Rubinius Ruby で、レシーバが代入されているローカル変数名を得る
“二変数を入れ替えるメソッド”を Squeak Smalltalk と Rubinius Ruby で について rubinius-irc で言及をいただいたみたいで、そのくだりでこんなやりとりを見つけました。
17:50:55 tmornini Howdy all.http://www.donttreadonme.co.uk/rubinius-irc/rubinius.log.20080511.html
17:51:07 tmornini Is there a way to get the symbol for a current object?
17:51:25 tmornini i.e. foo.symbol => :foo
18:01:35 Defiler tmornini: What is 'foo' in that code?
この種の情報を得るのには、Rubinius で、Ruby にインクリメント演算子モドキを実装 や、 Ruby勉強会@札幌-8「Rubinius 〜Smalltalk指向のRuby処理系〜」 のデモで #succ! モドキの実現に用いた方法がそのまま使えそうですね。
module Kernel def symbol sender = MethodContext.current.sender method = sender.method array = method.decode idx = array.index(array.detect{ |inst| inst.ip == sender.ip }) bc = method.bytecodes.decode[idx - 2] if bc.size == 3 bc[1].times{ sender = sender.home } else while sender.class == BlockContext do sender = sender.home end end sender.method.local_names[bc[-1]] end end foo = :something p foo.symbol #=> :foo
Object >> getTempName | sender varIdx | sender := thisContext sender. varIdx := (sender method at: sender pc - 2) \\ 16 + 1. ^sender tempNames at: varIdx
| foo | foo := #something. ^foo getTempName "=> 'foo' "