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