【问题标题】:How to get module name by file name?如何通过文件名获取模块名称?
【发布时间】:2023-03-28 19:23:01
【问题描述】:

我有模块Foo::Bar::Baz,它位于/some_path/Foo/Bar/Baz.pm,以及从/some_path/Foo/Bar 运行的perl 脚本。脚本需要分析此文件夹中的所有模块。

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

首先我应该使用Module::Infonew_from_filename方法,但不幸的是

使用 new_from_file() 加载的模块不会包含此信息

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

【问题讨论】:

  • 您能否提供更详细的解释来说明您正在尝试做什么或期望输出什么?我几乎可以肯定我的Devel::Examine::Subs 可以满足您的要求,但已经有一段时间了,我需要进一步澄清测试(我在后台使用PPI)。
  • 您假设存在 一个(单一的、唯一的)模块名称。情况不一定如此。如果有 0 个或 2+ 个名字,你想做什么?
  • 更改您的脚本,使其接受两个输入:基本目录 (/some_path) 和包名称 (Foo::Bar::Baz,或者甚至可能是 Foo::Bar::*)
  • 谢谢大家的回答,最后我用Module::Metadata 代替了我的project

标签: perl


【解决方案1】:

包名不需要与加载它的文件名相匹配,或者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;

【讨论】:

    【解决方案2】:

    我使用PPI 来分析(和重写)perl 代码。我记得,有点学习曲线,但效果相当好。在您的情况下,您实际上只需要从文件中找到 package <...> 语句。任何比这更复杂的东西,比如有人使用autopackage,PPI 也可能无法提供帮助。

    【讨论】:

      【解决方案3】:

      如果不解析文件,基本上你不能。 正确的方法是使用一些标准的 perl 模块,例如 https://perldoc.pl/Module::Metadata,但是如果你想自己做,使用下面的 sn-p 你可以从每个文件中提取所有命名空间(是的..文件只是一个容器,所以你里面可能有更多的包)。

      快速而肮脏的方式:

      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-9.]* 不足以解析 package 语句的 VERSION 组件,并且 package 语句可以使用包含自 Perl 5.14 以来的包内容的 BLOCK。我强烈建议不要试图重新发明它。
      • @Grinnz 你是对的,我修复了正则表达式。它仍然是一个脆弱的正则表达式,不考虑单行 perl 代码中的重复或其他特殊情况。这只是为了学校,即使它可以解决 99.99% 的情况。顺便说一句,我认为在使用其他人的课程之前尝试自己做事(至少对于个人文化)更有教育意义。否则,使用 perl 编程将变得像使用 Java 编程一样,其中唯一需要知道的是要实例化的类的名称,而不知道它在后台是如何工作的。但这只是我的观点,可能我错了。
      • 我认为查看针对您的问题建议的那些模块的源代码比尝试重新发明它已经修复的所有问题更有效。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-06
      • 1970-01-01
      • 2011-09-09
      • 1970-01-01
      • 2021-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多