Class#def_initailize

class Foo
  def initialize(foo, bar, baz)
    @foo = foo
    @bar = bar
    @baz = baz
  end
end

は各変数を 3 回も書いてぜんぜん DRY じゃなくて嫌。

class Foo
  def initialize(*a)
    @foo, @bar, @baz = *a
  end
end

は引数のチェックをしなくなるし、なんか嫌。

Foo = Struct.new(:foo, :bar, :baz)

はまあいいんだけど、なにか継承したいときに困るし、勝手にアクセサ定義されるし、まあなんか嫌。
ということで、こんなの考えた。

class Foo
  def_initialize(:@x, :@y, :@z)

  def foo
    p [@x, @y, @z]
  end
end

Foo.new(1, 2, 3).foo  #=> [1, 2, 3]

ううん、微妙だ。一応以下が実装。

class Class
  def def_initialize(*vars)
    define_method(:initialize) do |*vals|
      if vars.size != vals.size
        msg = "wrong number of arguments (#{ vals.size } for #{ vars.size })"
        raise ArgumentError, msg
      end
      vars.zip(vals) {|var, val| instance_variable_set(var, val) }
      yield if block_given?
    end
  end
end