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_sto_iを使って表すことになる。

しかしダックタイピングの弱点として、エラーが発生するのは最後の最後なので、 どこで間違った値が入ったのかよくわからないということが起こる。

というわけで、よりRubyっぽくない選択肢として、 keyword argumentsが使えて、値を入力した時に想定している値なのかゆるくチェックできるStructっぽいclassを(YAPC中に)作りました。

github.com

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

でどうぞ。