Ruby中的预填充提示

5

我正在使用Ruby编写一个小型的命令行工具来搜索Pubmed。目前,我会提示用户输入查询并显示结果,并且用户可以选择追加查询或输入全新的查询。我想要添加编辑当前查询的功能;也就是说,提示应该预填充以前查询的可编辑版本,如下所示:

Enter query: <PREVIOUS QUERY HERE>

很容易就可以在提示旁边打印出上一个查询结果,但如何使此输出可编辑,就像用户自己键入的一样?

@casper: 谢谢你的回答,Casper。我尝试了你下面提供的代码,它确实能够正常工作。奇怪的是,当我尝试在gem中使用它时,似乎无法正常工作。我的gem叫做db_hippo。我在gemspec中将rb-readline添加为依赖项,并将RbReadline扩展名放在lib/db_hippo/rb-readline.rb中。

module DbHippo
  module RbReadline
    <CASPER'S EXTENSION HERE>
  end
end

我希望在DbHippo的另一个子模块DbHippo::Source中使用这个功能。在DbHippo::Source中,我在顶部添加了以下代码:

require 'rb-readline'
require 'db_hippo/rb-readline'

然后在 DbHippo::Source 的一个方法中,我有以下代码:

RbReadline.prefill_prompt(query)
query = Readline.readline("Query: ", true)

查询变量肯定不是空的,但出于某种原因,在这种情况下提示框没有被预填充。我还注意到,如果将扩展名放在同一个文件中(lib/db_hippo/rb-readline),而不将其设置为DbHippo的子模块,则会在以下行上得到错误:未初始化常量DbHippo :: Source :: Readline(NameError)

query = Readline.readline("Query: ", true)

这似乎与模块的正确命名、require语句和gems有关。这是我尝试构建的第一个gem。你有什么想法,出了什么问题呢?


是的。你不能把我的扩展代码放在DbHippo模块内部。这是因为我的扩展代码正在对顶级模块RbReadline进行猴子补丁。如果你把补丁代码放在DbHippo内部,你将创建一个新的模块DbHippo::RbReadline,而原始的非补丁代码仍然存在于顶级RbReadline模块中。除此之外,你现在有了两个RbReadline模块,Ruby将很难区分它们...从而使一切工作得非常糟糕 :-/ 所以只需将我的猴子补丁保留在顶级位置,你就应该没问题了。 - Casper
通常我会在我的 lib 目录中创建一个名为 extensions 或类似的文件夹,并将所有猴子补丁放在那里。然后你只需要 require 'db-hippo/extensions/rb-readline',阅读代码的任何人都很清楚正在发生什么。 - Casper
还要注意,在要求扩展代码之前,您必须“require 'rb-readline'”。确保它按正确的顺序进行,否则它将无法正常工作。如果您不确定,请将扩展文件重命名为其他名称,例如'readline-patch.rb',以确保在包含补丁代码之前包含'rb-readline' gem(当您拥有一个与全局 gem 同名的文件时,可能会混淆rubygems)。 - Casper
很棒的解释,我现在已经把所有东西都弄好了。非常感谢您的帮助! - Sean Mackesey
2个回答

6
也许谷歌搜索会对此有所帮助。
使用 Ruby 2.1 上的普通 Readline,您可以使用以下命令:
def ask(prompt, default=nil)

  if default
    Readline.pre_input_hook = -> {
      Readline.insert_text(default)
      Readline.redisplay
      # prevent re-trigger on every `readline`
      Readline.pre_input_hook = nil
    }
  end
  data = Readline.readline("#{prompt}: ")
  return data.chomp
end

ask("MOAR...?", "COMPUTARS!") # displays: MOAR...? COMPUTARS!

在提示符下,文本 COMPUTARS! 将可以编辑。


1
在经过多个小时的搜索、谷歌和挖掘 Ruby 终端处理的多种方式来解决问题后,我终于找到了非常干净的解决方案,这要感谢您!谢谢您! - przemod
1
然而,在钩子处理程序中清除Readline.pre_input_hook是非常谨慎的。如果不这样做,它将继续在每个readline上触发(包括irb提示符:D)。 - Amadan

4
你可以使用 RbReadline 来完成此操作:
require 'rubygems'
require 'rb-readline'

module RbReadline
  def self.prefill_prompt(str)
    @rl_prefill = str
    @rl_startup_hook = :rl_prefill_hook
  end

  def self.rl_prefill_hook
    rl_insert_text @rl_prefill if @rl_prefill
    @rl_startup_hook = nil
  end
end

RbReadline.prefill_prompt("Previous query")
str = Readline.readline("Enter query: ", true)

puts "You entered: #{str}"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接