代码之家  ›  专栏  ›  技术社区  ›  Finglas

为什么不能在使用Ruby的方法中声明常量?

  •  2
  • Finglas  · 技术社区  · 14 年前

    考虑下面,Stuffo是Foo的存根,我希望在一些测试中删掉它。

    class Runner
    
      def run
          Foo = StubFoo
          foo = Foo.new
          # using Foo...
      end
    
    end
    

    这将生成以下错误消息: Dynamic constant assignment

    然而,在RSpec中,我可以做到以下几点,这是有效的,也是完全合法的:

    it "should be an example" do
      Foo = StubFoo
      foo = Foo.new
      foo.to_s.should == "I am stubbed!"
    end
    

    关于这一点有几个问题。

    • 为什么这适用于RSpec测试用例,而不是上面的方法?
    • 据我所知,“it”只是RSpec中的一个方法,但我能够在“method”中重新声明一个常量。

    在使用模拟框架之前,我只是想知道如何进行模拟、存根等。。。在Ruby中是不同的。我听说动态语言更容易模仿/存根,互联网上有一些指南,其中简单的类重新分配是如上所述的。根据我的研究,在Ruby中,不可能在一个方法中声明常量,但如上所述,我感到困惑。

    编辑

    对,这开始变得更有意义了。我已经将run更新为现在使用const_set。

      def run
          old = Foo
          self.class.const_set(:Foo, StubFoo)
          foo = Foo.new
          puts foo.to_s
          self.class.const_set(:Foo, old)
          foo = Foo.new
          puts foo.to_s
      end
    

    然而,这会产生一个警告,这就是模仿框架在Ruby中的工作原理吗?显然要优雅得多,功能齐全,但他们只是压制了这个警告吗?

    3 回复  |  直到 12 年前
        1
  •  10
  •   Jon Cairns    11 年前

    无法使用重新分配方法定义中的常量 Constant = value 。但是,您可以使用 const_set .基本上,这是为了阻止,但不是不允许,动态不断的重新分配。

    至于它为什么与 it :是的, 信息技术 是一个方法,但您不是在定义,而是在调用它。重新分配发生在作为参数传递给的块内 信息技术 .

    块继承创建它们的上下文的类型。这意味着在街区内, self.class.name 将是您的测试类的名称。因此,当您在传递给 信息技术 方法,实际上是在测试类上定义一个常量。

        2
  •  2
  •   Chubas    14 年前

    因为在你的测试中,你没有定义一个方法,而是 使命感 it .

    Ruby检测到您在一个方法中定义了一个常数,该常数可以多次运行,因此发出警告。如果你多次调用这个方法,你会得到一个 warning: already initialized constant Foo 警告这是因为它们应该是常数。(例如,如果定义 Foo = Time.now ?)

        3
  •  0
  •   Adrian    14 年前

    因为如果 Runner#run 叫做, Foo 将在调用方上意外更改。例如:

    class C; end
    
    def add_two_to(x) # this method is defined externally, and you cannot change it.
      C = Class.new {} # error
      x + 2
    end
    
    x = C.new
    puts add_two_to(5)
    y = C.new
    
    x.is_a? y.class # would be false if the code get here
    

    来电者 add_two_to 不期望 C 需要重新定义。更合理的是,上面代码的最后一行总是正确的。在第二个示例中,您的“方法”实际上不是一个方法,而是一个块。如果你跑两次街区(哪一次 it 不会),您将收到以下错误:

    warning: already initialized constant Q