Pergunta

eu quero fazer o seguinte:

Eu quero declarar as variáveis ??de instância de uma iteração classe sobre um dicionário.

Vamos supor que eu tenho esse hash

hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}

e eu quero ter cada tecla, como variável de instância de uma classe. Eu quero saber se eu poderia declarar as variáveis ??interagindo sobre que hash. Algo parecido com isto:

class MyClass
  def initialize()
    hash = {"key1" => "value1","key2" => "value2","key3" => "value3"}
    hash.each do |k,v|
      @k = v
    end
  end
end

Eu sei que isso não funciona! Eu só colocar este pedaço de código para ver se você pode entender o que eu quero de forma mais clara.

Obrigado!

Foi útil?

Solução

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

Os eigenclass é uma classe especial que pertence apenas a um único objeto, de modo que os métodos definidos haverá métodos de instância desse objeto, mas não pertencem a outras instâncias de classe normal do objeto.

Outras dicas

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

A resposta de Chuck é melhor do que as minhas duas últimas tentativas. Os eigenclass não é self.class como eu tinha pensado; ele fez um teste melhor do que eu tinha escrito para perceber isso.

Usando o meu código antigo, eu testado da seguinte maneira e descobriu que a classe estava realmente manipulado e não a instância:

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}" }

A saída foi:

Common methods between a & b:
    my_other_attr=
    my_attr
    my_attr=
    my_other_attr

Este refuta claramente o meu pressuposto. Minhas desculpas Chuck, você foram certo o tempo todo.

Resposta Mais:

attr_accessor só funciona quando avaliados em uma definição de classe, e não a inicialização de uma instância. Portanto, o único método para diretamente fazer o que você quer é usar instance_eval com uma string:

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

Para testar esta tentativa:

c = MyClass.new :my_var => 1
puts c.my_var

http://facets.rubyforge.org/apidoc/api /more/classes/OpenStructable.html

OpensStructable é um módulo mixin que podem fornecer um comportamento OpenStruct a qualquer classe ou objeto. OpenStructable permite a extensão de objectos de dados com atributos arbitrários.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top