LINUX.ORG.RU

require: как понять, что за пакет был подключен?

 


0

1

require с именем файла предполагает, что мы знаем, какой пакет в результате «придёт» в пространство имён. А если не знаем? Да и почему, собственно, имя файла так уж обязано соответствовать имени пакета хоть в чём-то?

Вместо принудительного установления соответствия между именем файла и полным именем пакета или частью имени хотелось бы использовать 2 более-менее разумных, на мой взгляд, подхода:

1) Подключать плагины по имени пакета, но без необходимости обеспечения соответствия между именем пакета и собственно именем файла (хочется один каталог для плагинов, без всякой вложенности каталогов внутри)

2) Подключать плагины по имени файла без расширения *.pm - и тогда нужно будет как-то понять, что за пакет-то был подключен в итоге, но не парсить же на предмет /^\s*package\s+(\w+)/ ради этого!

Есть ли что-то уже готовое для 1 или 2?

В PHP такие штуки не особо проблемно делаются автозагрузчиками модулей/классов. Для Perl'а что-то в упор не нашёл. Плохо искал?

★★★★★

Последнее исправление: DRVTiny (всего исправлений: 1)

А если не знаем?

Если не знаем, значит система нам не принадлежит. Должны знать (иначе вон из профессии) или просто не лезем в чужую систему.

Когда пишу фабричные классы, всегда инклуд ожидает пакет (и только один) с конкретным именем.

outtaspace ★★★
()
Последнее исправление: outtaspace (всего исправлений: 1)
Ответ на: комментарий от outtaspace

Что за **ня, простите? Не с той ноги встали? Проблемы в личной жизни? Можно ответить на вопрос, а не писать чушь? Нет - тогда и не отвечайте, пожалуйста.

DRVTiny ★★★★★
() автор топика

Module::Load

perl -le 'my %before = %INC; require Dancer2; for(sort keys %INC) { print s!/!::!rg =~ s/\.pm$//r if not $before{$_} }'
Casus ★★★★★
()

perldoc -f require

в @INC можно положить coderef

push @INC, sub {
    \ <<\code
package test;
sub say { print "hi there\n" }
1;
code
};


require test;

test::say;
vividsnow
()

На днях столкнулся с аналогичной проблемой и решил её пятиминутным гуглением. Зачем создавать целый тред из-за такой фигни?

anonymous
()
Ответ на: комментарий от anonymous

Это прекрасно.

Так как же дорогой анонимус предпочёл узнавать, что за пакет у него там из файлика подключился? Ну так, просто чтобы уточнить, куда он там гуглил и куда это его привело...

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от Casus
[user@host ~]$ perl -e 'use Data::Dumper; print Dumper \%INC'
$VAR1 = {
          'bytes.pm' => '/usr/share/perl5/bytes.pm',
          'warnings/register.pm' => '/usr/share/perl5/warnings/register.pm',
          'XSLoader.pm' => '/usr/share/perl5/XSLoader.pm',
          'Carp.pm' => '/usr/share/perl5/vendor_perl/Carp.pm',
          'Exporter.pm' => '/usr/share/perl5/vendor_perl/Exporter.pm',
          'strict.pm' => '/usr/share/perl5/strict.pm',
          'constant.pm' => '/usr/local/share/perl5/constant.pm',
          'warnings.pm' => '/usr/share/perl5/warnings.pm',
          'overload.pm' => '/usr/share/perl5/overload.pm',
          'overloading.pm' => '/usr/share/perl5/overloading.pm',
          'Data/Dumper.pm' => '/usr/lib64/perl5/vendor_perl/Data/Dumper.pm'
        };

И что мне это даёт? Если бы было соответствие «файл -> пакеты», то да, это было бы супер-полезно. Но, к сожалению, тут сущность «файл» мапится в тот же самый «файл», но с указанием пути. Это прекрасно, но мне нафиг не упёрлось.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Тебе пацаны помогают, а ты грубишь.

perl -E 'use File::Slurp; eval File::Slurp::read_file("Foo.pm") ; say $Bar::Foo::qux'

P.S. идея у тебя идиотская.

anonymous
()
Ответ на: комментарий от anonymous

И что ты хотел сказать этим куском кода?

И это не идея, и не у меня. Если бы ты родился не 15 лет назад или сколько там, то, наверное, знал бы, что таки да, для софта совершенно нормально, когда в его конфиге пользователь просит софт загрузить плагин «aaa», что соответствует файлу plugins/aaa.so, при этом aaa.so импортирует в соотв. софт объекты, которые буков «aaa» нигде не содержат. Это нормальная здоровая практика. Если это не так в случае с perl-приложениями - это не значит, что надо закрыть глаза и сказать, что такой практики не существует или что она «ни нужна». Это подход идиота, который читает, что совершенно обычная вещь - это типа мои «придумки».

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Я тебе показал как реализовать твою бредовую хотелку. Ничего не мешает сложить все зависимости в каталог cpan/, добавить этот католог в качестве библиотеки и оттуда всё подтягивать. А ты какую-то шизофазию несешь

anonymous
()
Ответ на: комментарий от anonymous

Я вижу, что сказанное мной не доходит до твоего ума в силу отсутствия такового. Предлагаю не развивать балаган.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

А может быть ты сначала почитаешь про разницу между пакетом и модулем? Объекты он импортирует.

perldoc parent читай

anonymous
()

Кто тебе мешает сделать на файл с модулем do или прочитать файл в переменную и сказать на неё eval?

shell-script ★★★★★
()

Решается конфигом имя_плагина -> имя_пакета. Или в PHP это как-то более красиво выглядит?

Olegymous ★★★
()

Вариант 1: экспортни из всех своих файлов с кодом переменную, содержащую массив имен пакетов. имя переменной по соглашению

Вариант 2: во всех файлах дергай Module::Loaded

Вариант 3:

не парсить же на предмет /^\s*package\s+(\w+)/ ради этого

для этого есть PPI. код будет довольно простой, тупо перебрать все PPI::Statement::Package

annulen ★★★★★
()
Ответ на: комментарий от shell-script

Пользоваться-то как? Предполагается, например, что будет создан объект: My::Super::Duper::Package->new() - и как я его создам в коде основной программы, если не знаю, какой, собственно, пакет-то ко мне приехал?

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Тут уже полёт фантазии неограничен. За полминуты вот такое набросалось.

$ cat mod.pm

package Foo;

use strict;
use warnings;

sub can {
        my $name = __PACKAGE__;
        print "$name can\n";
        return 1;
}

1;
$ cat test.pl
#!/usr/bin/perl

use warnings;
use strict;
use File::Slurp;

my $filename = $ARGV[0];
open(my $filehandle, '<', $filename) or die("$!\n");
my $code = read_file($filehandle);
my $modname = '';
if ($code =~ m/^package\s(.*);/) {
        $modname = $1;
}
eval($code);
print "$modname loaded\n";
$modname->can();
close($filehandle);
$ perl test.pl mod.pm
Foo loaded
Foo can

Количество проверок, формат и прочее можно придумать какой угодно. Если нет желания делать стандартизированный набор методов, никто не мешает, после получения имени модуля и его загрузки, пройтись по нему и получить все методы, которые он умеет. Или сделать аналог Exporter'а, чтобы он сам сказал.

Собственно require, use и Exporter это и делают. Посмотри в perldoc, там об этом прямым текстом написано. И там же написано, что require специально проверяет соответсвие название файла, положение его на файловой системе и имя модуля, а потом только eval'ит его. Это не бага, а фича, чтобы помойку не плодить. Но если тебе это не нравится, никто не заставляет сделать nih_require(), который будет проверять другие вещи и не станет обращать внимания не имена.

shell-script ★★★★★
()
Последнее исправление: shell-script (всего исправлений: 1)
Ответ на: комментарий от shell-script

Ничего require не проверяет, спокойно подключал модуль, в котором имя пакета не равно имени модуля.

Olegymous ★★★
()
Ответ на: комментарий от anonymous

У ТСа ПоХаПе головного мозга, а ты ему помогать собрался. Какие-то плагины придумывает, изобретает велосипеды, рассказывает про воображаемые best practices плагинных систем.

В Mojolicious хорошо реализованы плагины, удобно: https://github.com/kraih/mojo/blob/master/lib/Mojolicious/Plugins.pm#L45

Ну и классические фабрики, которые подгружают классы по запросу не отменяются. Но мы пойдем своим, особенным путем.

outtaspace ★★★
()
Ответ на: комментарий от annulen

Вариант 1: экспортни из всех своих файлов с кодом переменную, содержащую массив имен пакетов. имя переменной по соглашению

Довольно разумно: можно объявить список our и push'ить в него __PACKAGE__, а на стороне приложения - брать «вершину стека». Всё равно правда неэстетично как минимум :)

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от Olegymous
    require $pth2pm or die "Cant load handler $handler";
    die "Handler from file << $pth2pm >> seems to be invalid: no 'package' operator found" 
      unless my $loadedPackage=do {
        my $d=PPI::Document->new(\read_file($pth2pm)) || die $!;
        $d->find_first('PPI::Statement::Package')->namespace
      };
    my $oHndl=$hndls{$loadedPackage}{'slf'}=eval "${loadedPackage}->new"
      or die "Cant initialize handler from package $loadedPackage: $@";

Поздно :) Сделал так, как показано выше. В принципе вполне устраивает и главное - не требует от разработчиков плагина делать что-то «особенное», сильно странное и неочевидное.

DRVTiny ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.