From: Zach Dennis Date: 2005-08-12T12:19:54+09:00 Subject: Re: Dynamically added methods Yann Klis wrote: > In fact, I'd like to mimic the behaviour of ActiveRecord. > > If I have something like this: > > class Base > > def initialize(attributes) > #do something clever with attributes > end > > end > > class MyObject < Base > end > > I'd like to be able to do that: > > object = MyObject.new({"attribute1" => "value1", "attribute2" => > "value2"}) > val = object.attribute1 > To create methods on the class itself so all instances of that class get the method you can do: class A def initialize( args=nil ) if args.is_a? Hash args.each { |key,val| self.class.send( :define_method, key, proc { val } ) } end end end a = A.new( :zzz => "testing" ) puts a.zzz b = A.new puts b.zzz To create methods on the instance you have created only you can do: class A def initialize( args=nil ) if args.is_a? Hash s = class << self; self; end args.each { |key,val| s.send( :define_method, key, proc { val } ) } end end end a = A.new( :zzz => "testing" ) puts a.zzz b = A.new puts b.zzz #this will throw an error,because method zzz doesn't exist on this instance Note, that I think the second example above is bad design. We are relying on an instance of A to give the class A extra methods for all instances. We should instead rely on a singleton method for class A to handle this task. (keep reading) The above two solutions don't take into consideration if a method already exists though, so you could easily overwrite an existing method. Another way to do this is by overriding the method missing for your class which won't override existing methods. The below will handle things for instances only, like the first example: class A def initialize( args={} ) @args = args if args.is_a? Hash end def method_missing( method ) @args[method] || super end end puts A.new( :a => "z" ) # prints out "z" A.new.a #throws an error because :a wasn't passed in to this object And you can alter that to add methods for the class also so all instances get the methods, although above in the second example I think we used bad designed. So here we fix it by using a singleton method 'add_attributes': class A def self.add_attributes( attributes ) @@attributes = attributes end def initialize( args={} ) @args = args if args.is_a? Hash end def method_missing( method ) @@attributes[method] || super end end A.add_attributes( :attr1 => "attribute 1", :attr2 => "attribute 2" ) puts A.new.attr1 puts A.new.attr2 I hope this helps! Zach