我如何在动态定义的类的动态定义的子类中动态定义一个常量

时间:2018-06-23 16:04:59

标签: ruby

我如何在动态定义的类的动态定义的子类中动态定义一个常量,就像这样,但是没有NameError: uninitialized constant Foo::Bar错误:

Object.const_set('Foo',Class.new) {|klass| klass.const_set('Bar', Class.new){|subklass| subklass.const_set(:YEP,'Yep!')}}

获得:

> Foo::Bar::YEP #=> 'Yep!'

2 个答案:

答案 0 :(得分:5)

将方法参数括在括号中时,花括号块将应用于方法调用,而不是列表中的最后一个参数。因此,那些{ |klass| ... }被传递给Object.const_set而不是Class.new。如果您将封闭括号移到块后,它将起作用,因为块将传递给Class.new而不是Object.const_set

Object.const_set('Foo',Class.new { |klass|
  klass.const_set('Bar', Class.new { |subklass|
    subklass.const_set(:YEP,'Yep!')
  })
})
Foo::Bar::YEP # => "Yep!"

答案 1 :(得分:3)

以下等同于@SimpleLime的答案,只是表达方式有所不同。

def make_class(name, parent=Object)
  Object.const_set(name, Class.new(parent))
end

foo = make_class('Foo')
  #=> Foo
bar = make_class('Bar', foo)
  #=> Bar
bar.superclass
  #=> Foo
bar.const_set('YEP', 'Yep!')
Bar::YEP
  #=> "Yep!"
bar::YEP
  #=> "Yep!"

如果需要,可以排除变量。

make_class('Bar', make_class('Foo')).const_set('YEP', 'Yep!')
Bar::YEP
  # => "Yep!"

请参见Class::newModule#const_set

动态创建的类通常被匿名使用(无名),在这种情况下,可以简单地编写:

foo = Class.new
bar = Class.new(foo)
bar.const_set('YEP', 'Yep!')
bar::YEP
  #=> "Yep!"

,并通过变量foobar引用类。