如何将Class映射到Hash,反之亦然

时间:2011-11-10 20:33:28

标签: java ruby

我有一个班级,就像这个:

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

使用从类实例中获取的键和值来生成哈希的最佳方法是什么?

使用Hash中的值填充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 个答案:

答案 0 :(得分:1)

开始玩的东西:

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}

如果你想更精细地检测对getter / setter:

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>

但是,您似乎希望使用StructOpenStruct之类的内容。

答案 1 :(得分:1)

要哈希的类。当然,如果需要,可以将其写为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"} 

Hash to class:扩展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"> 

答案 2 :(得分:1)

 f.instance_variables.inject({}) { |m, v| m[v] = f.instance_variable_get v; m }

虽然这样可以在属性符号中显示@;如果它很重要,你可以在作业中将其剥离。反过来恰恰相反;迭代密钥并使用instance_variable_set

您还可以查询以=结尾的方法,如果您为其中任何一个添加逻辑而不是依赖attr_accessor创建的方法,则会更加健壮。