Как мне динамически обнаруживать пакеты из частичного пространства имен в Perl? - PullRequest
0 голосов
/ 04 июня 2010

У меня есть структура каталогов, которая выглядит следующим образом:

Foo :: Bar :: Баз :: 1 Foo :: Bar :: Baz :: 2 etc

Могу ли я перечислить пакеты с чем-то вроде:

use Foo::Bar::Baz;

Спасибо!

Редактировать: стало более понятно, что это за модули.

Ответы [ 4 ]

7 голосов
/ 04 июня 2010

Если вы хотите загрузить все модули в вашем пути включения с определенным префиксом (например, все под a::b::c, вы можете использовать Module :: Find .

Например:

use Module::Find 'useall';

my @loaded = useall 'Foo::Bar::Baz';  # loads everything under Foo::Bar::Baz

Это зависит от того, какой путь @INC настроен с необходимыми каталогами, поэтому сначала выполните все необходимые манипуляции (например, с use lib).

1 голос
/ 04 июня 2010

Это может быть излишним, но вы можете проверить таблицу символов до и после загрузки модуля и посмотреть, что изменилось:

use strict; use warnings;
my %original = map { $_ => 1 } get_namespaces("::");
require Inline;
print "New namespaces since 'require Inline' call are:\n";
my @new_namespaces = sort grep !defined $original{$_}, get_namespaces("::");
foreach my $new_namespace (@new_namespaces) {
  print "\t$new_namespace\n";
}

sub get_namespaces {
  # recursively inspect symbol table for known namespaces
  my $pkg = shift;
  my @namespace = ();
  my %s = eval "%" . $pkg;
  foreach my $key (grep /::$/, keys %s) {
    next if $key eq "main::";
    push @namespace, "$pkg$key", get_namespaces("$pkg$key");
  }
  return @namespace;
}

New namespaces since 'require Inline' call are:
        ::AutoLoader::
        ::Config::
        ::Digest::
        ::Digest::MD5::
        ::Dos::
        ::EPOC::
        ::Exporter::
        ::Exporter::Heavy::
        ::File::
        ::File::Spec::
        ::File::Spec::Cygwin::
        ::File::Spec::Unix::
        ::File::Spec::Win32::
        ::Inline::Files::
        ::Inline::denter::
        ::Scalar::
        ::Scalar::Util::
        ::Socket::
        ::VMS::
        ::VMS::Filespec::
        ::XSLoader::
        ::vars::
        ::warnings::register::
1 голос
/ 04 июня 2010

Обычно сценарий, такой как / b / c.pl, не имеет пространства имен, отличного от main. Возможно, вы думаете об открытии модулей с такими именами, как / b / c.pm (что является неправильным именем, поскольку имена пакетов в нижнем регистре обычно зарезервированы для внутренних объектов Perl).

Однако, учитывая путь к каталогу, вы можете искать потенциал модулей Perl, используя File :: Find :

use strict;
use warnings;
use File::Find;
use Data::Dumper;

my @modules;
sub wanted
{
    push @modules, $_ if m/\.pm$/
}
find(\&wanted, 'A/B');

print "possible modules found:\n";
print Dumper(\@modules)'
0 голосов
/ 04 июня 2010

Просто чтобы прояснить, вы смотрите на случайные пакеты в случайном коде Perl?

Или для модулей Perl , например. «a / b / c / d1.pm» с модулем «a :: b :: c :: d1»?

В любом случае вы не можете использовать один оператор "use" для загрузки их всех.

Вам нужно найти все подходящие файлы, используя glob или File::Find.

В первом случае (модули) вы можете затем загрузить их, либо require -из каждого файла, ИЛИ путем преобразования имени файла в имя модуля (s#/#::#g; s#\.pm$##;) и вызова use для каждого модуля отдельно. *

Что касается реальных пакетов, вложенных в случайные файлы Perl, то эти пакеты могут быть:

  • Перечислено путем сопоставления каждого файла (опять же, найдено через glob или File::Find) для /^package (.*);/

  • На самом деле загружается путем выполнения require $file для каждого файла.

    В этом случае обратите внимание, что имя пакета для каждого из этих пакетов в a/b/c/1.pl будет НЕ должно быть связано с "a :: b :: c" - например, они МОГУТ быть названы автором файла "p1", "a :: p1" или "a :: b :: c :: p1_something".

...