Нет ничего простого, что позволило бы как-то «зарегистрировать» пользовательские подпрограммы с помощью интерпретатора или чего-то подобного, чтобы вы могли запускать их как встроенные в любой части программы.
Один из способов получить запрашиваемое вами поведение - напрямую записывать в таблицы символов загруженных модулей. Это должно быть сделано после загрузки модулей и после определения подпрограмм, которые вы добавляете в эти модули. Я использую блок INIT
в приведенном ниже примере.
Обратите внимание, что в этом есть ряд недостатков, и в целом сама идея подозрительна для меня, сродни расширению интерпретатора. В целом, я бы предпочел написать модуль со всеми такими подпрограммами и использовать стандартные подходы для хорошего проектирования программы, чтобы загрузить этот модуль туда, где ему нужно go.
Сказав это, вот основа c demo
use warnings;
use strict;
use feature 'say';
use Data::Dump qw(dd pp);
use TestMod qw(modsub);
sub t_main { say "In t_main(), from ", __PACKAGE__ }
modsub("Calling from main::");
INIT {
no strict 'refs';
foreach my $pkg (qw(TestMod)) {
*{ $pkg . '::' . 'sub_from_main' } = \&t_main;
}
dd \%TestMod::;
}
Копирует ссылку на t_main
из текущего пакета (main::
) в таблицу символов $pkg
под именем sub_from_main
, которую затем можно использовать с этим именем в этом пакете.
Для простоты имя модуля жестко закодировано, но вы можете использовать вместо него %INC
и любые другие имеющиеся у вас ключи, чтобы выяснить, к каким загруженным хранилищам модулей нужно добавить.
Модуль благодетеля (или жертвы?) TestMod.pm
package TestMod;
use warnings;
use strict;
use feature 'say';
use Exporter qw(import);
our @EXPORT_OK = qw(modsub);
sub modsub {
say "In module ", __PACKAGE__, ", args: @_";
say "Call a sub pushed into this namespace: ";
sub_from_main();
}
1;
Имя добавленного подпрограммы может быть передано в модули по мере их загрузки, а не жестко закодировано, в этом случае вам нужно написать их import sub вместо заимствования Exporter
.
Существуют также модули, позволяющие добавлять ключевые слова, но это не легкая альтернатива.