實做 Binding.pm

作者:   發佈於: ,更新於:

下午連續喝了三杯之前在菡萏買的 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 的例子裡,變數名稱也是個變數,因此才會需要通用的解法。

實際的做法是利用 PadWalkerpeek_my 加上 Data::Dumppp 函式將上層的變數值複製一份下來。不算是個很漂亮的解法,但總算是個方法。

目前還沒實作完成,但可以嘗試看看的目標還有:

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,敬請賜教。