Импортировать файл require'd, как если бы это был оператор использования - PullRequest
1 голос
/ 07 сентября 2010

У меня возникла проблема с использованием константы, определенной в файле конфигурации.Это мой пакет:

package myPackage;
require "APIconfig.pl";
APIconfig::import(APIconfig);

use constant SERVICE_URL => APIconfig::SERVICE_URL();

Конфигурация выглядит следующим образом:

package APIconfig;
use constant SERVICE_URL => 'http://api.example.org/blah';
1;

При запуске этого кода я получаю следующую ошибку:

Undefined subroutine &APIconfig::SERVICE_URL called at API.pl line 4.

Iне может использовать 'use' вместо 'require', потому что это предполагает, что файл конфигурации будет иметь имя .pm, и он называется .pl на многих серверах в нашей сети.Как я могу использовать пакет без переименования файла?

Ответы [ 3 ]

7 голосов
/ 07 сентября 2010

Существует два различия между «использовать» и «требовать».Один из них влияет на вашу текущую проблему, другой нет.К сожалению, вы работаете над тем, что не имеет никакого эффекта.

Различия:

1 / 'use' вызывает функцию import (), 'require' - нет.

2 / 'use' происходит во время компиляции, 'require' происходит во время выполнения.

Вы работаете вокруг того факта, что 'require' не вызывает import (), вызывая его явно.Это не имеет никакого эффекта, так как ваш модуль не экспортирует никаких символов и не имеет подпрограммы import ().

Вы не работаете вокруг того факта, что операторы 'use' выполняются во время выполнения.Проблема в том, что "использовать константу SERVICE_URL => APIconfig :: SERVICE_URL ();"выполняется во время компиляции, и ваш 'require' к тому времени еще не выполнялся, поэтому myPackage ничего не знает о APIconfig.

(неприятное, хакерское) решение - поместить оператор require в блок BEGIN - toзаставить его выполняться во время компиляции.Вы также захотите удалить вызов функции import (), поскольку это приводит к ошибке времени выполнения (из-за отсутствия подпрограммы).

Тестовые файлы, которые я использовал для решения этой проблемы, следующие:

$ cat APIconfig.pl 
package APIconfig;
use constant SERVICE_URL => 'http://api.example.org/blah';
1;

$ cat api.pl 
#!/usr/bin/perl

package myPackage;
BEGIN {
  require "APIconfig.pl";
}
# APIconfig::import(APIconfig);

use constant SERVICE_URL => APIconfig::SERVICE_URL();

print SERVICE_URL, "\n";
$ ./api.pl 
http://api.example.org/blah

Реальное решение - переписать APIconfig как реальный модуль.Вы намекаете, что знаете это, но экологические проблемы мешают вам использовать этот подход.Я настоятельно рекомендую попытаться обойти эти проблемы и делать все правильно.

2 голосов
/ 07 сентября 2010

Это не может быть правдой - в пакете APIconfig нет подпрограммы import.Как только вы получаете доступ к символическим именам с полным путем к пакету, вам все равно не нужно экспортировать / импортировать.

Решение состоит в том, чтобы запустить require во время компиляции, до use constant.Это работает:

package myPackage;
BEGIN {
    require "APIconfig.pl";
}

use constant SERVICE_URL => APIconfig::SERVICE_URL();
1 голос
/ 08 сентября 2010

Если это файл конфигурации, не пишите его. У меня есть целая глава в Мастеринг Perl об этом, и на CPAN есть много модулей, которые помогут вам практически в любом формате конфигурации.

Если это код, почему бы просто не сделать его модулем, чтобы вы могли использовать использовать . Модули намного проще контролировать и манипулировать в другой программе.

Самые простые решения - это те, где вы не плывете против течения. :)

Кроме того, использование такое же, как:

 BEGIN {
      require Module;
      Module->import;
      }

Вы просто делаете то же самое с именем файла и пространством имен, которое оно определяет (при условии, что код в файле выглядит как модуль):

 BEGIN {
      require "file.pl";  # defines SomeNamespace
      SomeNamespace->import;
      }
...