引数にメソッド追加してリテラル風にするんだったら(追記)

id:takkawさんから返信を頂きました。
コメントしようかと思ったんですが長くなってしまったので、追記にしようと思ったらさらに長くなったので独立したエントリで。

特に実装側がinstance_variable_set だけで良いし。

http://d.hatena.ne.jp/takkaw/20080721/p1

これはそのまま欠点にもなって、例えばNumeric#bitが@sample_bitしか表せないのでGameRom.new(16.bit)とかには使えないんですよね。汎用性がない。
Symbolを渡しておいて実装側で処理を決定するほうが汎用的ではあります。

一方、ハッシュにしておくと、従来の通りのハッシュによる指定もできるしなー

http://d.hatena.ne.jp/takkaw/20080721/p1

そうなんですよね。

Wav.new(1.channel, 44100.hz, 16.bit)
Wav.new(:channel => 1, :freq => 44100, :bit => 16)

が同義になるのが理想だと思います。


これ書いたときはHashの配列をmergeする手段がぱっと思いつかなかったのですが、良く考えると

args.inject({}){ |result, value| result.merge! value }

の一行で済みますね。


上記を踏まえて、こんな感じの実装も考えてみました。

# 仕込み
class Numeric
  def hz      ; {:freq,    self}        ; end
  def khz     ; {:freq,    self * 1000} ; end
  def bit     ; {:bit,     self}        ; end
  def channel ; {:channel, self}        ; end
  def ch      ; {:channel, self}        ; end
end

# 実際のWavクラス
class Wav
  def initialize *args
    options = args.inject({}){ |result, value| result.merge! value }
    
    options.each_pair do |key, value|
      case key
      when :channel ; @channels    = value
      when :freq    ; @sample_rate = value
      when :bit     ; @sample_bit  = value
      end
    end
  end
end

これで、Hashで渡してもメソッドで渡しても同義になるはずです。

p Wav.new(1.channel, 44100.hz, 16.bit)               #=> #<Wav:0x2b2e77c @channels=1, @sample_bit=16, @sample_rate=44100>
p Wav.new(44100.hz, 16.bit, 1.channel)               #=> #<Wav:0x2b2e5d8 @channels=1, @sample_bit=16, @sample_rate=44100>
p Wav.new(:channel => 1, :freq => 44100, :bit => 16) #=> #<Wav:0x2b2e470 @channels=1, @sample_bit=16, @sample_rate=44100>