在Perl脚本运行并使用脚本中的模块时安装Term :: ReadLine :: Gnu

时间:2011-05-06 22:54:26

标签: perl module install readline

我正在为其他人编写程序以供使用。其中一个设计规范是使用Term :: ReadLine :: Gnu Perl库。大多数用户都没有安装,我想在程序运行时安装它。

因此,当用户启动程序时,他们没有安装库。我的程序将在他们使用OS包管理器使用程序时为他们安装。

我正在检查模块

         require Term::ReadLine;

         my $Readline_Support = 1;
         eval { require Term::ReadLine::Gnu }
           or $Readline_Support = 0;

我使用$ Readline_Support变量重定向终端,使用历史文件等。

          $OUT = $TERMINAL->OUT if $readline_installed;
          if ($readline_installed)
          {
            # save every answer and default, good or not, to the history file
            $TERMINAL->add_history($Ans);
            $TERMINAL->append_history(1, HIST_FILE);
          }

不幸的是,当我尝试使用历史文件时出现此错误:

无法在./msi.pl第618行第2行通过包“Term :: ReadLine :: Stub”找到对象方法“using_history”。

第618行是

          $TERMINAL->using_history();

第一次使用$ TERMINAL对象。

是否有人在脚本运行时安装Perl模块,然后在同一个脚本中使用模块?

好的...感谢Andy,如果没有安装模块,那么

          # I removed the  require Term::ReadLine; here
          my $Readline_Support = 1;
          eval { require Term::ReadLine::Gnu }
            or $Readline_Support = 0;

下面的代码

            if ($readline_installed)
            {
              # Required for the dynamic loading of Term::ReadLine::Gnu
              require Term::ReadLine;

              $TERMINAL = Term::ReadLine->new ('ProgramName')
                 if $Interactive or $Brief
            }

然而,现在,对已安装mod的检查总是失败,我认为是因为

            require Term::ReadLine::Gnu;

需要

            require Term::ReadLine;

在代码的早期,就像旧的

一样
     require Term::ReadLine;

     my $Readline_Support = 1;
     eval { require Term::ReadLine::Gnu }
       or $Readline_Support = 0;

3 个答案:

答案 0 :(得分:2)

  

大多数用户都没有安装,我想在程序运行时安装它。

你在这里游泳。没有其他人这样做,安装后更换系统也会让我认识的大多数系统管理员感到不安。

只需声明依赖项,因此在安装程序时,还会安装T :: R :: G.我链接到How do I create a build for a legacy system?中的相关文档。

工具链已经为您提供了所有必要的功能,让每个参与其中的人都可以轻松学习。

答案 1 :(得分:1)

您可以从“cpan”命令本身学习。 cpan可以自己安装(升级)并重新加载所有使用过的模块。这应该是一个很好的学习起点。

答案 2 :(得分:0)

我在Term::ReadLine的代码中看到,它确定在加载时将使用哪个实现,而不是在调用new时。所以我建议采用以下顺序:

  1. 测试Term::ReadLine::Gnu的可用性,就像您当前一样,但在加载任何ReadLine模块之前
  2. 安装Term::ReadLine::Gnu(如果不存在)
  3. require Term::ReadLine
  4. 使用Term::ReadLine->new
  5. 创建对象

    事情变得更加复杂,因为Term::ReadLine::Gnu在尝试使用userequire直接加载时会引发错误,因此直截了当的eval测试失败,即使它是安装。解决这个问题的一种方法是解析$@,但我不喜欢解析诊断消息,因为它们可能会随着时间的推移而发生变化。从%INC删除也不是很好,但只要直接加载Term::ReadLine::Gnu的错误不会消失,就应该有效。

    my $readline_installed = 1;
    unless (eval { require Term::ReadLine::Gnu; }) {
        # Term::ReadLine::Gnu throws an error that it can't be loaded directly,
        # even when it's installed.
        $readline_installed = exists ($INC{"Term/ReadLine/Gnu.pm"});
    
        # Needed so that it will be reloaded after installation
        delete $INC{"Term/ReadLine/Gnu.pm"};
    }
    
    unless ($readline_installed) {
        print "Installing Term::ReadLine::Gnu\n";
        # ...
    }
    
    require Term::ReadLine;
    
    my $term = Term::ReadLine->new ("app");
    $term->addhistory ("blah");
    print $term->readline ("> "), "\n";