method_sourceってgemを読んだら知恵が詰まってた。


method_source is 何?


minimum sample

require 'method_source'

def my_important_method
# do nothing, just sleep
sleep 4
'successfuly done with my hard work!!'
end

method = method(:my_important_method)
method.source.display

すると。。。

def my_important_method

# do nothing, just sleep
sleep 4
'successfuly done with my hard work!!'
end

メソッドの定義がプリントされる。


どんな実装か

Method objectからは定義もとのfile, lineが取れる。

そのファイルを全部読み込み、line以下を全て取ってくる

lines = File.readlines(file)

lines = lines[(line - 1)..-1]

linesをイテレートして、methodの定義が終わるところを判定する。

lines.each do |v|

code << v
return code if complete_expression?(block ? block.call(code) : code)
end

これでmethod定義が抜き出せたので、あとは表示するだけ


知恵

rescueされるerrorを判別するだけのmodule

def hoge

rescue MyModule
end

module MyModule
def self.===(error)
some_condition(error)
end
end

evalを使ってstrの構文をチェックだけして、BEGIN throwで実行させずに戻る

catch(:valid) do

eval("BEGIN{throw :valid}\n#{str}")
end

どうゆう仕組みか?

strが構文としておかしいとSyntaxErrorが出て throwされない。

strが構文としてokだったらそのstr実行前に BEGIN で登録された throwが走る。


所感

まず BEGIN とか知らなかった。

この3行でこれだけのこと詰め込めるrubyはスマートで好き。