HashKeyOrderable

っていうものを作りました。http://gist.github.com/358709

作った動機

Hashをeachで繰り返すときにキーで順序を指定したい、というのはたまにありますが、出力したい順序が決まっている場合もある。

例えば、赤、青、黄色という順番で出力したいとか。

colors = {:red => 1, :blue => 2, :yellow => 4}
#=> {:blue=>2, :yellow=>4, :red=>1}
colors.each{|k,v| puts "#stdout #{k.inspect}: #{v.inspect}"}
#stdout :blue: 2
#stdout :yellow: 4
#stdout :red: 1

これを

#stdout :red: 1
#stdout :blue: 2
#stdout :yellow: 4

という順に出力させたい。

使い方

http://gist.github.com/358709
の内容をhash_key_orderable.rb とかいう名前にして、使用したい箇所でrequireする。で、対象のHashにHashKeyOrderableをextendさせて、key_order=メソッドで出力したい順番を指定すればOK。

colors.extend(HashKeyOrderable)
#=> {:blue=>2, :yellow=>4, :red=>1}
colors.key_order = [:red, :blue, :yellow]
#=> [:red, :blue, :yellow]

colors.each{|k,v| puts "#stdout #{k.inspect}: #{v.inspect}"}
#stdout :red: 1
#stdout :blue: 2
#stdout :yellow: 4

特徴

key_orderに指定していないキーがHashに含まれている場合は、key_orderで指定されたものよりも後にブロックに渡される。また、inspectも拡張するのでとても読みやすいはず。

rainbow = {:red => 1, :orange => 2, :yellow => 4, :green => 8, :blue => 16, :navy => 32, :purple => 64}
#=> {:navy=>32, :blue=>16, :purple=>64, :yellow=>4, :orange=>2, :green=>8, :red=>1}
rainbow.extend(HashKeyOrderable)
#=> {:navy=>32, :blue=>16, :purple=>64, :yellow=>4, :orange=>2, :green=>8, :red=>1}
rainbow.key_order = [:red, :blue, :yellow]
#=> [:red, :blue, :yellow]
puts rainbow.inspect
{:red=>1, :blue=>16, :yellow=>4, :navy=>32, :purple=>64, :orange=>2, :green=>8}
#=> nil

逆にkey_order=で指定されているが、Hashには含まれていないキーの場合は単純に無視されます。

rainbow.key_order = [:red, :blue, :yellow, :black]
#=> [:red, :blue, :yellow, :black]
puts rainbow.inspect
{:red=>1, :blue=>16, :yellow=>4, :navy=>32, :purple=>64, :orange=>2, :green=>8}
#=> nil