StructとYAMLの仲を取り持つHash

StructとYAMLとHashが連携する機会が多いので最も頑張っているHashにヘルパーさんをつけることにした

HashHelperとその働き
# coding: CP932
require "yaml"
require "pp"

module HashHelper

  module ClassMethods

    def new_each_block
      new { |hash, key| hash[key] = self.new_each_block }
    end

  end
  
  module InstanceMethods

    def to_struct
      Struct.new( *self.keys )
            .new( *self.values.map{ |e| Hash === e ? e.to_struct : e } )
    end

  end
      
  def self.included(receiver)
    receiver.extend         ClassMethods
    receiver.send :include, InstanceMethods
  end

end

class Hash
  include HashHelper
end



module YOML

  class << self

    def dump( obj, io=nil )
      sio = StringIO.new
      ( io || sio ) << YAML.dump_stream(obj).gsub(/":?.+"/) { |s| eval(s) }
      io ? io.close : sio.rewind && sio.read
    end

  end

end

if __FILE__ == $0

@dic = Hash.new_each_block
@dic[:EJ][:I][:am][:a][:satisfied][:customer] = "そちらでの買い物に大変満足しています"
@dic[:EJ][:I][:am][:a][:Christian]            = "私はクリスチャンです"
@dic[:EJ][:I][:am][:a][:dancer]               = "【映画】華麗なるダンサー◆英1972"
@dic[:EJ][:I][:got][:burned][:Christian]      = "火傷をした"
@dic[:EJ][:I][:got][:carried][:away]          = %w{調子に乗り過ぎた はしゃぎ過ぎた 悪乗りし過ぎた}
# 日本語メソッドは作れるが呼び出すのは困難
@dic[:JE][:私は][:クリスチャン][:です]        = "I am a Christian"

pp @dic

YOML.dump( @dic, File.open( "dic.yaml", "w" ) )
dic = YAML.load( File.open( "dic.yaml" ) ).to_struct

puts dic.EJ.I.am.a.satisfied.customer
puts dic.EJ.I.am.a.dancer
puts dic.EJ.I.got.carried.away*"/"

end
出力結果(ハッシュ)
{:EJ=>
  {:I=>
    {:am=>
      {:a=>
        {:satisfied=>{:customer=>"そちらでの買い物に大変満足しています"},
         :Christian=>"私はクリスチャンです",
         :dancer=>"【映画】華麗なるダンサー◆英1972"}},
     :got=>
      {:burned=>{:Christian=>"火傷をした"},
       :carried=>{:away=>["調子に乗り過ぎた", "はしゃぎ過ぎた", "悪乗りし過ぎた"]}}}},
 :JE=>{:私は=>{:クリスチャン=>{:です=>"I am a Christian"}}}}
出力結果(ハッシュの値)
そちらでの買い物に大変満足しています
【映画】華麗なるダンサー◆英1972
調子に乗り過ぎた/はしゃぎ過ぎた/悪乗りし過ぎた