Ruby Metaprogrammazione: dinamica variabile di istanza nomi

Diciamo che ho il seguente hash:

{ :foo => 'bar', :baz => 'qux' }

Come potrei impostare dinamicamente le chiavi e i valori diventano le variabili di istanza in oggetto…

class Example
  def initialize( hash )
    ... magic happens here...
  end
end

… in modo che io alla fine con il seguente all’interno del modello…

@foo = 'bar'
@baz = 'qux'

?

InformationsquelleAutor Andrew | 2011-07-19

 

4 Replies
  1. 165

    Il metodo che si sta cercando è instance_variable_set. Quindi:

    hash.each { |name, value| instance_variable_set(name, value) }

    O, più brevemente,

    hash.each &method(:instance_variable_set)

    Se la variabile di istanza nomi manca la “@” (come nell’OP esempio), è necessario aggiungerli, per cui sarebbe più come:

    hash.each { |name, value| instance_variable_set("@#{name}", value) }
    • Non ha funzionato per me per 1.9.3. Ho usato questo invece hash.each {|k,v| instance_variable_set("@#{k}",v)}
    • ancora un altro motivo per amore di Ruby
    • potete per favore spiegare come in hash.each &method(:instance_variable_set), il metodo instance_variable_set riceve due parametri di cui ha bisogno?
    • qualsiasi idea di come fare questo in modo ricorsivo ? (se c’è più di livello in ingresso hash)
  2. 12
    h = { :foo => 'bar', :baz => 'qux' }
    
    o = Struct.new(*h.keys).new(*h.values)
    
    o.baz
     => "qux" 
    o.foo
     => "bar" 
    • Che è piuttosto interessante… che cosa è esattamente la seconda incatenato .new() facendo?
    • crea una nuova classe basata su chiavi hash, e poi la seconda new fa il primo oggetto appena creato la classe, l’inizializzazione dei valori di Hash. Vedere ruby-doc.org/core-1.8.7/classes/Struct.html
    • Questo è in realtà un ottimo modo per farlo dal momento che questo è praticamente quello che Struct è fatto per.
    • O OpenStruct. require 'ostruct'; h = {:foo => 'foo'}; o = OpenStruct.new(h); o.foo == 'foo'
    • Ho dovuto mappa mie chiavi di simboli: Struct.new(*hash.keys.map { |str| str.to_sym }).new(*hash.values)
  3. 5

    È inoltre possibile utilizzare send che impedisce all’utente di impostazione inesistenti le variabili di istanza:

    def initialize(hash)
      hash.each { |key, value| send("#{key}=", value) }
    end

    Utilizzare send quando in classe c’è un setter come attr_accessor per le variabili di istanza:

    class Example
      attr_accessor :foo, :baz
      def initialize(hash)
        hash.each { |key, value| send("#{key}=", value) }
      end
    end

Lascia un commento