2016-07-20 7 views
0

これは私の問題です。私はAndrea Pavoniのネストされたハッシュを使ってクラスを初期化することができます。Ruby:ネストされたハッシュといくつかの既定の既定値を持つRubyクラスを初期化します

オリジナルの挙動デフォルトなし(上で次のように動作がなるよう

require 'ostruct' 

class DeepStruct < OpenStruct 
    def initialize(hash=nil) 
    @table = {} 
    @hash_table = {} 

    if hash 
     hash.each do |k,v| 
     @table[k.to_sym] = (v.is_a?(Hash) ? self.class.new(v) : v) 
     @hash_table[k.to_sym] = v 

     new_ostruct_member(k) 
     end 
    end 
    end 

    def to_h 
    @hash_table 
    end 

end 

しかし、私は、特定のデフォルト値を持つ(クラス)のハッシュを含める方法を見つけることができませんコード):

default_h = {a: {dc: 2}, dd: {de: 4}} 
:クラス内で定義された次default_hで

input_hash = {a: {b: 1}} 
new_object = DeepStruct.new hash 
new_object.a  # => #<DeepStruct b=1> 
new_object.a.b # => 1 
new_object.a.to_h # => {b: 1} 

デフォルトのハッシュと (実際には、ネストされたハッシュのためdeep_mergeを使用して)

{:a=>{:dc=>2, :b=>1}, :dd=>{:de=>4}} 

行動を次のように10

input_hashとdefault_hはマージする必要がありますする必要があります:

new_object = DeepStruct.new hash 
new_object.a.b # => 1 
new_object.a.dc # => 2 
new_object.a.to_h # => {:dc=>2, :b=>1} 

私は方法を見つけることができませんクラス内でこの動作を実装します。私は本当にこの問題の助けを感謝します。

編集:今すぐクラスにDavidのコードを使用しようとしている:

class CompMedia 
    require 'ostruct' 
    attr_accessor :merged_h 

    def initialize(hash) 
     defaults = {a: {dc: 2}, dd: {de: 4}} 
     @merged_h = {} 
     deep_update(merged_h, defaults) 
     deep_update(merged_h, hash) 
     @merged_h 
    end 

    def deep_update(dest, src) 
     src.each do |key, value| 
     if value.is_a?(Hash) 
      dest[key] = {} if !dest[key].is_a?(Hash) 
      deep_update(dest[key], value) 
     else 
      dest[key] = value 
     end 
     end 
    end 

    def deep_open_struct(hash) 
     result = OpenStruct.new 
     hash.each do |key, value| 
     if value.is_a?(Hash) 
      result[key] = deep_open_struct(value) 
     else 
      result[key] = value 
     end 
     end 
     result 
    end 

end # class CompMedia 

input_hash = {a: {b: 1}} 

cm = CompMedia.new(input_hash) 

object = cm.deep_open_struct(cm.merged_h) 

p object.marshal_dump # {:a=>#<OpenStruct dc=2, b=1>, :dd=>#<OpenStruct de=4>} 
p object.a    # <OpenStruct dc=2, b=1> 
p object.a.marshal_dump # {:dc=>2, :b=>1} 
p object.a.b    # 1 
p object.a.dc   # 2 
p object.dd    # <OpenStruct de=4> 

を明らかに、私は簡単な方法でopenstructオブジェクトからネストされたハッシュの要素を取得する方法を発見していません。 私の目的は、クラスに含まれるデフォルト(ネストされた)ハッシュと(ネストされた)入力ハッシュで初期化されるクラスを作成することです。また、クラス内でハッシュを処理するメソッドを追加できるようにしたい。私はまだそこにいません。誰かが使ってコードを作ることができない限り、私は私の解決策として最後のバージョンを検討する

class CompMedia 
    attr_accessor :merged_h 

    def initialize(hash) 
     defaults = {a: {dc: 2}, dd: {de: 4}} 
     @merged_h = {} 
     deep_update(merged_h, defaults) 
     deep_update(merged_h, hash) 
     @merged_h 
    end 

    def deep_update(dest, src) 
     src.each do |key, value| 
     if value.is_a?(Hash) 
      dest[key] = {} if !dest[key].is_a?(Hash) 
      deep_update(dest[key], value) 
     else 
      dest[key] = value 
     end 
     end 
    end 

    def multiply_by(k) 
     merged_h[:a][:dc] * k 
    end 

end 

input_hash = {a: {b: 1}} 

cm = CompMedia.new(input_hash) 
p cm.merged_h   # {:a=>{:dc=>2, :b=>1}, :dd=>{:de=>4}} 
p cm.merged_h[:a]  # {:dc=>2, :b=>1} 
p cm.merged_h[:a][:dc] # 2 
p cm.merged_h[:dd]  # {:de=>4} 
p cm.multiply_by(10) # 20 

一方、私はマージされたハッシュを使用することができ、これは少し面倒な表記でいえ働くだろう私が望むOpenStructの仕事。

答えて

1

OpenStructをサブクラス化するという考えを捨てた以外は、あなたが望むことをするコードがいくつかありますが、これは良いアイデアかどうかわかりませんでした。また、自分でdeep_mergeを実装したのはかなり簡単でしたが、必要に応じてActiveSupportのバージョンを使用してみることもできます。

require 'ostruct' 

# Merges two hashes that could have hashes inside them. Default 
# values/procs of the input hashes are ignored. The output hash will 
# not contain any references to any of the input hashes, so you don't 
# have to worry that mutating the output will affect the inputs. 
def deep_merge(h1, h2) 
    result = {} 
    deep_update(result, h1) 
    deep_update(result, h2) 
    result 
end 

def deep_update(dest, src) 
    src.each do |key, value| 
    if value.is_a?(Hash) 
     dest[key] = {} if !dest[key].is_a?(Hash) 
     deep_update(dest[key], value) 
    else 
     dest[key] = value 
    end 
    end 
end 

def deep_open_struct(hash) 
    result = OpenStruct.new 
    hash.each do |key, value| 
    if value.is_a?(Hash) 
     result[key] = deep_open_struct(value) 
    else 
     result[key] = value 
    end 
    end 
    result 
end 

input_hash = {a: {b: 1}} 
defaults = {a: {dc: 2}, dd: {de: 4}} 
object = deep_open_struct(deep_merge(defaults, input_hash)) 
p object.a.b 
p object.a.dc 
p object.a.to_h 
+0

これはうまくいきますが、デフォルトのハッシュを含むクラスが必要で、マージされたハッシュ(デフォルト+入力)で初期化されている必要があります。その理由は、ハッシュの内容を処理するメソッドを追加したいからです。私はあなたのコードでそれに取り組んでおり、何かを見つけたら投稿します。なぜOpenStructをサブクラス化するのが悪い考えですか? – JMor

+0

デフォルトのハッシュを保持するクラスを持つのは難しくありません。コードをそのままこの投稿に残して、内部的に使用するクラスを作成することができます。 –

+0

私はそれをしました。しかし、私は、マージされたハッシュにアクセスするクラスのメソッドに苦労しています。 – JMor

関連する問題