2012-08-13 148 views
3

寻找宝石或至少知道如何解决这个问题,那些我不完全优雅:)映射的哈希映射到类实例

的想法很简单,我想映射散列比如:

{ :name => 'foo', 
    :age => 15, 
    :job => { 
     :job_name => 'bar', 
     :position => 'something' 
    ... 
    } 
} 

向类的对象(具有扁平构件结构)或结构,例如:

class Person { 
    @name 
    @age 
    @job_name 
    ... 
} 

感谢所有。

+1

我在我个人的扩展库中的'哈希#to_ostruct'方法:http://rubydoc.info/gems/shenanigans/ 1.0.5/Hash:to_ostruct它也可以正确处理嵌套数组和散列。这不是针对这个特定问题的解决方案,但您可能会发现它很有趣。 – 2012-08-13 13:59:18

+0

@MichaelKohl :)非常优雅的解决方案(在git上找到它)。你应该将它作为答案发布。 – 2012-08-13 14:07:20

+0

@MichaelKohl对于不是散列的数组元素,代码是否会失败?可能我错过了一些东西...... – 2012-08-13 14:47:54

回答

1

假设你可以肯定的子项的项将不会包含输入键冲突,这里的一些代码,应该工作...我用它

require 'ostruct' 

def flatten_hash(hash) 
    hash = hash.dup 
    hash.entries.each do |k,v| 
    next unless v.is_a?(Hash) 
    v = flatten_hash(v) 
    hash.delete(k) 
    hash.merge! v 
    end 
    hash 
end 

def flat_struct_from_hash(hash) 
    hash = flatten_hash(hash) 
    OpenStruct.new(hash) 
end 
+0

非常好,波纹管是我的解决方案,它处理子键问题,但没有扁平结构。 – 2012-08-13 13:56:19

+0

除此之外:我更倾向于'o.is_a?()'在' === o''上,因为它适用于duck-type编码。任何类都可以重写#is_a?方法返回任何它想要替代的类或类的真。 – 2012-08-13 14:13:23

0

解决方案解决了问题,同样的键名但它并没有给出扁平的阶级结构。有人可能会发现这个方便,只需记住保留名称的值,如id,类型需要处理。

require 'ostruct' 

    def to_open_struct(element) 
    struct = OpenStruct.new 
    element.each do |k,v| 
     value = Hash === v ? to_open_struct(v) : v 
     eval("object.#{k}=value") 
    end 
    return struct 
    end 
0

,你知道前手的钥匙的替代答案

class Job 
    attr_accessor :job_name, :position 

    def initialize(params = {}) 
    self.job_name = params.fetch(:job_name, nil) 
    self.position = params.fetch(:position, nil) 
    end 
end 

class Person 
    attr_accessor :name, :age, :job 

    def initialize(params = {}) 
    self.name = params.fetch(:name, nil) 
    self.age = params.fetch(:age, nil) 
    self.job = Job.new(params.fetch(:job, {})) 
    end 
end 


hash = { :name => 'foo', :age => 1, :job => { :job_name => 'bar', :position => 'soetmhing' }} 
p = Person.new(hash) 

p.name 
==> "foo" 

p.job 
==> #<Job:0x96cacd8 @job_name="bar", @position="soetmhing"> 

p.job.name 
==> "bar"