繁体   English   中英

改变 arguments 在传递给子 MAIN 之前的处理方式

[英]Alter how arguments are processed before they're passed to sub MAIN

鉴于文档和对较早问题的评论,根据要求,我制作了一个最小的可重现示例,展示了这两个语句之间的区别:

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 数组,两者在两种情况下的工作方式相同。

问题是它在脚本和模块中都不是同一个变量。

当然他们有相同的名字,但这并不意味着什么。

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 ,你唯一能找到的是这一

    my %sub-main-opts   := %*SUB-MAIN-OPTS // {};

这会在主编译单元中查找变量。 如果没有找到它,它会创建并使用一个空的 Hash。

因此,当您尝试在主编译单元以外的 scope 中执行此操作时,它不在该行可以找到的位置。


要测试添加是否可以解决问题,您可以将其添加到主编译单元的顶部。 (加载模块的脚本。)

BEGIN Rakudo::Internals.REGISTER-DYNAMIC: '%*SUB-MAIN-OPTS', {
    PROCESS::<%SUB-MAIN-OPTS> := {}
}

然后在模块中,这样写:

%*SUB-MAIN-OPTS = :named-anywhere;

或者更好的是:

%*SUB-MAIN-OPTS<named-anywhere> = True;

在尝试了这个之后,它似乎工作得很好。


问题是, 那里曾经有过类似的东西。

考虑到它会减慢每个 Raku 程序的速度,它被删除了。

尽管我认为它导致的任何减速仍然是一个问题,因为仍然存在的行必须查看是否存在该名称的动态变量。
(给出的理由更多,坦率地说,我不同意所有这些理由。)

愿一杯茶给未来思考事物意义的SO读者带来启迪。 [1]

丽兹的相关回答

我认为Liz 对 SO 问一个类似问题的回答可能是一个很好的读物,可以很好地解释为什么模块主线中的my (就像一个较小our )不起作用,或者至少确认核心开发人员知道它。

她后来对另一个 SO 的回答解释了如何通过将my放在RUN-MAIN使用它。

为什么 slurpy 数组默认工作但没有在任何地方命名?

关于事情为何如此的一个丰富资源是声明 S06 的 MAIN 子程序部分(子程序概要) [2]

关键摘录:

像往常一样,开关被假定为第一个,并且第一个非开关之后的所有内容,或 - 之后的任何开关都被视为位置或 go 进入 slurpy 阵列(即使它们看起来像开关)。

所以看起来这是默认行为的来源,其中命名不能go 来自任何地方; 似乎@Larry [3]声称“通常的” shell 约定如所描述,并暗示这应该表明默认行为是原样的。

自从 Raku 正式发布以来, RFC: Allow subcommands in MAIN让我们走上了通往今天的:named-anywhere选项的道路。 RFC 提出了一个非常强大的 1-2 拳——一个无可挑剔的两行黑客散文/数据论点,很快就导致了粗略的共识,并带有一个带有此提交消息的工作代码 PR:

允许 --named-switches 在命令行中的任何位置。

Raku 类似于 GNU,因为它具有“--double-dashes”,并且在遇到“--”时停止解释命名参数,但与类似 GNU 的解析不同,它在遇到任何位置参数时也停止解释命名参数。 此补丁通过允许在位置后命名为 arguments 以准备允许子命令,使其更像 GNU。

> 改变 arguments 在传递给子 MAIN 之前的处理方式

在 S06 的上述链接部分中, @Larry还写道:

通常,顶级 Raku“脚本”只是评估其匿名主线代码并退出。 在主线代码中,程序的 arguments 以原始形式从@*ARGS数组中获得。

这里的重点是您可以在将@*ARGS传递给MAIN之前对其进行预处理。

继续:

然而,在主线代码的末尾,将使用@*ARGS中保留的任何命令行 arguments 调用MAIN子例程。

请注意,正如 Liz 所解释的,Raku 现在有一个在调用MAIN之前调用的RUN-MAIN例程。

然后是标准参数处理(可通过使用标准选项进行更改,其中目前只有:named-anywhere一个,或诸如SuperMAIN类的用户区模块,它添加了各种其他功能)。

最后@Larry指出:

通过显式调用MAIN可以轻松引入其他 [命令行解析] 策略。 例如,您可以使用语法解析您的 arguments 并将生成的Match object 作为Capture传递给MAIN

文档修复?

昨天您写了一条评论,建议进行文档修复

我现在看到我们(集体)知道编码问题。 那么为什么文档是这样的呢? 我认为您的 SO 和以前的 SO 的组合提供了足够的轶事来支持至少考虑提出相反的文档问题 再一次,Liz 在其中一个 SO 中暗示可能会出现修复,至少对于our的 s。 SO 本身可以说是 doc。 所以也许等待更好? 我会踢球,让你决定。 如果您决定提交文档问题,至少您现在有几个 SO 要引用。

脚注

[1]我想明确一点,如果有人认为发布此 SO 有任何错误,那么他们是对的,错误完全是我的。 我向@acw 提到我已经进行了搜索,因此他们可以相当合理地得出结论,他们也没有必要进行搜索。 所以,mea culpa,包括糟糕的咖啡启发双关语。 (糟糕的双关语,不错的咖啡。)

[2]当您了解 Raku 时,Imo 这些古老的历史推测性设计文档值得一读再读,尽管它们在某些方面已经过时。

[3] @Larry出现在 Raku 文化中,作为 Larry Wall 等人(由 Larry 领导的 Raku 语言团队)的一种有趣且方便的简写。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM