Ruby:在模块中动态定义类方法

3

我在模块内动态定义类方法方面遇到了麻烦。请看以下代码。我在模块中引用另一个类方法时,出现了NameError: undefined local variable or method错误。似乎这可能是作用域或上下文问题,但我尚未能够解决它。

module Bar

  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods

    def fruits
      ["apple", "orange", "banana"]
    end

    def example_function(string)
      string.upcase
    end

    fruits.each do |fruit|
      method_name = fruit.to_sym
      define_method(method_name) { example_function(fruit) }
    end

  end

end

class Foo
  include Bar
end

puts Foo.apple
puts Foo.orange
puts Foo.banana

我希望能够调用以下内容:

puts Foo.apple => "APPLE"
puts Foo.orange => "ORANGE"
puts Foo.banana => "BANANA"

目前,当我尝试使用以下任何一种方法时,会出现以下错误:

NameError: undefined local variable or method 'fruits' for Bar::ClassMethods:Module

此外,Bar::ClassMethods中的类方法应该对Foo可用,因此我应该能够调用:

puts Foo.fruits => ["apple", "orange", "banana"]

要求:

  1. 所有代码都在一个单一的模块内。
  2. 该模块允许混合实例方法和类方法(请参考下面的文章)。
  3. 目标方法是动态定义的。

请阅读“Ruby中的Include vs Extend”(尤其是标题为“A Common Idiom”的部分)。http://www.railstips.org/blog/archives/2009/05/15/include-vs-extend-in-ruby/

非常感谢您的帮助!

1个回答

2
问题在于,fruits方法被定义为实例方法,但你在ClassMethods上调用它时没有实例。只需按照以下方式进行定义即可:
```ruby def self.fruits # method body here end ```
请注意,添加了self关键字将使该方法成为类方法。
def self.fruits
  ["apple", "orange", "banana"]
end

你的代码可以正常运行。

编辑: 为了使fruits方法在Foo类中也能作为类方法被调用,你需要以一种可在ClassMethods模块内部访问的方式声明fruits数组。其中一种方法是将该数组声明为类变量,并在fruits方法和each块中使用它。请看以下代码:

module Bar

  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    @@fruits = ["apple", "orange", "banana"]

    def fruits
      @@fruits
    end

    def example_function(string)
      string.upcase
    end

    @@fruits.each do |fruit|
      method_name = fruit.to_sym
      define_method(method_name) { example_function(fruit) }
    end
  end
end

class Foo
  include Bar
end

puts Foo.apple
puts Foo.orange
puts Foo.banana
puts Foo.fruits

嘿,Mario,你的代码确实修复了我的初始示例,但我忽略了澄清我想要能够访问Foo.fruits,请查看更新版本。由于使用模块模式,Bar :: ClassMethods模块中的所有内容都应该是Foo中有效的类方法,即使没有使用self定义函数也是如此。 - mayatron
1
@mayatron 我更新了我的答案。希望这符合你的意图。 - mario

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接