具有嵌套模块的Object.const_set中的错误常量名称

时间:2014-02-20 00:19:23

标签: ruby-on-rails ruby metaprogramming

我有一堆我想在命名空间中定义的模块,我把它们放在初始化器中,但是我得到了一个'错误的常量名'例外:

# 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是空的,我不确定是什么错。

2 个答案:

答案 0 :(得分:3)

将代码包含在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_scamelize

此外,它不适合你的原因是在常量名称中使用冒号以及通过执行Object.const_set而不是在Foobar上定义它们来定义Object上的常量这一事实。这也有效:

%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,前面的示例也会起作用。

答案 1 :(得分:2)

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

相关问题