在ruby中,如何将类变量传递给混合模块的动态创建的类方法?

时间:2017-01-25 20:10:30

标签: ruby-on-rails ruby rspec rspec-rails

... SO

我有一个模块......

module Foo
  class_methods do
    def bar(*fields)
      fields.each do |field|
        define_method("set_#{field}=") do |value|
          # nil check, other checks and validations
        end
    end
  end
end

...这个模块将在我的应用程序中的几个模型中使用,但是现在我正在尝试测试它......

let(:entity_type) do
  class TestClass
    def initialize(value)
      @field_value = value
    end

    include Foo
    bar @field_value

    self
  end
end

let(:entity) { entity_type.new(:some_field) }

...但是,当我在测试中设置断点并查看实体的方法时,我只看到“set_ =”而不是“set_some_field =”,并且我尝试了几种使用符号,类实例变量的变体等等。非常感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

你的标题是“动态创建的类方法”,但看起来你实际上是动态创建实例类,也就是说,你可以有多个TestClass实例,每个实例都有自己的set_x =方法集合。这是你想要的吗?

假设是这样,您可以创建模块:

module Foo
  def bar(*fields)
    fields.each do |field|
      define_method("set_#{field}=") do |value|
         # nil check, other checks and validations
      end
    end
  end
end

并像这样创建类:

class TestClass
  extend Foo
  def initialize(value)
    @field_value = value
    TestClass.bar(@field_value)
  end
end

这样:t = TestClass.new("boop")会使用方法t为您提供实例类set_boop=()

我应该提一下,如果你创建另一个实例,它会有任何新的方法你给它以及之前实例中的所有先前方法。这是因为您正在使用每个实例修改类定义。

如果您不想要该功能,可以使用define_singleton_method并包含模块而不是扩展它,这使得bar成为设计用于创建其他实例方法的实例方法。你的课程看起来像这样:

module Foo
  def bar(*fields)
    fields.each do |field|
      define_singleton_method("set_#{field}=") do |value|
        # nil check, other checks and validations
      end
    end
  end
end


class TestClass
  include Foo
  def initialize(value)
    @field_value = value
    bar(@field_value)
  end
end

如果这不是你想要的,请告诉我,我会修改我的答案。