【问题标题】:How do I access a module's symbol table dynamically at runtime in Raku?如何在 Raku 运行时动态访问模块的符号表?
【发布时间】:2021-04-11 01:56:35
【问题描述】:

我希望能够将我的脚本传递给.rakumod 文件的路径,比如<blah>/Mod.rakumod,并且能够像使用used 模块一样访问符号表作为哈希:

模块:

$ cat Mod.rakumod
unit module Mod;
sub bag        is export             { ... }
use lib <dir-containing-Mod>
use Mod;
say Mod::EXPORT::.keys

作为expected工作,返回(ALL DEFAULT)

另一方面:

use lib <dir-containing-Mod>
require Mod;
say Mod::EXPORT::.keys

失败

Could not find symbol '&EXPORT' in 'Mod'
  in block <unit> at <blah>

尽管事实上即使使用requiresay Mod::.keys 确实会看到EXPORT

use lib <dir-containing-Mod>
require Mod;
say Mod::.keys
---
(EXPORT Mod)

我需要使用require 来制作这个dynamic,因为我不知道我需要哪个模块。


其实我可以想到一件事情去做,但是绝对恶心:

  • 将我的模块名称保存到变量$mod
  • 让我的脚本编写另一个脚本using 该模块:
my $mod = <whatever>
my $cd = qq:to/END/;
use v6;
use lib qq\|\$\*CWD\|;
use $mod;

say {$mod}::EXPORT::ALL::.keys;
END

'aux.p6'.IO.spurt($cd);
  • 然后让初始脚本调用辅助脚本:
shell("raku aux.p6")

根据raiph's answer(我已接受并在此解释)有效的方法:

  • 将路径传递给模块并保存为$path
  • use lib相关目录:
my $dir = $path.IO.dirname;
use lib $dir;
  • 提取纯文件名:
my $modFile = S/(.*)\..*/$0/ with $path.IO.basename;
  • 最后,require 并从raiph's answer 中提取.WHO 技巧,稍作改编:
require ::($modFile);
say ::("{$modFile}::EXPORT::ALL").WHO.keys;

使用返回(&amp;bag)&lt;script&gt; &lt;path&gt; 运行正常。


实际上,上面的方法不太适用:use lib $dir 会说$dir 为空,因为use lib 不是动态的。

所以我现在求助于没有吸引力的解决方案

  • 将模块文件复制到临时目录./TMP
  • 已致电use './TMP';
  • 然后在完成后删除该目录。

【问题讨论】:

  • 如果你不知道你想要什么模块,那么你就不会做require Mod,而是require ::("Mod");
  • 我知道,但这不是重点:它仍然是 require,它不会让我以哈希的形式访问模块。这里我展示了一个简化版本,它不使用字符串变量来保存模块路径。

标签: module raku


【解决方案1】:

TL;DR 使用动态符号查找在运行时获取所需符号的包的符号;然后.WHO 得到它的藏匿处;然后.keys 获取该存储的符号。

例如:

use lib '.';
require Mod;
say ::Mod::EXPORT::('ALL').WHO.keys; # (&bag)

我要去做早餐了。我稍后会详细说明。

【讨论】:

  • 是的!做到了,即使@ugexe 指出了增加的复杂性。我将在对最初问题的另一个编辑中进行详细说明,但也期待您早餐后的详细说明:)
  • @grobber 我已经准备好大部分答案,但目前我正试图正确辨别foo::bar::foo::bar.WHO 之间的区别,.WHO 在运行时工作这一事实而尾随的:: 没有。具体代码package foo { our sub bar { package { } } }; say foo::bar::; # (&lt;anon&gt;) 目前让我很烦恼。那是什么&lt;anon&gt;?我想我的下一步将是去晒太阳,吃第二份早餐。 ;)
  • 实际上,我第二次编辑中的脚本毕竟不能正常工作:它只是因为我默认为use lib "." 并将模块保存在工作目录中而工作。如果我从其他地方运行它找不到模块,因为use lib 不是动态的..
  • 我不认为您当前的问题是关于 use lib 不是动态的(不确定这意味着什么);几乎可以肯定,您传递的是相对路径而不是绝对路径
  • 所以你在运行时间和编译时间方面遇到了麻烦。长话短说,您可以使用my $path = "."; CompUnit::RepositoryRegistry.use-repository(CompUnit::Repository::FileSystem.new(prefix =&gt; $path))
猜你喜欢
  • 2011-11-09
  • 1970-01-01
  • 2015-07-20
  • 2018-11-05
  • 1970-01-01
  • 1970-01-01
  • 2017-03-18
  • 2020-07-21
  • 1970-01-01
相关资源
最近更新 更多