読者です 読者をやめる 読者になる 読者になる

処理が同じ俺定義Getter Setterを自動生成する

Rubyはattr_accessorとか書くとプロパティが作れるわけだが、これはインスタンス変数を読み書きするだけ。それ以上の動作をさせたい場合は自分でメソッドを定義する必要がある。

しかし名前が違うだけで処理内容が同じプロパティが沢山あったら超面倒くさい。例えば…

class Test
  def initialize
    @hash = Hash.new
  end 

  def hoge; @hash["hoge"]; end
  def fuga; @hash["fuga"]; end
  def piyo; @hash["piyo"]; end

  def hoge=(val); @hash["hoge"]=val; end
  def fuga=(val); @hash["fuga"]=val; end
  def piyo=(val); @hash["piyo"]=val; end
end

この程度ならば何とかなるが、処理が複雑になったり数がもっと増えたらやってられない。何か良い方法がありそうな気がするのだが見つからなかったので、Module#define_methodを使って何とかしてみた。

module Mod
  def define_accessors(*args)
    args.each do |attr|
      define_method(attr) { reader(attr) }
      define_method((attr.to_s+"=").to_sym) { |value| writer(attr, value)}
    end
  end
end

class Test
  extend Mod

  define_accessors :hoge, :fuga, :piyo

  def initialize
    @hash = Hash.new
  end

  def reader(name)
    @hash[name]
  end

  def writer(name, value)
    @hash[name] = value
  end
end

test = Test.new
test.hoge = "a"
test.fuga = "b"
p test.hoge  => "a"
p test.fuga  => "b"

define_methodはModuleの中でしか呼べないので適当なモジュールを作ってextendするという方法をとる。define_accessorsをModuleクラスに追加しても良いが標準ライブラリはあんまり弄りたくない。

class Module
  def define_accessors(*args)
    args.each do |attr|
      define_method(attr) { reader(attr) }
      define_method((attr.to_s+"=").to_sym) { |value| writer(attr, value)}
    end
  end
end

class Test
  define_accessors :hoge, :fuga, :piyo

  def initialize
    @hash = Hash.new
  end

  def reader(name)
    @hash[name]
  end

  def writer(name, value)
    @hash[name] = value
  end
end

もっと上手い方法がないかなー、とゆうかRubyならば標準機能にあってもおかしくなさそうな気がするんだけど…

あと、コード量増えてんじゃん!というツッコミはなしの方向でお願いします。