在将参数传递给 sub MAIN 之前更改参数的处理方式
Alter how arguments are processed before they're passed to sub MAIN
鉴于 documentation and the comments on an ,根据要求,我制作了一个最小的可重现示例,演示了这两个语句之间的区别:
my %*SUB-MAIN-OPTS = :named-anywhere;
PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
给定一个只有这个的脚本文件:
#!/usr/bin/env raku
use MyApp::Tools::CLI;
和 MyApp/Tools 中名为 CLI.pm6 的模块文件:
#PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
my %*SUB-MAIN-OPTS = :named-anywhere;
proto MAIN(|) is export {*}
multi MAIN( 'add', :h( :$hostnames ) ) {
for @$hostnames -> $host {
say $host;
}
}
multi MAIN( 'remove', *@hostnames ) {
for @hostnames -> $host {
say $host;
}
}
命令行中的以下调用不会产生可识别的子例程,但会显示用法:
mre.raku add -h=localhost -h=test1
将 my %*SUB-MAIN-OPTS = :named-anywhere;
切换为 PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
将按预期打印两行提供的两个主机名。
然而,如果这是在单个文件中完成的,则两者的工作方式相同:
#!/usr/bin/env raku
#PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
my %*SUB-MAIN-OPTS = :named-anywhere;
proto MAIN(|) is export {*}
multi MAIN( 'add', :h( :$hostnames )) {
for @$hostnames -> $host {
say $host;
}
}
multi MAIN( 'remove', *@hostnames ) {
for @hostnames -> $host {
say $host;
}
}
我觉得这很难理解。
重现此内容时,请注意必须如何调用每个命令。
mre.raku remove localhost test1
mre.raku add -h=localhost -h=test1
因此,当在带有 my %*SUB-MAIN-OPTS = :named-anywhere;
的单独文件中使用时,无法识别命名数组引用。虽然 PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
始终有效。对于一个 slurpy 数组,两者在两种情况下的工作方式相同。
May a cuppa给未来SO读者思考事物的意义带来启示。[1]
Liz 的相关回答
我认为 询问类似问题的 SO 可能是一本很好的读物,可以很好地解释为什么 my
(就像较小的 our
)在模块的主线不起作用,或者至少确认核心开发人员知道它。
通过将 my
放在 RUN-MAIN
.
中来解释如何 可以 使用 my
为什么 slurpy 数组默认工作但没有在任何地方命名?
S06(子程序概要)的 Declaring a MAIN subroutine 节[2][是关于事情为何如此的丰富资源=105=].
关键摘录:
As usual, switches are assumed to be first, and everything after the first non-switch, or any switches after a --, are treated as positionals or go into the slurpy array (even if they look like switches).
所以看起来这就是默认行为的来源,其中命名不能去任何地方;似乎@Larry[3] 声称“通常的”shell 约定如所描述的那样,并含蓄地争辩说这应该规定默认行为是原样。
自从 Raku 正式发布以来,RFC: Allow subcommands in MAIN 使我们走上了通往今天 :named-anywhere
选项的道路。 RFC 提出了一个非常强大的 1-2 打击——一个无懈可击的两行黑客的 prose/data 论点,迅速导致粗略的共识,工作代码 PR 与此提交消息:
Allow --named-switches anywhere in command line.
Raku was GNU-like in that it has '--double-dashes' and that it stops interpreting named parameters when it encounters '--', but unlike GNU-like parsing, it also stopped interpreting named parameters when encountering any positional argument. This patch makes it a bit more GNU-like by allowing named arguments after a positional, to prepare for allowing subcommands.
> 改变参数在传递给子 MAIN 之前的处理方式
在S06的上面链接部分@Larry
还写了:
Ordinarily a top-level Raku "script" just evaluates its anonymous mainline code and exits. During the mainline code, the program's arguments are available in raw form from the @*ARGS
array.
这里的重点是您可以在 @*ARGS
传递给 MAIN
之前对其进行预处理。
继续:
At the end of the mainline code, however, a MAIN
subroutine will be called with whatever command-line arguments remain in @*ARGS
.
请注意,正如 Liz 所解释的,Raku 现在有一个 RUN-MAIN
例程,该例程在调用 MAIN
.
之前被调用
然后是标准参数处理(可以通过使用标准选项进行更改,目前只有 :named-anywhere
一个,或者用户空间模块,例如 SuperMAIN
添加了各种其他功能)。
最后 @Larry
注意到:
Other [command line parsing] policies may easily be introduced by calling MAIN
explicitly. For instance, you can parse your arguments with a grammar and pass the resulting Match
object as a Capture
to MAIN
.
文档修复?
昨天你写了。
我现在看到我们(集体)了解编码问题。那么为什么文档是这样的呢?我认为您的 SO 和之前的 SO 的组合提供了足够的轶事数据来支持至少考虑 filing a doc issue to the contrary。然后 Liz 在其中一个 SO 中再次暗示修复可能即将到来,至少 our
s。 SO 本身可以说是 doc。所以也许等待更好?我会下注,让你决定。如果您决定提交文档问题,至少您现在有几个 SO 可以引用。
脚注
[1] 我想明确一点,如果有人认为发布此 SO 有任何错误,那么他们是对的,错完全是我的。我向@acw 提到我已经进行了搜索,因此他们可以相当合理地得出结论,他们也没有必要进行搜索。所以,mea culpa,包括坏咖啡启发的双关语。 (糟糕的双关语,不错的咖啡。)
[2] Imo 这些古老的历史推测设计文档在您了解 Raku 时值得一读再读,尽管它们是部分已过时。
[3] @Larry
出现在 Raku 文化中,作为 Larry Wall 的乐趣和方便 shorthand等人,由 Larry 领导的 Raku 语言团队
问题是脚本和模块中的变量不同。
当然他们有相同的名字,但这并不意味着什么。
my \A = anon class Foo {}
my \B = anon class Foo {}
A ~~ B; # False
B ~~ A; # False
A === B; # False
这两个 类 同名,但却是不同的实体。
如果您查看其他内置动态变量的代码,您会看到如下内容:
Rakudo::Internals.REGISTER-DYNAMIC: '$*EXECUTABLE-NAME', {
PROCESS::<$EXECUTABLE-NAME> := $*EXECUTABLE.basename;
}
这确保变量安装到正确的位置,以便它适用于每个编译单元。
如果您查找 %*SUB-MAIN-OPTS
,您唯一找到的是 line:
my %sub-main-opts := %*SUB-MAIN-OPTS // {};
在主编译单元中查找变量。如果找不到它,它会创建并使用一个空哈希。
因此,当您尝试在主编译单元以外的范围内执行此操作时,它不在该行可以找到的地方。
要测试添加是否可以解决问题,您可以将其添加到主编译单元的顶部。 (加载模块的脚本。)
BEGIN Rakudo::Internals.REGISTER-DYNAMIC: '%*SUB-MAIN-OPTS', {
PROCESS::<%SUB-MAIN-OPTS> := {}
}
然后在模块中,这样写:
%*SUB-MAIN-OPTS = :named-anywhere;
或者更好的是:
%*SUB-MAIN-OPTS<named-anywhere> = True;
尝试过后,它似乎工作得很好。
事情是这样的 used to be there。
它被删除是因为它会减慢每个 Raku 程序的速度。
虽然我认为它导致的任何减速仍然是一个问题,因为仍然存在的行必须查看是否有该名称的动态变量。
(给出的理由更多,坦率地说,我不同意所有这些。)
鉴于 documentation and the comments on an
my %*SUB-MAIN-OPTS = :named-anywhere;
PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
给定一个只有这个的脚本文件:
#!/usr/bin/env raku
use MyApp::Tools::CLI;
和 MyApp/Tools 中名为 CLI.pm6 的模块文件:
#PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
my %*SUB-MAIN-OPTS = :named-anywhere;
proto MAIN(|) is export {*}
multi MAIN( 'add', :h( :$hostnames ) ) {
for @$hostnames -> $host {
say $host;
}
}
multi MAIN( 'remove', *@hostnames ) {
for @hostnames -> $host {
say $host;
}
}
命令行中的以下调用不会产生可识别的子例程,但会显示用法:
mre.raku add -h=localhost -h=test1
将 my %*SUB-MAIN-OPTS = :named-anywhere;
切换为 PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
将按预期打印两行提供的两个主机名。
然而,如果这是在单个文件中完成的,则两者的工作方式相同:
#!/usr/bin/env raku
#PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
my %*SUB-MAIN-OPTS = :named-anywhere;
proto MAIN(|) is export {*}
multi MAIN( 'add', :h( :$hostnames )) {
for @$hostnames -> $host {
say $host;
}
}
multi MAIN( 'remove', *@hostnames ) {
for @hostnames -> $host {
say $host;
}
}
我觉得这很难理解。 重现此内容时,请注意必须如何调用每个命令。
mre.raku remove localhost test1
mre.raku add -h=localhost -h=test1
因此,当在带有 my %*SUB-MAIN-OPTS = :named-anywhere;
的单独文件中使用时,无法识别命名数组引用。虽然 PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
始终有效。对于一个 slurpy 数组,两者在两种情况下的工作方式相同。
May a cuppa给未来SO读者思考事物的意义带来启示。[1]
Liz 的相关回答
我认为 my
(就像较小的 our
)在模块的主线不起作用,或者至少确认核心开发人员知道它。
my
放在 RUN-MAIN
.
my
为什么 slurpy 数组默认工作但没有在任何地方命名?
S06(子程序概要)的 Declaring a MAIN subroutine 节[2][是关于事情为何如此的丰富资源=105=].
关键摘录:
As usual, switches are assumed to be first, and everything after the first non-switch, or any switches after a --, are treated as positionals or go into the slurpy array (even if they look like switches).
所以看起来这就是默认行为的来源,其中命名不能去任何地方;似乎@Larry[3] 声称“通常的”shell 约定如所描述的那样,并含蓄地争辩说这应该规定默认行为是原样。
自从 Raku 正式发布以来,RFC: Allow subcommands in MAIN 使我们走上了通往今天 :named-anywhere
选项的道路。 RFC 提出了一个非常强大的 1-2 打击——一个无懈可击的两行黑客的 prose/data 论点,迅速导致粗略的共识,工作代码 PR 与此提交消息:
Allow --named-switches anywhere in command line.
Raku was GNU-like in that it has '--double-dashes' and that it stops interpreting named parameters when it encounters '--', but unlike GNU-like parsing, it also stopped interpreting named parameters when encountering any positional argument. This patch makes it a bit more GNU-like by allowing named arguments after a positional, to prepare for allowing subcommands.
> 改变参数在传递给子 MAIN 之前的处理方式
在S06的上面链接部分@Larry
还写了:
Ordinarily a top-level Raku "script" just evaluates its anonymous mainline code and exits. During the mainline code, the program's arguments are available in raw form from the
@*ARGS
array.
这里的重点是您可以在 @*ARGS
传递给 MAIN
之前对其进行预处理。
继续:
At the end of the mainline code, however, a
MAIN
subroutine will be called with whatever command-line arguments remain in@*ARGS
.
请注意,正如 Liz 所解释的,Raku 现在有一个 RUN-MAIN
例程,该例程在调用 MAIN
.
然后是标准参数处理(可以通过使用标准选项进行更改,目前只有 :named-anywhere
一个,或者用户空间模块,例如 SuperMAIN
添加了各种其他功能)。
最后 @Larry
注意到:
Other [command line parsing] policies may easily be introduced by calling
MAIN
explicitly. For instance, you can parse your arguments with a grammar and pass the resultingMatch
object as aCapture
toMAIN
.
文档修复?
昨天你写了
我现在看到我们(集体)了解编码问题。那么为什么文档是这样的呢?我认为您的 SO 和之前的 SO 的组合提供了足够的轶事数据来支持至少考虑 filing a doc issue to the contrary。然后 Liz 在其中一个 SO 中再次暗示修复可能即将到来,至少 our
s。 SO 本身可以说是 doc。所以也许等待更好?我会下注,让你决定。如果您决定提交文档问题,至少您现在有几个 SO 可以引用。
脚注
[1] 我想明确一点,如果有人认为发布此 SO 有任何错误,那么他们是对的,错完全是我的。我向@acw 提到我已经进行了搜索,因此他们可以相当合理地得出结论,他们也没有必要进行搜索。所以,mea culpa,包括坏咖啡启发的双关语。 (糟糕的双关语,不错的咖啡。)
[2] Imo 这些古老的历史推测设计文档在您了解 Raku 时值得一读再读,尽管它们是部分已过时。
[3] @Larry
出现在 Raku 文化中,作为 Larry Wall 的乐趣和方便 shorthand等人,由 Larry 领导的 Raku 语言团队
问题是脚本和模块中的变量不同。
当然他们有相同的名字,但这并不意味着什么。
my \A = anon class Foo {}
my \B = anon class Foo {}
A ~~ B; # False
B ~~ A; # False
A === B; # False
这两个 类 同名,但却是不同的实体。
如果您查看其他内置动态变量的代码,您会看到如下内容:
Rakudo::Internals.REGISTER-DYNAMIC: '$*EXECUTABLE-NAME', {
PROCESS::<$EXECUTABLE-NAME> := $*EXECUTABLE.basename;
}
这确保变量安装到正确的位置,以便它适用于每个编译单元。
如果您查找 %*SUB-MAIN-OPTS
,您唯一找到的是 line:
my %sub-main-opts := %*SUB-MAIN-OPTS // {};
在主编译单元中查找变量。如果找不到它,它会创建并使用一个空哈希。
因此,当您尝试在主编译单元以外的范围内执行此操作时,它不在该行可以找到的地方。
要测试添加是否可以解决问题,您可以将其添加到主编译单元的顶部。 (加载模块的脚本。)
BEGIN Rakudo::Internals.REGISTER-DYNAMIC: '%*SUB-MAIN-OPTS', {
PROCESS::<%SUB-MAIN-OPTS> := {}
}
然后在模块中,这样写:
%*SUB-MAIN-OPTS = :named-anywhere;
或者更好的是:
%*SUB-MAIN-OPTS<named-anywhere> = True;
尝试过后,它似乎工作得很好。
事情是这样的 used to be there。
它被删除是因为它会减慢每个 Raku 程序的速度。
虽然我认为它导致的任何减速仍然是一个问题,因为仍然存在的行必须查看是否有该名称的动态变量。
(给出的理由更多,坦率地说,我不同意所有这些。)