metaprogramming - Ruby: Dynamically defining class methods in a module -


i'm having trouble dynamically defining class methods within module. see code below. nameerror: undefined local variable or method when trying reference class method in module. seems might scope or context issue, i've not been able figure out 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 |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 able call:

puts foo.apple => "apple" puts foo.orange => "orange" puts foo.banana => "banana" 

currently when try of these following error: nameerror: undefined local variable or method 'fruits' bar::classmethods:module

additionally, class methods in bar::classmethods should available foo, should able call:

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

requirements:

  1. all code within single module.
  2. the module allows mixing both instance , class methods (article below).
  3. the target methods dynamically defined.

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 appreciated!

the problem is, fruits method defined instance method, calling without instance on classmethods. define this:

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

and code works.

edit: make fruits method accessible class method on foo too, have declare fruits array in way accessible while inside classmethods module. 1 way declare array class variable , use in fruits method , each block. @ 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 |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 

Comments