【问题标题】:wrong constant name in Object.const_set with nested module带有嵌套模块的 Object.const_set 中的常量名称错误
【发布时间】:2014-02-20 00:19:22
【问题描述】:

我想在命名空间中定义一堆模块,我将它们放在初始化程序中,但我得到一个“错误的常量名称”异常:

# this is a self-contained example
require 'active_support/all'
# ==> true

[:baz, :qux].each do |name|
  Object.const_set("FooBar::#{name.to_s.camelize}", Module.new {
    define_singleton_method :my_awesome_static_method do |amount|
      DoSomething.calculate(amount)
    end
  })
end
# =NameError: wrong constant name FooBar::Baz
# = from (irb):4:in `const_set'
# = from (irb):4:in `block in irb_binding'
# = from (irb):3:in `each'
# = from (irb):3
# = from /usr/local/var/rbenv/versions/2.0.0-p353/bin/irb:12:in `<main>'

我认为我得到这个是因为初始化程序在定义 FooBar 之前运行,但问题是如果我在这个初始化程序中定义它,FooBar.constants 是空的,我不确定出了什么问题。

【问题讨论】:

    标签: ruby-on-rails ruby metaprogramming


    【解决方案1】:

    将您的代码包装在Foobar 类或模块中:

    module Foobar
      %w[Baz Qux].each do |name|
        const_set(name, Module.new {
          define_singleton_method :my_awesome_static_method do |amount|
            DoSomething.calculate(amount)
          end
        })
      end
    end
    

    如果是班级,请使用class Foobar。

    这不会重新定义它或任何东西,只是打开它以在其命名空间中添加新类。请注意我是如何从 const_set 中删除 Object 和 Foobar 并使用 Ruby 的 %w[] 表示法来定义字符串数组的,现在不需要 to_s 和 camelize 它们了。

    此外,它对您不起作用的原因是在常量名称中使用了冒号,以及您通过 Object.const_set 在 Object 上定义常量而不是在 Foobar 上定义它们。这也可以:

    %w[Baz Qux].each do |name|
      Foobar.const_set(name, Module.new {
        define_singleton_method :my_awesome_static_method do |amount|
          DoSomething.calculate(amount)
        end
      })
    end
    

    假设 Foobar 已经定义,即使 Foobar 尚未加载,前面的示例也可以工作。

    【讨论】:

    • 我明白了,我做错了两件事,const_set 被发送到 FooBar,而不是 Object,并且名称不包含冒号。
    【解决方案2】:

    您的常量名称包含冒号。这在常量名中是不允许的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-15
      • 2015-10-04
      • 1970-01-01
      • 2012-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多