モジュールDevel::Declareには、Perlの構文を比較的安全に拡張するためのツールが含まれています。
Devel :: Declareを使用すると、with
トークンにフックが作成され、その単語に到達するとパーサが停止します。そこから、あなたはパーサーを制御でき、{
シンボルに達するまで先読みすることができます。その時点で、作業する必要があるものがあるので、有効なPerlに書き換えて、パーサーに渡します。
ファイルWith.pm
中:
package With;
use warnings;
use strict;
use Devel::Declare;
sub import {
my $caller = caller;
Devel::Declare->setup_for (
$caller => {with => {const => \&parser}}
);
no strict 'refs';
*{$caller.'::with'} = sub ($&) {
$_[1]() for $_[0];
$_[0]
}
}
our $prefix = '';
sub get {substr Devel::Declare::get_linestr, length $prefix}
sub set { Devel::Declare::set_linestr $prefix . $_[0]}
sub parser {
local $prefix = substr get, 0, length($_[0]) + $_[1];
my $with = strip_with();
strip_space();
set "scalar($with), sub " . get;
}
sub strip_space {
my $skip = Devel::Declare::toke_skipspace length $prefix;
set substr get, $skip;
}
sub strip_with {
strip_space;
my $with;
until (get =~ /^\{/) {
(my $line = get) =~ s/^([^{]+)//;
$with .= $1;
set $line;
strip_space;
}
$with =~ s/\s+/ /g;
$with
}
し、それを使用する:
window add: Box(Button(1) Button(2) Button(3) Button(4))
を完全に異なるアプローチをスキップするようになります:印刷し
use With;
sub Window::add {say "window add: ", $_[1]->str}
sub Window::new {bless [] => 'Window'}
sub Box::new {bless [] => 'Box'}
sub Box::add {push @{$_[0]}, @_[1..$#_]}
sub Box::str {"Box(@{$_[0]})"}
sub Button::new {"Button($_[1])"}
with Window->new {
$_->add(with Box->new {
for my $num (1 .. 4) {
$_->add(Button->new($num))
}
})
};
with
完全にキーワードとコンストラクタサブルーチンを生成するためのルーチンを記述します。
BEGIN {
for my $name (qw(VBox)) { # and any others you want
no strict 'refs';
*$name = sub (&@) {
use strict;
my $code = shift;
my $with = "Gtk2::$name"->new(@_);
$code->() for $with;
$with
}
}
}
、その後、あなたのコードは
for (Gtk2::Window->new('toplevel')) {
$_->set_title('Test Application');
$_->add(VBox {
my $box = $_;
$box->add(Gtk2::Button->new("Button $_")) for (1..4);
});
$_->show_all;
}