@Readonly
Si votre utilisation de "class MyObject" est une utilisation d'une classe ouverte, veuillez noter que vous redéfinissez la méthode initialize.
En Ruby, il n'y a pas de surcharge... seulement de remplacement, ou redéfinition... en d'autres termes, il ne peut y avoir qu'une seule instance de n'importe quelle méthode donnée, donc si vous la redéfinissez, elle est redéfinie... et la méthode initialize n'est pas différente (même si c'est ce que la nouvelle méthode des objets de classe utilise).
Ainsi, ne redéfinissez jamais une méthode existante sans lui donner un alias d'abord... du moins si vous voulez accéder à la définition originale. Et redéfinir la méthode initialize d'une classe inconnue peut être assez risqué.
Quoi qu'il en soit, je pense avoir une solution beaucoup plus simple pour vous, qui utilise la métaclass réelle pour définir des méthodes singleton :
m = MyObject.new
metaclass = class << m; self; end
metaclass.send :attr_accessor, :first, :second
m.first = "first"
m.second = "second"
puts m.first, m.second
Vous pouvez utiliser à la fois la métaclass et les classes ouvertes pour devenir encore plus rusé et faire quelque chose comme :
class MyObject
def metaclass
class << self
self
end
end
def define_attributes(hash)
hash.each_pair { |key, value|
metaclass.send :attr_accessor, key
send "#{key}=".to_sym, value
}
end
end
m = MyObject.new
m.define_attributes({ :first => "first", :second => "second" })
Le code ci-dessus expose essentiellement la métaclass via la méthode "metaclass", puis l'utilise dans define_attributes pour dynamiquement définir un tas d'attributs avec attr_accessor, et ensuite invoquer le setter d'attribut ensuite avec la valeur associée dans le hash.
Avec Ruby, vous pouvez être créatif et faire la même chose de nombreuses manières différentes ;-)
Petite info, au cas où vous ne le saviez pas, utiliser la métaclass comme je l'ai fait signifie que vous ne travaillez que sur l'instance donnée de l'objet. Ainsi, en invoquant define_attributes, vous allez seulement définir ces attributs pour cette instance particulière.
Exemple :
m1 = MyObject.new
m2 = MyObject.new
m1.define_attributes({:a => 123, :b => 321})
m2.define_attributes({:c => "abc", :d => "zxy"})
puts m1.a, m1.b, m2.c, m2.d # cela fonctionnera
m1.c = 5 # cela échouera car c= n'est pas défini sur m1 !
m2.a = 5 # cela échouera car a= n'est pas défini sur m2 !