大量のハッシュデータを簡潔に作成する

スクリプト言語では Hash や dict のリテラルが用意されているので、書きやすい。しかしテストデータなどで大量の記述が必要になると、さすがにちょっと面倒である。

data = [
  {:name=>"Haruhi", :gender=>1, :role=>"Leader of SOS Brigade"},
  {:name=>"Mikuru", :gender=>1, :role=>"Time Traveler"},
  {:name=>"Yuki",   :gender=>1, :role=>"Humanoid Interface"},
  {:name=>"Itsuki", :gender=>0, :role=>"ESPer Boy"},
  {:name=>"Kyon",   :gender=>0, :role=>"Story Teller"},
]

同じキーが繰り返し出てくるのがいやだよね。これなら Excel のほうがまだまし。
#同じキーが繰り返されていることに何も感じないプログラマーがいたら、センスがないので勉強しなおしたほうがいい。


で、これをもっと簡潔に書くために、次のような utility method を定義してみた。

class Hash
  def self.create_with(*keys)
    return yield.collect {|row|
      hash = self.new
      keys.zip(row) {|k, v| hash[k] = v }
      hash
    }
  end
end

使い方はこんな感じ。けっこう良くね?

data = Hash.create_with(:name, :gender, :role) {[
  ["Haruhi", 1, "Leader of SOS Brigade"],
  ["Mikuru", 1, "Time Traveler"],
  ["Yuki",   1, "Humanoid Interface"],
  ["Itsuki", 0, "ESPer Boy"],
  ["Kyon",   0, "Story Teller"],
]}
require 'pp'
pp data
### 実行結果:
# [{:gender=>1, :role=>"Leader of SOS Brigade", :name=>"Haruhi"},
#  {:gender=>1, :role=>"Time Traveler", :name=>"Mikuru"},
#  {:gender=>1, :role=>"Humanoid Interface", :name=>"Yuki"},
#  {:gender=>0, :role=>"ESPer Boy", :name=>"Itsuki"},
#  {:gender=>0, :role=>"Story Teller", :name=>"Kyon"}]

YAML を使えば、quote も消える!

yaml = <<'END'
[
  [Haruhi, 1, Leader of SOS Brigade],
  [Mikuru, 1, Time Traveler],
  [Yuki,   1, Humanoid Interface],
  [Itsuki, 0, ESPer Boy],
  [Kyon,   0, Story Teller]
]
END
require 'yaml'
data = Hash.create_with(:name, :gender, :role) { YAML.load(yaml) }

けっこうお気に入り。

追記: YAMLのサンプルだけど、なんでブロック構文を使わなかったのだろう。YAML使いとして恥ずかしい限りだ。申し訳ありませんが上のサンプルは忘れて下のを参考にしてください。

yaml = <<'END'
- [Haruhi, 1, Leader of SOS Brigade]
- [Mikuru, 1, Time Traveler]
- [Yuki,   1, Humanoid Interface]
- [Itsuki, 0, ESPer Boy]
- [Kyon,   0, Story Teller]
END
require 'yaml'
data = Hash.create_with(:name, :gender, :role) { YAML.load(yaml) }