Как получить имя модуля по имени файла? - PullRequest
0 голосов
/ 29 января 2019

У меня есть модуль Foo::Bar::Baz, который находится на /some_path/Foo/Bar/Baz.pm, и скрипт perl, который запускается с /some_path/Foo/Bar.Скрипт должен проанализировать все модули в этой папке.

Как я могу получить имя модуля (Foo::Bar::Baz) по имени файла (Baz.pm)?Я не могу просто обрезать .pm окончание, а также lib путь в @INC недетерминирован

Сначала я должен использовать new_from_file и name методыиз Module :: Info , но, к сожалению

Модуль, загруженный с помощью new_from_file (), не будет иметь этой информации

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

Ответы [ 3 ]

0 голосов
/ 29 января 2019

Не требуется, чтобы имена пакетов соответствовали имени файла, из которого оно было загружено, или для первого пакета до .Но для любого разумно написанного модуля, который вы можете use нормально и даже для некоторых странных, Module :: Metadata может найти эту информацию.Как правило, вы должны работать с абсолютными именами файлов независимо от вашего текущего каталога, что может помочь.( File :: Spec и Path :: Tiny могут помочь в этом)

use strict;
use warnings;
use Module::Metadata;
my $metadata = Module::Metadata->new_from_file('/path/to/File.pm');
my $package = $metadata->name;
0 голосов
/ 29 января 2019

В принципе, вы не можете без анализа ваших файлов.Правильный путь - использовать какой-то стандартный модуль Perl, например https://perldoc.pl/Module::Metadata,, но если вы хотите сделать это самостоятельно, с помощью следующего фрагмента вы можете извлечь все пространства имен из каждого файла (да .. файл - это просто контейнер, поэтому у вас может быть больше пакетов внутри).

Быстрый и грязный способ:

my $PACKAGES ;
my @files = ('lib/Foo.pm','lib/Bar.pm') ;
my $row ;
map {
    open PKGFILE , '<', $_ or die "Got error opening file $_: $!" ;
    while ( $row = <MODULE>){
        if ( $row =~ /\s*package\s+([\S]+)(.*?)[;{]/ ){
            # rx modified on Grinnz review
            push @{$PACKAGES->{ $_ }} , $1 ;
            # last ; # <== uncomment if you are sure each file 
                     #     contains only one package
        } ;
    }
    close PKGFILE ;
} @files ;

Предполагая, что у нас есть два файла:

1) lib/Foo.pm (с 2пакеты внутри)

package Banana::Joe 0.003 ;

...code...

package Papaya::Frank 0.001 ;

...code...

1 ;

2) lib/Bar.pm

package Apple::Steve 0.013 ;

...code...

1 ;

$PACKAGES будет:

 {
   'lib/Bar.pm' => [
                     'Apple::Steve'
                   ],
   'lib/Foo.pm' => [
                     'Banana::Joe',
                     'Papaya::Frank'
                   ]
 };
0 голосов
/ 29 января 2019

Я использовал PPI для анализа (и переписывания) Perl-кода.Насколько я помню, немного кривой обучения, но это работало довольно хорошо.В вашем случае вам действительно нужно только найти оператор package <...> внутри файла.Ничего более сложного, например, кто-то использует autopackage и PPI, вероятно, тоже не сможет помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...