世界線航跡蔵

Mad web programmerのYuguiが技術ネタや日々のあれこれをお送りします。

2008年07月23日

RubyでPythonのdecoratorっぽいもの

Pythonのdecoratorは格好いいよね。Rubyでこんな感じのものを作れないかと何回か考えたものの、上手いAPIを思いつかずにいた。

このたび、technohippyさんの挑戦に刺激されて書いてみた。

仕様としてはPythonに合わせて、呼び出し可能オブジェクトを返す関数としてdecoratorを作成する。そして、declareというメソッドにdecoratorを渡すと、ブロック内で定義されたメソッドはdecoratorで修飾される。

class Module
 def type(name, types)
    before(name) do |name, args|
      args.zip(types).each_with_index do |(arg, type), i|
        raise TypeError, "#{i}th argument #{arg} should be #{type}" unless arg.instance_of?(type)
      end
    end
  end

  def always_one(name)
     proc{|*args| 1 }
  end
end

class Calc
  declare :type, [Float, Float] do
    def add(x,y); x+y end
    def sub(x,y); x-y end
    def mul(x,y); x*y end
  end
  declare :always_one do
    def div(x,y); x/y end
  end
end

calc = Calc.new
p calc.add(1.0, 2.0)
p.calc.div(1.0, 2.0)   #=> 1
p calc.sub(1.0, 2)     #=> TypeError

ポイント

  • Rubyなんだからブロック使おうよ、という。Module#privateみたいに頑張ってブロックなしにするのも考えたけど、労多くして実り少なしだよね。
  • Ruby 1.8.7以降で動作する。
  • 特異メソッドに非対応
  • イテレータは修飾できない。define_methodにブロックを渡した場合、呼び出し時にメソッド本体へブロックを渡す方法がないので。Ruby 1.9だと頑張ればできるんだけど。
  • UnboundMethod経由のメソッドすり替えを試せて楽しかった。
  • もうちょっと真面目に書いてgem化したら誰か使う?

トラックバック

http://yugui.jp/articles/792/ping

現在のところトラックバックはありません

コメント

technohippy (2008年07月24日 01時15分54秒)
<p>ブロックの中に入れてmethod_addedで拾うのかー。<br />いろいろ勉強になります。</p>
blog comments powered by Disqus

ご案内

前の記事
次の記事

タグ一覧

過去ログ

  1. 2016年07月
  2. 2016年01月
  3. 2015年09月
  4. 2015年08月
  5. 過去ログ一覧

フィード

フィードとは

その他

Powered by "rhianolethe" the blog system