ruby-on-rails – 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)

我意识到上面指出的问题行中的“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"

只在需要时添加复杂性(选项提取,输入规范化等).代码及时,不仅仅是以防万一.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...