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

In ruby, how to pass a class variable into a mixed-in module's dynamically created class method?

所以...

我有一个模块...

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=" 并且我尝试了几种使用符号的变体,class 实例变量等。非常感谢任何帮助!

你的标题说 "dynamically created class method" 但看起来你实际上是在动态创建实例 classes,即你可以有多个 TestClass 实例,每个实例都有自己的 collection 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:

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

这样:t = TestClass.new("boop") 将使用方法 set_boop=().

为您提供实例 class t

我应该提一下,如果您创建另一个实例,它将具有您为其提供的任何新方法 以及 先前实例中的所有先前方法。这是因为您正在修改每个实例的 class 定义。

如果您不需要该功能,您可以使用 define_singleton_method 并包含模块而不是扩展它,这使得 bar 成为一个实例方法,旨在创建其他实例方法。您的 class 看起来像这样:

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

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