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!

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top