Kernel.send :define_method

method_missing やだなーと思ったので、似たことをやる別解を

describe "Kernel.send :define_method & send例" do
  class Calc2
    def initialize
      yield self if block_given?
    end

    def defun(key, &block)
      Kernel.send :define_method, key.to_sym do |*args|
        yield(args)
      end
    end
  end

  subject {
    Calc2.new do |c|
      c.defun(:plus)  {|args| args.reduce(:+) }
      c.defun(:minus) {|args| args.reduce(:-) }
      c.defun(:multi) {|args| args.reduce(:*) }
      c.defun(:greeting)  {|name, world| "hello #{name}. I love #{world}" }
    end
  }

  it "メソッド呼び出しのようにできること" do
    subject.plus(4, 3, 2).should == 9
    subject.minus(10, 1, 2).should == 7
    subject.multi(2, 3).should == 6
    subject.greeting("haru01", "Ruby").should == "hello haru01. I love Ruby"
  end

  it "メソッド呼び出しのようにできること" do
    subject.send(:plus, 4, 3, 2).should == 9
    subject.send(:minus, 10, 1, 2).should == 7
    subject.send(:multi, 2, 3, 3).should == 18
    subject.send(:greeting, "haru01", "Ruby").should == "hello haru01. I love Ruby"
  end
end

:define_method & send を使ったら、インスタンス変数も消去できて、すっきりした。