Here's how you could do that. One instance variable and an associated read/write accessor will be created for each of initialize
's parameters, with the variable having the same name, preceded by @
, and each instance variable will be assigned the value of the associated parameter.
Code
class MyClass
def initialize(< arbitrary parameters >)
self.class.params.each { |v|
instance_variable_set("@#{v}", instance_eval("#{v}")) }
< other code >
end
@params = instance_method(:initialize).parameters.map(&:last)
@params.each { |p| instance_eval("attr_accessor :#{p}") }
class << self
attr_reader :params
end
< other code >
end
Example
class MyClass
def initialize(a, b, c)
self.class.params.each { |v|
instance_variable_set("@#{v}", instance_eval("#{v}")) }
end
@params = instance_method(:initialize).parameters.map(&:last)
@params.each { |p| instance_eval("attr_accessor :#{p}") }
class << self
attr_reader :params
end
end
MyClass.methods(false)
#=> [:params]
MyClass.instance_methods(false)
#=> [:a, :a=, :b, :b=, :c, :c=]
m = MyClass.new(1,2,3)
m.a #=> 1
m.b #=> 2
m.c #=> 3
m.a = 4
m.a #=> 4
Explanation
When class MyClass
is parsed, the class instance variable @params
is assigned an array whose elements are initialize
's parameters. This is possible because the method initialize
been created when the code beginning @params = ...
is parsed.
The method Method#parameters is used to obtain initialize
's parameters. For the example above,
instance_method(:initialize).parameters
#=> [[:req, :a], [:req, :b], [:req, :c]]
so
@params = instance_method(:initialize).parameters.map(&:last)
#=> [:a, :b, :c]
We then create the read/write accessors:
@params.each { |p| instance_eval("attr_accessor :#{p}") }
and a read accessor for @params
, for use by initialize
:
class << self
attr_reader :params
end
When an instance my_class
of MyClass
is created, the parameter values passed to MyClass.new
are passed to initialize
. initialize
then loops though the class instance variable @params
and sets the value of each instance variable. In this example,
MyClass.new(1,2,3)
invokes initialize(a,b,c)
where
a => 1
b => 2
c => 3
We have:
params = self.class.params
#=> [:a, :b, :c]
params.each { |v| instance_variable_set("@#{v}", instance_eval("#{v}")) }
For the first element of params
(:a
), this is:
instance_variable_set("@a", instance_eval(a) }
which is:
instance_variable_set("@a", 1 }
causing @a
to be assigned 1
.
Note the accessor for @params
is not essential:
class MyClass
def initialize(a, b, c)
self.class.instance_variable_get(:@params).each { |v|
instance_variable_set("@#{v}", instance_eval("#{v}")) }
end
@params = instance_method(:initialize).parameters.map(&:last)
@params.each { |p| instance_eval("attr_accessor :#{p}") }
end