как отобразить класс в хэш и наоборот - PullRequest
0 голосов
/ 11 ноября 2011

У меня есть класс, как этот:

class A
  attr_accessor(:field2)
  attr_accessor(:field1)
end

Каков наилучший способ создать из него хеш-код с ключами и значениями, взятыми из экземпляра класса?

А как лучше всего заполнить экземпляр класса A значениями из этого хэша?

=====

Я, вероятно, ищу что-то похожее на самоанализ JavaBeans, который бы дал мне имена полей объекта данных, а затем выполнил бы логику на основе этой информации. Ruby - очень современный гибкий и динамический язык, и я отказываюсь признать, что он не позволит мне делать то, что я легко могу сделать с Java; -)

=====

В итоге я обнаружил, что Struct - лучший вариант:

a = {:a => 'qwe', :b => 'asd'}

s = Struct.new(*a.keys).new(*a.values) # Struct from Hash

h = Hash[*s.members.zip(s.values).flatten] # Hash from Struct

Ответы [ 3 ]

1 голос
/ 11 ноября 2011

Класс для хеширования.Конечно, можно написать это как метод в A, если это необходимо.

foo = A.new
foo.field1 = "foo"
foo.field2 = "bar"
hash = {}
foo.instance_variables.each {|var| hash[var.to_s.delete("@")] = foo.instance_variable_get(var) }
p hash
 => {"field1"=>"foo", "field2"=>"bar"} 

Хеширование в класс: расширение A initialize.Заимствовано из http://pullmonkey.com/2008/01/06/convert-a-ruby-hash-into-a-class-object/.

class A
  def initialize(hash)
    hash.each do |k,v|
      self.instance_variable_set("@#{k}", v)
    end
  end
end

Тогда вы можете:

hash = { :field1 => "hi" }
foo = A.new(hash)
 => #<A:0x00000002188c40 @field1="hi"> 
1 голос
/ 11 ноября 2011
 f.instance_variables.inject({}) { |m, v| m[v] = f.instance_variable_get v; m }

Хотя это дает вам @ в символах атрибута; Вы можете снять это в задании, если это важно. Обратное как раз наоборот; переберите ключи и используйте instance_variable_set.

Вы также можете опрашивать методы, оканчивающиеся на =, что было бы более надежным, если бы вы добавили логику к любому из них вместо того, чтобы полагаться на методы, созданные attr_accessor.

1 голос
/ 11 ноября 2011

С чего начать играть:

a = A.new
a.field1 = 1
a.field2 = 2
methods = a.public_methods(false).select { |s| s.end_with?("=") }
attributes = Hash[methods.map { |m| [m, a.send(m)] }]
=> {"field1"=>1, "field2"=>2}

Если вы хотите более детальное обнаружение пар геттер / сеттер:

methods = a.public_methods(false).group_by { |s| s.split("=")[0] }.
  map { |k, vs| k if vs.size == 2 }.compact

По второму вопросу:

attributes = {"field1"=>1, "field2"=>2}
a = A.new
a.each { |k, v| a.send(k+"=", v) }
=> #<A:0x7f9d7cad7bd8 @field1=1, @field2=2>

Однако может показаться, что вы хотите использовать что-то вроде Struct или OpenStruct .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...