#perl
#perl
Вопрос:
У меня есть небольшой файл конфигурации скрипта, который загружается из основного скрипта.
#main.pl
package MYPACKAGE;
our $isMaster=1;
package main;
my config=do "./config.pl"
#config.pl
my $runViaDoFlag;
$runViaDoFlag=$0=~/main.pl/; #Test if main.pl is the executing script
$runViaDoFlag=defined $MYPACKAGE::isMaster; #Test custom package variable
#Is there a 'built-in' way to do this?
die "Need to run from main script! " unless $runViaDoFlag;
{
options={
option1=>"some value",
option2=>"some value",
},
mySub=>sub {
# do interesting things here
}
}
В более сложном конфигурационном файле может быть не так очевидно, что config.pl скрипт предназначен для выполнения только с помощью do
. Поэтому я хочу включить a die
с основными инструкциями по использованию.
Решения:
- проверьте
$0
имя основного скрипта - иметь пользовательскую переменную пакета, определенную в основном скрипте и проверяемую скриптом конфигурации
- просто добавьте комментарий в конфигурацию, инструктирующий пользователя, как его использовать.
Это работает, однако есть ли какой-то способ узнать, выполняется ли скрипт через do через встроенную переменную / subs?
Комментарии:
1. Почему вы не хотите использовать
require
? Или, почему вы хотите исключитьrequire
? Единственное отличие заключается в том, что этоrequire
останавливает вас, если в коде есть проблема и нет окончательного истинного значения.
Ответ №1:
Я бы предложил изменить дизайн: иметь эту конфигурацию в обычном модуле, в котором вы можете затем проверить, было ли оно загружено (из) main::
пространства имен или нет. Тогда нет необходимости в какой-либо акробатике с управляющими переменными и т.д.
Один из способов сделать это
use warnings;
use strict;
use feature 'say';
use FindBin qw($RealBin);
use lib $RealBin; # so to be able to 'use' from current directory
use ConfigPackage qw(load_config);
my $config = load_config();
# ...
и ConfigPackage.pm
(в том же каталоге)
package ConfigPackage;
use warnings;
use strict;
use feature 'say';
use Carp;
use Exporter qw(); # want our own import
our @EXPORT_OK = qw(load_config);
sub import {
#say "Loaded by: ", (caller)[0];
croak "Must only be loaded from 'main::'"
if not ( (caller)[0] eq 'main' );
# Now switch to Exporter::import to export symbols as needed
goto amp;Exporter::import;
}
sub load_config {
# ...
return 'Some config-related data structure';
}
1;
(Обратите внимание, что это использование goto нормально.)
Конечно, это всего лишь набросок; корректируйте, развивайте дальше и вносите изменения по мере необходимости. Если это загружается из пакета, отличного от main::
, и поэтому происходит сбой, то это происходит на этапе компиляции, поскольку именно тогда вызывается import . Я бы счел это хорошей вещью.
Если этот конфигурационный код также должен быть в состоянии выполняться, как может указывать вопрос, тогда создайте отдельный исполняемый файл, который загружает этот модуль и запускает то, что нужно запустить.
Что касается вопроса, как указано, заголовок и (кажущийся) запрос вопроса немного отличаются, но оба могут быть обработаны с помощью выражения вызывающего абонента. Однако это не будет чистым небольшим «встроенным» вызовом.
Суть в том, чтобы делать так, как предназначено для использования, заключается в том, что
do
«./stat.pl
во многом похожеeval `cat stat.pl`;
за исключением этого…
(Это stat.pl
введено ранее в документах, просто для обозначения того, что do
вызывается в файле.)
Тогда caller(0)
у вас будут четкие подсказки (см. Документы). Он возвращает
my ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash) = caller($i);
В запрошенном вызове, do './config.pl'
, помимо main
(package) и правильного имени файла, caller(0)
in config.pl
также возвращает:
(eval)
для$subroutine
./config.pl
для$evaltext
1
для$is_require
В целом это дает достаточно, чтобы решить, был ли вызов выполнен по мере необходимости.
Однако я бы не рекомендовал такой сложный анализ вместо простого использования пакета, что также несравненно более гибко.
Комментарии:
1. Спасибо за подробности!
caller
Я думаю, это то, что мне нужно для моего простого скрипта. Оказываетсяcaller
, возвращает пустой массив при вызове на верхнем уровне. Итак, простое тестирование @{[caller]}==0 указывает, что мой config.pl скрипт был выполнен напрямую.