J'ai une classe à laquelle j'ajoute dynamiquement des accesseurs d'attribut au moment de l'exécution. Cette classe fait partie d'un DSL, par lequel les blocs sont passés aux méthodes de configuration et invoqués en utilisant instance_eval. Cela permet dans la DSL de supprimer les références à "self" lors du référencement des méthodes de la classe.L'affectation d'accesseurs ajoutée dynamiquement ne fonctionne pas lors de l'invocation d'un bloc via instance_eval dans Ruby
Cependant, j'ai découvert que je peux référencer les attributs pour récupérer leurs valeurs, mais je suis incapable de les assigner, sauf si je fais explicitement référence à self, comme l'illustre l'exemple de code suivant.
class Bar
def add_dynamic_attribute_to_class(name)
Bar.add_dynamic_attribute(name)
end
def invoke_block(&block)
instance_eval &block
end
def self.add_dynamic_attribute(name)
attr_accessor name
end
end
b = Bar.new
b.add_dynamic_attribute_to_class 'dyn_attr'
b.dyn_attr = 'Hello World!'
# dyn_attr behaves like a local variable in this case
b.invoke_block do
dyn_attr = 'Goodbye!'
end
# unchanged!
puts "#{b.dyn_attr} but should be 'Goodbye!'"
# works if explicitly reference self
b.invoke_block do
self.dyn_attr = 'Goodbye!'
end
# changed...
puts "#{b.dyn_attr} = 'Goodbye!"
# using send works
b.invoke_block do
send 'dyn_attr=', 'Hello Again'
end
# changed...
puts "#{b.dyn_attr} = 'Hello Again!"
# explain this... local variable or instance method?
b.invoke_block do
puts "Retrieving... '#{dyn_attr}'"
# doesn't fail... but no effect
dyn_attr = 'Cheers'
end
# unchanged
puts "#{b.dyn_attr} should be 'Cheers'"
Quelqu'un peut-il expliquer pourquoi cela ne se comporte pas comme prévu?
Je ne comprends pas complètement; vous dites que les classes ruby font la distinction entre les variables locales et les variables d'instance, mais le problème est avec les méthodes accesseurs. c'est-à-dire bar! = @bar! = bar()! = bar =(). – VirtualStaticVoid
BTW: J'ai réussi à contourner le problème en implémentant une méthode appelée "config", qui retourne self, sur la classe, afin que mon DSL soit mieux lu (ie au lieu d'utiliser self. * Maintenant config. *) – VirtualStaticVoid
J'ai mis à jour le poste avec plus de détails. Le problème est que vous définissez sans le savoir une variable locale plutôt qu'une instance varaible. Pour être plus précis, bar == @bar == bar() == self.bar si une variable locale nommée bar n'est pas définie. Sinon bar! = @bar == bar() == self.bar si une variable locale nommée bar est définie. Pour être sûr, ne définissez pas les variables locales nommées "bar" ou n'utilisez que les autres méthodes. –