【问题标题】:Why can you not declare constants in methods with Ruby?为什么不能在 Ruby 方法中声明常量?
【发布时间】:2010-08-04 21:22:06
【问题描述】:

考虑以下情况,StubFoo 是 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 测试用例,但不适用于上述方法?
  • 据我所知,“它”只是 RSpec 中的一个方法,但我可以在“方法”中重新声明一个常量。

我在使用模拟框架之前这样做只是想知道模拟、存根等在 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 中的工作方式/方式?显然更加优雅和功能齐全,但他们只是压制这个警告吗?

【问题讨论】:

    标签: ruby constants


    【解决方案1】:

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

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

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

    【讨论】:

    • @user1735921 举个例子?
    【解决方案2】:

    因为在您的测试中,您没有定义方法,而是调用 it

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

    【讨论】:

      【解决方案3】:

      您收到错误是因为如果调用了 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
      

      【讨论】:

      • 这不是错误。这是一个警告。该程序仍然可以正常运行。
      猜你喜欢
      • 1970-01-01
      • 2013-08-01
      • 1970-01-01
      • 2022-11-28
      • 1970-01-01
      • 2012-05-07
      • 2019-03-05
      • 2015-01-21
      • 1970-01-01
      相关资源
      最近更新 更多