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

在Perl脚本运行时安装Term::ReadLine::Gnu并使用脚本中的模块,perl,module,installation,readline,Perl,Module,Installation,Readline,我正在写一个供别人使用的程序。设计规范之一是使用术语::ReadLine::Gnu Perl库。大多数用户不会安装这个,我想在程序运行时安装它 因此,当用户启动程序时,他们没有安装库。我的程序将在他们使用OS package manager时为他们安装它 这就是我检查模块的方式 require Term::ReadLine; my $Readline_Support = 1; eval { require Term::ReadLine::G

我正在写一个供别人使用的程序。设计规范之一是使用术语::ReadLine::Gnu Perl库。大多数用户不会安装这个,我想在程序运行时安装它

因此,当用户启动程序时,他们没有安装库。我的程序将在他们使用OS package manager时为他们安装它

这就是我检查模块的方式

         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;

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

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

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

  • 在加载任何
    ReadLine
    模块之前,测试
    Term::ReadLine::Gnu的可用性,就像当前一样
  • 如果不存在,请安装
    Term::ReadLine::Gnu
  • require Term::ReadLine
  • 使用
    Term::ReadLine->new
  • 事情变得更加复杂,因为
    Term::ReadLine::Gnu
    在尝试使用
    use
    require
    直接加载时抛出错误,因此直接的
    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";
    

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

  • 在加载任何
    ReadLine
    模块之前,测试
    Term::ReadLine::Gnu的可用性,就像当前一样
  • 如果不存在,请安装
    Term::ReadLine::Gnu
  • require Term::ReadLine
  • 使用
    Term::ReadLine->new
  • 事情变得更加复杂,因为
    Term::ReadLine::Gnu
    在尝试使用
    use
    require
    直接加载时抛出错误,因此直接的
    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";
    
    大多数用户不会安装这个,我想在程序运行时安装它

    你在逆流而上。没有其他人会这样做,而且在安装后更改系统也会让我认识的大多数系统管理员感到不安

    只需声明依赖项,这样在安装程序时,也会安装T::R::G。我链接到中的相关文档

    工具链已经为您提供了所有必要的信息,让所有相关人员都能轻松地完成此任务,请务必了解它

    大多数用户不会安装这个,我想在程序运行时安装它

    你在逆流而上。没有其他人会这样做,而且在安装后更改系统也会让我认识的大多数系统管理员感到不安

    只需声明依赖项,这样在安装程序时,也会安装T::R::G。我链接到中的相关文档


    工具链已经为您提供了所有必要的信息,让所有相关人员都能轻松地完成这项工作,请务必了解它。

    我认为这种通用方法会起作用,但是
    Term::ReadLine::Gnu
    在尝试直接加载时会抛出一个错误,因此它将更加复杂。我会做一些更完整的工作。谢谢,这很有效,但是现在如果安装了模块,那么它将不会加载mod。@bitbucket安装后,即使有更新的代码,它也不会加载吗?您是否有
    删除$INC{…}
    ?在linux上使用Perl5.10.1对我来说是可行的。很好,很好用。我看到其他一些代码改变了$INC。现在我想我对使用、require和%INC有了更好的了解。谢谢。我认为一般的方法会起作用,但是
    Term::ReadLine::Gnu
    在尝试直接加载它时会抛出错误,所以它会更复杂一些。我会做一些更完整的工作。谢谢,这很有效,但是现在如果安装了模块,那么它将不会加载mod。@bitbucket安装后,即使有更新的代码,它也不会加载吗?您是否有
    删除$INC{…}
    ?它在Perl5.10.1o中为我工作