そこでStructですよ

「怠慢はプログラマの美徳」というけれど - kなんとかの日記

俺がJavaに萌えない理由を100%代弁してくれている。それはさておき、

data = [
  {'name'=>'Foo', 'age'=>20, 'email'=>'foo@mail.com'},
  {'name'=>'Bar', 'age'=>21, 'email'=>'bar@mail.net'},
  {'name'=>'Baz', 'age'=>22, 'email'=>'baz@mail.org'},
]

うむ、たしかに冗長だ…

だけど3つくらいならそのまま書くかもしれない。多くなると俺は「怠惰」だからmapとStruct使う。

require 'pp'

[ ['Foo',   20,   'foo@mail.com'],
  ['Bar',   21,   'bar@mail.net'],
  ['Baz',   22,   'baz@mail.org'],
].map{ |n,a,e| {'name' => n, 'age' => a, 'email' => e} }.tap{|_| pp _}
################ vs ################
Person = Struct.new(:name, :age, :email)
[ ['Foo',   20,   'foo@mail.com'],
  ['Bar',   21,   'bar@mail.net'],
  ['Baz',   22,   'baz@mail.org'],
].map{ |elms| Person.new(*elms) }.tap{|_| pp _}
# >> [{"name"=>"Foo", "age"=>20, "email"=>"foo@mail.com"},
# >>  {"name"=>"Bar", "age"=>21, "email"=>"bar@mail.net"},
# >>  {"name"=>"Baz", "age"=>22, "email"=>"baz@mail.org"}]
# >> [#<struct Person name="Foo", age=20, email="foo@mail.com">,
# >>  #<struct Person name="Bar", age=21, email="bar@mail.net">,
# >>  #<struct Person name="Baz", age=22, email="baz@mail.org">]

↑のdataを得たければ前者を、Struct使うなら後者を。

Person = Struct.new :name, :age, :email
s = Person.new "Foo", 20, "foo@mail.com"
s["name"]                       # => "Foo"
s[:name]                        # => "Foo"
s[0]                            # => "Foo"
s.name                          # => "Foo"

RubyのStructは萌える。なんせStringでもSymbolでもFixnumでもインデックスにできるし、アクセサにもなる。たまにはStructのことも思い出してあげてください。

ちなみに tap はメソッドチェーンで自分自身に作用させるときに便利Ruby 1.8でも1.8.7から使えるようになる。

Structとmapであっさり書けるから、わざわざ%hリテラルを導入するには弱いと思う。

追記

こっちのほうがmapがなくていいのかな。Person.newが冗長だって!?

Person = Struct.new(:name, :age, :email)
[ Person.new('Foo', 20, 'foo@mail.com'),
  Person.new('Bar', 21, 'bar@mail.net'),
  Person.new('Baz', 22, 'baz@mail.org'),
].tap{|_| pp _}
# >> [#<struct Person name="Foo", age=20, email="foo@mail.com">,
# >>  #<struct Person name="Bar", age=21, email="bar@mail.net">,
# >>  #<struct Person name="Baz", age=22, email="baz@mail.org">]