主子程序
MAIN subroutine
场景
假设您有一个模块 X
,用户可以通过命令行界面使用其功能。这样的模块本身并没有做太多事情,但它允许其他人创建类似插件的模块,他们可以连接到模块 X
。理想情况下,插件可以通过 X
的 CLI 使用。
因此我的问题是:
你需要做什么才能连接任何功能
插件可能会提供给 X
的 CLI?
这意味着插件需要提供一些结构来描述命令、需要调用的内容以及插件的使用信息。因此,当您使用 运行 X
的 CLI 时,插件的命令和帮助消息会显示在常规 X
的 CLI 的帮助消息中。
例子
main.p6
:
use Hello;
use Print;
multi MAIN('goodbye') {
put 'goodbye'
}
lib/Hello.pm6
:
unit module Hello;
our %command = %(
command => 'hello',
routine => sub { return "Hello" },
help => 'print hello.'
);
lib/Print.pm6
:
unit module Print;
our %command = %(
command => 'print',
routine => sub { .print for 1..10 },
help => 'print numbers 1 through 10.'
);
程序main.p6
是这个场景的简化版本。我想整合 Hello.pm6
和 Print.pm6
提供的信息
他们各自的 %command
变量到 main.p6
.
中的两个新的 MAIN
子
这可能吗?如果是这样,我将如何实现它?
这看起来有点特定于 Whosebug 问题,但无论如何我都会试一试。这里有几个问题。第一个是这样注册命令,以便 MAIN
可以发出一条消息说 "this does that",第二个是实际执行命令。如果两者都可以在编译时知道,这可能可以解决。但是让我们看看实际的代码是如何进行的。我只做第一部分,剩下的留作练习。
第一件事是 %command
需要以某种方式导出。你不能像现在这样去做。首先,因为它没有明确导出;如果是这样,你最终会在外部范围内得到几个同名的符号。所以我们需要将其更改为 class,以便实际符号对 class 是词法的,并且不会污染外部范围。
unit class Hello;
has %.command = %(
command => 'hello',
routine => sub { return "Hello" },
help => 'print hello.'
);
(Print
也一样)
只要我们有了那个,剩下的就不是那么难了,只是我们必须使用内省来知道那里到底是什么,作为一个小技巧:
use Hello;
use Print;
my @packages= MY::.keys.grep( /^^<upper> <lower>/ );
my @commands = do for @packages -> $p {
my $foo = ::($p).new();
$foo.command()<command>
};
multi MAIN( $command where * eq any(@commands) ) {
say "We're doing $command";
}
我们检查符号 table 寻找以大写字母开头,后跟其他 non-capital 字母的包。碰巧唯一的包是我们感兴趣的包,但是当然,如果您想将其用作插件机制,您应该只使用它们独有的任何模式。
然后我们创建这些新包的实例,并调用 command auto-generated 方法来获取命令的名称。这正是我们用来检查我们是否在 MAIN
子例程中执行正确命令的方法,通过使用 where
签名来检查我们正在使用的字符串是否实际上在已知列表中命令。
由于函数和其他内容也可从 @packages
获得,实际调用它们(或提供附加消息或其他)留作练习。
更新:您可能想查看 作为模块中签名的替代机制。
场景
假设您有一个模块 X
,用户可以通过命令行界面使用其功能。这样的模块本身并没有做太多事情,但它允许其他人创建类似插件的模块,他们可以连接到模块 X
。理想情况下,插件可以通过 X
的 CLI 使用。
因此我的问题是:
你需要做什么才能连接任何功能
插件可能会提供给 X
的 CLI?
这意味着插件需要提供一些结构来描述命令、需要调用的内容以及插件的使用信息。因此,当您使用 运行 X
的 CLI 时,插件的命令和帮助消息会显示在常规 X
的 CLI 的帮助消息中。
例子
main.p6
:
use Hello;
use Print;
multi MAIN('goodbye') {
put 'goodbye'
}
lib/Hello.pm6
:
unit module Hello;
our %command = %(
command => 'hello',
routine => sub { return "Hello" },
help => 'print hello.'
);
lib/Print.pm6
:
unit module Print;
our %command = %(
command => 'print',
routine => sub { .print for 1..10 },
help => 'print numbers 1 through 10.'
);
程序main.p6
是这个场景的简化版本。我想整合 Hello.pm6
和 Print.pm6
提供的信息
他们各自的 %command
变量到 main.p6
.
MAIN
子
这可能吗?如果是这样,我将如何实现它?
这看起来有点特定于 Whosebug 问题,但无论如何我都会试一试。这里有几个问题。第一个是这样注册命令,以便 MAIN
可以发出一条消息说 "this does that",第二个是实际执行命令。如果两者都可以在编译时知道,这可能可以解决。但是让我们看看实际的代码是如何进行的。我只做第一部分,剩下的留作练习。
第一件事是 %command
需要以某种方式导出。你不能像现在这样去做。首先,因为它没有明确导出;如果是这样,你最终会在外部范围内得到几个同名的符号。所以我们需要将其更改为 class,以便实际符号对 class 是词法的,并且不会污染外部范围。
unit class Hello;
has %.command = %(
command => 'hello',
routine => sub { return "Hello" },
help => 'print hello.'
);
(Print
也一样)
只要我们有了那个,剩下的就不是那么难了,只是我们必须使用内省来知道那里到底是什么,作为一个小技巧:
use Hello;
use Print;
my @packages= MY::.keys.grep( /^^<upper> <lower>/ );
my @commands = do for @packages -> $p {
my $foo = ::($p).new();
$foo.command()<command>
};
multi MAIN( $command where * eq any(@commands) ) {
say "We're doing $command";
}
我们检查符号 table 寻找以大写字母开头,后跟其他 non-capital 字母的包。碰巧唯一的包是我们感兴趣的包,但是当然,如果您想将其用作插件机制,您应该只使用它们独有的任何模式。
然后我们创建这些新包的实例,并调用 command auto-generated 方法来获取命令的名称。这正是我们用来检查我们是否在 MAIN
子例程中执行正确命令的方法,通过使用 where
签名来检查我们正在使用的字符串是否实际上在已知列表中命令。
由于函数和其他内容也可从 @packages
获得,实际调用它们(或提供附加消息或其他)留作练习。
更新:您可能想查看