Dichiarare variabili di istanza che ripetono un hash!
-
06-07-2019 - |
Domanda
Voglio fare quanto segue:
Voglio dichiarare le variabili di istanza di una classe che scorre su un dizionario.
Supponiamo che io abbia questo hash
hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
e voglio avere ogni chiave come variabile di istanza di una classe. Voglio sapere se potrei dichiarare le variabili che ripetono quell'hash. Qualcosa del genere:
class MyClass
def initialize()
hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
hash.each do |k,v|
@k = v
end
end
end
So che non funziona! Metto solo questo pezzo di codice per vedere se riesci a capire cosa voglio più chiaramente.
Grazie!
Soluzione
class MyClass
def initialize()
hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
hash.each do |k,v|
instance_variable_set("@#{k}",v)
# if you want accessors:
eigenclass = class<<self; self; end
eigenclass.class_eval do
attr_accessor k
end
end
end
end
L'Eigenclass è una classe speciale che appartiene solo a un singolo oggetto, quindi i metodi definiti ci saranno metodi di istanza di quell'oggetto ma non appartengono ad altre istanze della classe normale dell'oggetto.
Altri suggerimenti
class MyClass
def initialize
# define a hash and then
hash.each do |k,v|
# attr_accessor k # optional
instance_variable_set(:"@#{k}", v)
end
end
end
La risposta di Chuck è migliore dei miei ultimi due tentativi. L'eigenclass non è self.class
come avevo pensato; ci è voluto un test migliore di quello che avevo scritto per rendermene conto.
Usando il mio vecchio codice, ho testato nel modo seguente e ho scoperto che la classe è stata effettivamente manipolata e non l'istanza:
a = MyClass.new :my_attr => 3
b = MyClass.new :my_other_attr => 4
puts "Common methods between a & b:"
c = (a.public_methods | b.public_methods).select { |v| a.respond_to?(v) && b.respond_to?(v) && !Object.respond_to?(v) }
c.each { |v| puts " #{v}" }
L'output è stato:
Common methods between a & b:
my_other_attr=
my_attr
my_attr=
my_other_attr
Ciò smentisce chiaramente il mio presupposto. Mi scuso, Chuck, avevi sempre giusto.
Risposta precedente:
attr_accessor
funziona solo quando valutato in una definizione di classe, non l'inizializzazione di un'istanza. Pertanto, l'unico metodo per fare direttamente quello che vuoi è usare instance_eval
con una stringa:
class MyClass
def initialize(params)
#hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
params.each do |k,v|
instance_variable_set("@#{k}", v)
instance_eval %{
def #{k}
instance_variable_get("@#{k}")
end
def #{k}= (new_val)
instance_variable_set("@#{k}", new_val)
end
}
end
end
end
Per provare questo provare:
c = MyClass.new :my_var => 1
puts c.my_var
http://facets.rubyforge.org/apidoc/api /more/classes/OpenStructable.html
OpensStructable è un modulo mixin che può fornire un comportamento OpenStruct a qualsiasi classe o oggetto. OpenStructable consente l'estensione di oggetti dati con attributi arbitrari.