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

发布于 2024-11-06 05:59:35 字数 1935 浏览 0 评论 0原文

我正在编写一个程序供其他人使用。设计规范之一是使用 Term::ReadLine::Gnu Perl 库。大多数用户不会安装它,而我想在程序运行时安装它。

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

这就是我检查模块的方式

         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);
          }

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

无法定位对象方法“using_history” " via package "Term::ReadLine::Stub" at ./msi.pl 第 618 行,第 2 行。

第 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;

I'm writing a program for others to use. One of the design specs is to use the Term::ReadLine::Gnu Perl library. Most of the users will not have this installed and I want to install it while the program is running.

So, when the user starts the program they do not have the library installed. My program will install it for them while they are using the program using the OS package manager.

This is how I'm checking for the module

         require Term::ReadLine;

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

I use the $Readline_Support variable to redirect the terminal, use the history file etc.

          $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);
          }

Unfortunately, I get this error when I try to use the history file:

Can't locate object method "using_history" via package "Term::ReadLine::Stub" at ./msi.pl line 618, line 2.

line 618 is

          $TERMINAL->using_history();

Which is the first use of the $TERMINAL object.

Has any one had experience with installing Perl modules while the script is running and then using the modules in that same script?

Ok... Thanks to Andy if the module is not installed this works

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

below in the code

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

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

Now, however, the check for the installed mod always fails, I think because

            require Term::ReadLine::Gnu;

needs

            require Term::ReadLine;

early in the code, like the old

     require Term::ReadLine;

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

掩于岁月 2024-11-13 05:59:35

大多数用户不会安装此程序,而我想在程序运行时安装它。

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

只需声明依赖关系,这样当您的程序安装时,T::R::G 也会被安装。我链接到 How 中的相关文档我要为遗留系统创建构建吗?

该工具链已经为您提供了所有必要的部分,使每个参与其中的人都可以轻松完成此任务,请务必了解它。

Most of the users will not have this installed and I want to install it while the program is running.

You're swimming against the flow here. No one else does it this way, and changing a system after installation would also upset most system admins I know.

Simply declare the dependency, so when your program is installed, T::R::G is also installed. I link to the pertinent documentation in How do I create a build for a legacy system?.

The toolchain gives you already all the necessary bits to make this painless for everyone who is involved, do learn about it.

淡写薰衣草的香 2024-11-13 05:59:35

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

You can learn from the "cpan" command itself. cpan can install (upgrade) himself and reload all used modules afterward. That should be a good starting point for learning.

镜花水月 2024-11-13 05:59:35

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

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

事情变得更加复杂,因为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";

I see in the code for Term::ReadLine that it determines which implementation it is going to use at load time, as opposed to when new is called. So I would suggest the following sequence:

  1. test for availability of Term::ReadLine::Gnu just like you are currently, but before loading any ReadLine modules
  2. install Term::ReadLine::Gnu if not present
  3. require Term::ReadLine
  4. create your object with Term::ReadLine->new

Things are made more complicated because Term::ReadLine::Gnu throws an error on an attempt to load it directly with use or require, so the straightforward eval test fails even when it's installed. One way to deal with that is to parse $@, but I don't like parsing diagnostic messages because there's a risk they may change over time. Deleting from %INC doesn't seem great either, but should work as long as the error on a direct load of Term::ReadLine::Gnu doesn't go away.

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";
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文