Ruby:Mixin 添加动态实例方法,其名称是使用类方法创建的
我有以下内容:
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)
我意识到上面指出的问题行(InstanceMethods 模块的第一行)中的“self”是指 InstanceMethods 模块。
如何引用“things”类方法(在本例中返回 [:one, :two]),以便我可以循环遍历并为每个方法创建动态实例方法?谢谢。或者,如果您有其他建议来完成此任务,请告诉我。
I have the following:
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
In another class which mixes-in the Thing module:
class Group
has_things :one, :two, :option => "something"
end
When calling has_things
within a class, I would like to have the dynamic "foo_for_thing_one" and "foo_for_thing_two" instance methods available. For example:
@group = Group.new
@group.foo_for_thing_one # => "bar for thing one"
@group.foo_for_thing_two # => "bar for thing two"
However, I get the following error:
`<module:InstanceMethods>': undefined method `things' for Module:Class (NoMethodError)
I realize that "self" in the problem line pointed out above (first line of the InstanceMethods module) refers to the InstanceMethods module.
How do I reference the "things" class method (which returns [:one, :two] in this example) so I can loop through and create dynamic instance methods for each? Thanks. Or if you have other suggestions for accomplishing this, please let me know.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
快速回答:
将 InstanceMethods 的内容放入
has_things
方法定义中,并删除 InstanceMethods 模块。更好的答案:
您对 InstanceMethods-ClassMethods 反模式的使用在这里尤其没有根据,并且它的货物崇拜增加了您对范围和上下文的困惑。做可能有效的最简单的事情。未经批判性思考,请勿复制他人的代码。
您需要的唯一模块是 ClassMethods,应该为它指定一个有用的名称,并且不应将其包含在内,而是用于扩展您想要授予
has_things
功能的类。这是可能起作用的最简单的事情:仅在需要时添加复杂性(选项提取、输入标准化等)。及时编写代码,而不仅仅是以防万一。
Quick answer:
Put the contents of InstanceMethods inside the
has_things
method definition and remove the InstanceMethods module.Better answer:
Your use of the InstanceMethods-ClassMethods anti-pattern is especially unwarranted here and cargo-culting it has added to your confusion about scope and context. Do the simplest thing that could possibly work. Don't copy someone else's code without critical thinking.
The only module you need is ClassMethods, which should be given a useful name and should not be included but rather used to extend the class that you want to grant the
has_things
functionality. Here's the simplest thing that could possibly work:Only add complexity (options extraction, input normalization, etc) when you need it. Code just in time, not just in case.