В любом случае, чтобы определить, запускается ли perl-скрипт через do?

#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 скрипт был выполнен напрямую.