如何通过文件名获取模块名称?

时间:2019-01-28 22:03:40

标签: perl

我有位于<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script> 上的模块Foo::Bar::Baz和从/some_path/Foo/Bar/Baz.pm运行的perl脚本。脚本需要分析此文件夹中的所有模块。

如何通过文件名(/some_path/Foo/Bar)获得模块名(Foo::Bar::Baz)?我不能只修剪Baz.pm结尾,而且@INC中的.pm路径是不确定的

首先,我应该使用new_from_filenameModule::Info方法,但是很遗憾

  

使用new_from_file()加载的模块将没有此信息

好像我需要一些进行静态代码分析的模块。有人知道它的名字吗?

3 个答案:

答案 0 :(得分:4)

不需要软件包名称与加载的文件名匹配,即for the first package to。但是对于您可以正常use甚至是一些奇怪的模块编写的任何合理的模块,Module::Metadata都可以找到此信息。通常,无论当前目录如何,都应使用绝对文件名,这可能会有所帮助。 (File::SpecPath::Tiny可以为您提供帮助)

use strict;
use warnings;
use Module::Metadata;
my $metadata = Module::Metadata->new_from_file('/path/to/File.pm');
my $package = $metadata->name;

答案 1 :(得分:2)

我已经使用PPI来分析(和重写)perl代码。我记得,这是一个学习曲线,但效果很好。就您而言,您实际上只需要从文件中找到package <...>语句。比这更复杂的事情,例如使用autopackage的人,以及PPI可能也无济于事。

答案 2 :(得分:2)

基本上,您不能不分析文件。 正确的方法是使用一些标准的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'
                   ]
 };