53 votes

Définir dynamiquement un attribut d'un objet Ruby

Comment puis-je définir un attribut d'objet dynamiquement en Ruby, par exemple ?

def set_property(obj, prop_name, prop_value)
    #need to do something like > obj.prop_name = prop_value 

    #we can use eval but I'll prefer a faster/cleaner alternative:
    eval "obj.#{prop_name} = #{prop_value}"
end

98voto

lucapette Points 13109

Utilisation envoyer :

def set_property(obj, prop_name, prop_value)
    obj.send("#{prop_name}=",prop_value)
end

2 votes

Si vous utilisez la version 1.9.2, vous devriez appeler public_send au lieu de send car send peut également appeler des méthodes privées d'un objet, voir [ [joshstaiger.org/archives/2006/12/the_ruby_send_h.html]](http://www.joshstaiger.org/archives/2006/12/the_ruby_send_h.html])

20 votes

Cela ne fonctionne pas pour la définition d'une propriété de manière dynamique . Faire obj.send("foo=", "bar") se brisera à moins que le foo= est déjà définie (par un accesseur d'attribut ou une définition explicite de méthode). Tous les send a pour effet d'invoquer une méthode existante en utilisant les arguments spécifiés. Voir aussi ruby-doc.org/core-1.9.3/Objet.html#method-i-send

0 votes

Et si le prop_name est une clé imbriquée ? foo.bar

15voto

jschulenklopper Points 809

Object#instance_variable_set() est ce que vous recherchez, et c'est la version la plus propre de ce que vous vouliez.

Exemple :

your_object = Object.new
your_object.instance_variable_set(:@attribute, 'value')
your_object
# => <Object:0x007fabda110408 @attribute="value">

Documentation Ruby sur Object#instance_variable_set

0 votes

En supposant que le PO veuille réellement définir une variable d'instance plutôt que d'appeler la méthode du mutateur. La question semble confondre les deux, mais le code de l'exemple appelle au moins la méthode du mutateur.

0 votes

@mu-is-too-short, Bien sûr, mais instance_variable_set() définit réellement une variable d'instance pour un nom de variable qui est déterminé au moment de l'exécution. Dans ce sens, cela a le même effet que dans la question, mais une alternative plus propre et plus claire.

1 votes

Pas nécessairement. Définir directement une variable d'instance et appeler une méthode de mutateur n'est pas toujours la même chose ; la méthode peut modifier/contrôler la valeur entrante, la méthode peut stocker la valeur ailleurs, il peut même ne pas y avoir de variable d'instance derrière le mutateur, ... C'est tout ce que je dis.

9voto

benjineer Points 96

Si les circonstances permettent l'utilisation d'une méthode d'instance, ce qui suit n'est pas trop offensant :

class P00t
  attr_reader :w00t

  def set_property(name, value)
    prop_name = "@#{name}".to_sym # you need the property name, prefixed with a '@', as a symbol
    self.instance_variable_set(prop_name, value)
  end
end

Utilisation :

p = P00t.new
p.set_property('w00t', 'jeremy')

5voto

Tincho Rockss Points 41

Cette réponse ( https://stackoverflow.com/a/7466385/6094965 ) a fonctionné pour moi :

Object.send(attribute + '=', value)

attribute doit être un String . Ainsi, si vous itérez à travers un tableau de Symbol (comme moi), vous pouvez utiliser to_s .

Object.send(attribute.to_s + '=', value)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X