I'm trying to generate the attr_reader from a hash (with nested hash) so that it mirror the instance_variable creation automatically.
here is what i have so far:
data = {:@datetime => '2011-11-23', :@duration => '90', :@class => {:@price => '£7', :@level => 'all'}}
class Event
#attr_reader :datetime, :duration, :class, :price, :level
def init(data, recursion)
data.each do |name, value|
if value.is_a? Hash
init(value, recursion+1)
else
instance_variable_set(name, value)
#bit missing: attr_accessor name.to_sym
end
end
end
But i can't find out a way to do that :(
You need to call the (private) class method attr_accessor
on the Event
class:
self.class.send(:attr_accessor, name)
I recommend you add the @
on this line:
instance_variable_set("@#{name}", value)
And don't use them in the hash.
data = {:datetime => '2011-11-23', :duration => '90', :class => {:price => '£7', :level => 'all'}}
You could do a bit of meta-magic to solve this, using method_missing:
class Event
def method_missing(method_name, *args, &block)
if instance_variable_names.include? "@#{method_name}"
instance_variable_get "@#{method_name}"
else
super
end
end
end
What this will do is allow access to object instance variables via object.variable syntax, if the object has those variables defined, without resorting to modifying the entire class via attr_accessor.
attr_accessor
is a class method and as such needs to be invoked on the class. It is also a private method, so you need to invoke it in a context in which the class object is self
.
As an example:
class C
def foo
self.class.instance_eval do
attr_accessor :baz
end
end
end
After creating an instance of C
and calling foo
on that instance, that instance -- and all future instances -- will contain methods baz
and baz=
.
来源:https://stackoverflow.com/questions/7527832/ruby-dynamically-generate-attribute-accessor