我有以下内容:
module Thing def self.included(base) base.send :extend,ClassMethods end module ClassMethods attr_reader :things def has_things(*args) options = args.extract_options! # Ruby on Rails: pops the last arg if it's a Hash # Get a list of the things (Symbols only) @things = args.select { |p| p.is_a?(Symbol) } include InstanceMethods end end module InstanceMethods self.class.things.each do |thing_name| # !!! Problem is here,explaination below define_method "foo_for_thing_#{thing_name}" do "bar for thing #{thing_name}" end end end end
在另一个混合了Thing模块的类中:
class Group has_things :one,:two,:option => "something" end
在类中调用has_things时,我希望动态的“foo_for_thing_one”和“foo_for_thing_two”实例方法可用.例如:
@group = Group.new @group.foo_for_thing_one # => "bar for thing one" @group.foo_for_thing_two # => "bar for thing two"
但是,我收到以下错误:
`<module:InstanceMethods>': undefined method `things' for Module:Class (NoMethodError)
我意识到上面指出的问题行中的“self”(InstanceMethods模块的第一行)引用了InstanceMethods模块.
如何引用“things”类方法(在此示例中返回[:one,:two]),以便我可以遍历并为每个方法创建动态实例方法?谢谢.或者如果您有其他建议来完成此操作,请告诉我.
解决方法
快速回答:
将InstanceMethods的内容放在has_things方法定义中,然后删除InstanceMethods模块.
更好的答案:
您对InstanceMethods-ClassMethods反模式的使用在这里尤其没有根据,因此货物结果增加了您对范围和上下文的困惑.做最简单的事可能有用.没有批判性思维,不要复制别人的代码.
您需要的唯一模块是ClassMethods,它应该被赋予一个有用的名称,不应该包含在内,而是用于扩展您要授予has_things功能的类.这是最简单的事情:
module HasThings def has_things(*args) args.each do |thing| define_method "thing_#{thing}" do "this is thing #{thing}" end end end end class ThingWithThings extend HasThings has_things :foo end ThingWithThings.new.thing_foo # => "this is thing foo"