實做 Binding.pm
作者:gugod 發佈於: #perl #cpan #ruby #tcl下午連續喝了三杯之前在菡萏買的 Espresso 綜合豆,雖然有點小過期,帶點雜味,但是仍然是酸勁十足。
結論:動態語言果然好玩。
之前在寫 Markapl 的時候,曾經需要解這這個問題:
執行以下這段程式時:
eval 'my @attr = ($x, $y)';
如何使其中 $x
與 $y
的的值,參照到 caller 之中的同名變數。
換同話說,如何實做出以下這段程式中的 caller_eval 函式:
sub x_add_one {
caller_eval '$x + 1';
}
sub ans {
my $x = 41;
x_add_one;
}
print ans; #42
實際上在 Markapl 中碰到的狀況比較廣泛一些,但是只要寫出這裡的 caller_eval
函式,就可以一併解決。今天則是把這個做法整理成一個單獨的模組,也就是 Binding.pm
。
在其他動態語言中,能同樣解決這個問題的,有 Tcl 的 uplevel
函式,以及 Ruby 中的 Binding.of_caller
方法。
我實際上實做的用法是參照 Ruby 的 Binding
類別而提供了 Binding.pm
模組,用法如下:
my $binding = Binding->of_caller;
$binding->eval('$x + 1');
這些例子都算是比較特例,因為傳給 eval
的程式碼中實際寫了會用到的變數 $x
,在 Markapl 的例子裡,變數名稱也是個變數,因此才會需要通用的解法。
實際的做法是利用 PadWalker
的 peek_my
加上 Data::Dump
的 pp
函式將上層的變數值複製一份下來。不算是個很漂亮的解法,但總算是個方法。
目前還沒實作完成,但可以嘗試看看的目標還有:
Binding->of_package
Binding->of_sub
Binding->local
可以想見的是,這些都有些難度,也不見得會很有用。完全是屬於實驗或研究性質的作品。不過接著便可以在 Rubyish 中直接使用 Binding.pm 了。
這個作品的初版已經上傳到 CPAN: https://metacpan.org/pod/Binding , 版本控制則是放在 github 上:https://github.com/gugod/binding/tree/master,敬請賜教。