I'm having trouble dynamically defining class methods within a module. See code below. I get a NameError: undefined local variable or method when trying to reference another class method in the module. Seems like this might be a scope or context issue, but I've not been able to figure it out so far.
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
I want to be able to call:
puts Foo.apple => "APPLE"
puts Foo.orange => "ORANGE"
puts Foo.banana => "BANANA"
Currently when I try any of these I get the following error:
NameError: undefined local variable or method 'fruits' for Bar::ClassMethods:Module
Additionally, class methods in Bar::ClassMethods should be available to Foo, so I should be able to call:
puts Foo.fruits => ["apple", "orange", "banana"]
Requirements:
Read "Include vs Extend in Ruby" (esp. section titled "A Common Idiom") http://www.railstips.org/blog/archives/2009/05/15/include-vs-extend-in-ruby/
Help with this is greatly appreciated!
The problem is, the fruits method is defined as an instance method, but you are calling it without an instance on ClassMethods. Just define it like this:
def self.fruits
["apple", "orange", "banana"]
end
And your code works.
EDIT:
To make the fruits method accessible as a class method on Foo too, you have to declare the fruits array in a way that is accessible while inside the ClassMethods module. One way would be to declare the array as a class variable and use it in the fruits method and the each block. Look at the following code:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With