Ecco come è possibile farlo. Verrà creata una variabile di istanza e un accessore di lettura/scrittura associato per ciascuno dei parametri di initialize
, con la variabile con lo stesso nome, preceduta da @
e ad ogni variabile di istanza verrà assegnato il valore del parametro associato.
Codice
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
Esempio
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
Spiegazione
Quando la classe MyClass
viene analizzato, l'istanza della classe variabile @params
viene assegnato un array i cui elementi sono i parametri di initialize
. Ciò è possibile perché il metodo initialize
è stato creato quando viene analizzato il codice che inizia con @params = ...
.
Il metodo Method#parameters viene utilizzato per ottenere i parametri di initialize
. Per l'esempio precedente,
instance_method(:initialize).parameters
#=> [[:req, :a], [:req, :b], [:req, :c]]
così
@params = instance_method(:initialize).parameters.map(&:last)
#=> [:a, :b, :c]
Abbiamo poi creiamo le funzioni di accesso di lettura/scrittura:
@params.each { |p| instance_eval("attr_accessor :#{p}") }
e una funzione di accesso di lettura per @params
, per l'utilizzo da parte initialize
:
class << self
attr_reader :params
end
Quando viene creata un'istanza my_class
di MyClass
, i valori dei parametri passati a MyClass.new
vengono passati a initialize
. initialize
quindi esegue il ciclo della variabile di istanza di classe @params
e imposta il valore di ogni variabile di istanza.In questo esempio,
MyClass.new(1,2,3)
invoca initialize(a,b,c)
dove
a => 1
b => 2
c => 3
Abbiamo:
params = self.class.params
#=> [:a, :b, :c]
params.each { |v| instance_variable_set("@#{v}", instance_eval("#{v}")) }
Per il primo elemento di params
(:a
), questo è:
instance_variable_set("@a", instance_eval(a) }
che è:
instance_variable_set("@a", 1 }
causando @a
da assegnare 1
.
Nota la funzione di accesso per @params
non è essenziale:
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
Un bel thread su quello qui. http://stackoverflow.com/questions/2680523/dry-ruby-initialization-with-hash-argument – Jazzepi
@Jazzepi, si tratta di un filo di interessante, ma si occupa solo con argomenti hash. –