我对缩短代码的追求进展顺利。有一件事还是挺啰嗦的,那就是对象创建。为了让管道充满生命,我们需要 Proc::Async
的实例。
my $find = Proc::Async.new: </usr/bin/find /tmp>;
正如我前面所展示的操作符是去样板化。我们将需要那个目前要去 .new
的参数列表。如果能把其他的东西减少到只有两个字母,那就更好了。让我们定义一个子例程前缀来做到这一点。
sub prefix:<px>(List:D \l) is looser(&infix:<,>) { say ‚Proc::Async.new: <‘, l.Str, ‚>‘; };
px</usr/bin/find /tmp>; # OUTPUT Proc::Async.new: </usr/bin/find /tmp>
px ‚/usr/bin/find‘, ‚/tmp‘; # OUTPUT Proc::Async.new: </usr/bin/find /tmp>
通过使用 is looser(&infix:<,>)
,我们告诉编译器创建一个 List,然后用一种有趣的语法调用名为 px
的子例程。通过这样做,我们模仿了用于实现 qx
的引号结构,并且能够留下一个空格。不过有一个问题。
px«/usr/bin/find /tmp»;
# OUTPUT:
# ===SORRY!=== Error while compiling /home/dex/projects /raku/lib/raku-shell-piping/EVAL_0
# Two terms in a row
# at /home/dex/projects/raku/lib/raku-shell-piping/EVAL_0:1
# ------> px«/usr/⏏bin/find /tmp;
# expecting any of:
# infix
# infix stopper
# statement end
# statement modifier
# statement modifier loop
这里的 grammar 似乎很混乱。既然有一种替代方法可以用内插的方式列出引号,我将继续进行错误修复。
我通过 R#3799 的唠叨取得了成果,并提供了一个解决这个问题的办法。
class C {
has $.state is rw;
}
my \px = C.new;
multi postcircumfix:<{ }>(C:D, $s, Bool :$adverb = False) {
Proc::Async.new: $s;
}
multi postcircumfix:<{ }>(C:D, @a, Bool :$adverb = False) {
Proc::Async.new: @a;
}
multi infix:<|»>(Proc::Async:D $l, Proc::Async:D $r, :$different-adverb = "non-given") {
dd $l;
dd $r;
}
px<ls>;
px«ls»;
my $a = 42;
px<ls 1 2 3 $a>;
px«ls $a»;
px«ls $a»:adverb;
px{'foo' ~ 41.succ};
px«ls $a»:adverb |» (px«sort»:adverb) :different-adverb(42);
这提供了我所需要的所有模拟 qx
的各种形式。C 的实例被用作编译器的占位符,它的状态可以是全局的,适用于所有对 postcircumfix:<{ }>(C:D,...)
的调用。这在以后可能会很方便。
Shell::Piping 到目前为止已经引起了 3 个 bug 报告。我确实觉得自己是第一个踩到这个沼泽地的人。如果我没能成功,请抱着我的朋友们删除我的浏览器历史记录。