rubygems type_structをリリースした
RubyはわりとHashオブジェクト中心なところがあって、 便利なその場限りのデータの塊として使ったり、キーワード引数として使ったりする。
でもやたらHashを使っていると、長いこと引数として使いまわしてしまい、 なんでも入れられるがゆえに「今ここでどうなってるの?」みたいなことが読みにくくなる場合がある。
僕はそういう時はStruct classの出番だと思っていて、 class名が付けられてメンバーが固定にできるので、 途中でメンバーが変わったりしないのでコードを読めばどのメンバーが入ってるか一目瞭然だ。
しかしながら、メンバーが増えてくると、どのメンバーがあったかよく分からなくなるので表記が以下のようになる。
#! /usr/bin/env ruby class Foo < Struct.new(:a, :b, :c) end f = Foo.new f.a = 123 f.b = "bar" f.c = Object.new printf "f.a: %d, f.b: %s, f.c: %s\n", f.a, f.b, f.c #=> f.a: 123, f.b: bar, f.c: #<Object:0x007f97889e0fa8>
こうなるとkeyword argumentsが欲しくなるけど、Struct.new
だと、当然最初のメンバーにHashが入ることになるので使えない。
#! /usr/bin/env ruby class Foo < Struct.new(:a, :b, :c) end p Foo.new(a: 123, b: "bar", c: Object.new) #=> #<struct Foo a={:a=>123, :b=>"bar", :c=>#<Object:0x007f9e2b187da8>}, b=nil, c=nil>
また、Structのメンバーにはどの値でも途中で入れることができるけど、Rubyは型を拒絶しダックタイピングを基礎としているので、ダックタイピングを使って、「ここは文字列ですよ」「ここは整数ですよ」というのをto_s
やto_i
を使って表すことになる。
しかしダックタイピングの弱点として、エラーが発生するのは最後の最後なので、 どこで間違った値が入ったのかよくわからないということが起こる。
というわけで、よりRubyっぽくない選択肢として、 keyword argumentsが使えて、値を入力した時に想定している値なのかゆるくチェックできるStructっぽいclassを(YAPC中に)作りました。
Rubyっぽくないといえばそれまでだけど、
class Foo < TypeStruct.new( a: String, b: Integer, ); end foo = Foo.new(a: "ksss", b: 29) p foo #=> #<Foo a="ksss", b=29> foo.a = 123 #=> TypeError: expect String got Fixnum
みたいな感じで、keyword argumentsとゆるいチェック( ===
を使用 )が出来るようになっています。
$ gem install type_struct
でどうぞ。