0

mix-inした関数を上書き定義前にalias_methodで退避する

用途

Ruby版EventEmitterなどのincludeして既存クラスを拡張するタイプのライブラリを使う時に、mix-inされる関数と自分の関数の名前が衝突してしまう場合に有用。

Ruby用のsocket.io実装を作っているんだけど、EventEmitter gemで定義されているemit関数を__emitに退避してemitを新たに自分で定義するのに使った。


alias_methodで関数名の衝突を回避する

module Fooをclass Barにincludeした時に、FooにもBarにも同じ関数を定義している場合、クラスの方に定義した関数の方が優先される。
モジュールの方の、せっかくincludeでmix-inした関数は消滅してしまう

includeしたmoduleの方の関数fooも使いたい場合、includeしてすぐにalias_methodで別名に退避するとよい。

module Foo
def foo
puts "foo called!!"
end
end

class Bar
include Foo
alias_method :__foo, :foo ## fooを別名(__foo)に退避

def bar
puts "bar called!!"
end

def foo
puts "Bar's foo called.."
end
end


bar = Bar.new
bar.bar
bar.__foo # include後に退避したmoduleの関数が呼ばれる
bar.foo # include後に上書きした関数が呼ばれる


結果
bar called!!
foo called!!
Bar's foo called..


alias_methodのタイミング

関数の上書き定義後にalias_methodを使っても、退避できない。

module Foo
def foo
puts "foo called!!"
end
end

class Bar
include Foo

def bar
puts "bar called!!"
end

def foo
puts "Bar's foo called.."
end

alias_method :__foo, :foo ## 上書き定義した後にエイリアスでの退避を試みる
end


bar = Bar.new
bar.bar
bar.__foo
bar.foo

fooも__fooも、どちらも上書き定義されたメソッドが呼ばれる。
bar called!!
Bar's foo called..
Bar's foo called..

ちなみにもちろんinclude前にalias_methodしても、NameError(undefined method)例外が起こる。

0

node-methodmissingを高速化した

methodmissingというnpmがあって、rubyのmethodmissingと同じく存在しなメソッドを呼び出した時にno method errorにするのではなく、メソッド名と引数を横取りできる。


使用例

mm = require 'methodmissing'

class Foo
baz: "bazbaz"

foo = new Foo()

## methodmissingを適用
foo = mm foo, (func_name, args) ->
console.log "missing-method '#{func_name}' called"
console.log args


## 普通のメソッド呼び出し
console.log foo.baz

## 存在しないメソッドを呼び出す
foo.kazusuke("niku", "beer", "rice")

実行結果
bazbaz
missing-method 'kazusuke' called
{ '0': 'niku', '1': 'beer', '2': 'rice' }


存在しないメソッドが呼び出された時に、動的にメソッドが存在するフリをできるのはWebAPIのラッパーを作る時などに便利。


高速化


ベンチマークを取ってみたら、
存在しないメソッド呼び出しをキャプチャーするのは6〜7倍ぐらい速くなった。普通のメソッド呼び出しと比べて10倍遅い程度。
また、methodmissing適用した後のオブジェクトは通常のメソッド呼び出しが100倍ぐらい遅くなっていたのを、9倍遅い程度に抑えられた。

(methodmissingでメソッドを呼び出すコストが通常のメソッド呼び出しに比べて10倍ぐらい遅くなるだけで、呼び出されたメソッド全体の速度が遅くなるわけではないので、ループで何万回も呼び出す等でない限りこのコストは無視していいと思う)


といっても修正したの1行だけなんだけど、けっこうこういうので変わるものだな

存在しないプロパティを呼び出した時の動作が遅いのがまだ気になる。

0

shinjuku.rb #18でメタプログラミングについて話した

けどいた人のレベル的にあまり新鮮味は無かったかもしれませんね

内容は

  • skype → method_missing
  • babascript → instance_eval
  • event_emitter → mix-in
です


どうでもいいけどjoker1007さんの眉毛には親近感を覚えた

Shinjuku.rb #18 on Zusaar