【问题标题】:Customising IRB console for gem为 gem 自定义 IRB 控制台
【发布时间】:2017-01-22 19:05:29
【问题描述】:

我想通过应用一些 IRB 配置选项来扩展默认的控制台应用程序,该应用程序是使用 bundle gem 作为标准构建的。

Looking at the documentation,我可以看到例如应该可以更改提示,这在交互式会话中可以正常工作。例如,我可以像这样使用显示的提示:

2.1.4 :001 > conf.prompt_mode=:SIMPLE
=> :SIMPLE
>>
?> conf.prompt_mode=:DEFAULT
=> :DEFAULT
irb(main):004:0>

但是,我找不到如何将其转换为在控制台应用程序中使用的语法。例如这个脚本:

require 'irb'
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.start

从通用的配置提示开始:

2.1.4 :001 >

我花了一些时间试图找到一个在不加载全局默认值的情况下将 IRB 用于自定义 repl 的示例,但没有找到任何可以复制的内容。

我可以看到未记录的方法IRB.setup 与此有关,它以某种方式设置所有配置。我唯一的选择是编写自己的IRB.start 版本,在调用IRB.setup 后应用我想要的配置,还是支持我想做的内置但未在标准位置记录的功能?


例如以下工作,但我觉得以这种方式扩展 IRB 模块有点笨拙(如果 IRB 内部发生变化,也容易失败)。

require 'irb'

def IRB.custom_start custom_conf = {}
  STDOUT.sync = true

  IRB.setup(nil)

  custom_conf.each do |k,v|
    IRB.conf[k] = v
  end

  if @CONF[:SCRIPT]
    irb = IRB::Irb.new(nil, @CONF[:SCRIPT])
  else
    irb = IRB::Irb.new
  end

  @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
  @CONF[:MAIN_CONTEXT] = irb.context

  trap("SIGINT") do
    irb.signal_handle
  end

  begin
    catch(:IRB_EXIT) do
      irb.eval_input
    end
  ensure
    irb_at_exit
  end
end

IRB.custom_start :PROMPT_MODE => :SIMPLE

【问题讨论】:

    标签: ruby irb


    【解决方案1】:

    您可以通过两种方式应用自定义配置。

    第一个是使用irbrc file。构建控制台应用程序可能会很棘手(从 ruby​​ 文件调用 IRB.start 而不是从控制台调用 irb)。

    第二种方法是您在帖子中描述的方法。您可以基于the original one 编写自己的IRB::start 方法。与使用未记录的 API 存在完全相同的潜在问题 - 它可能会在未来使用更新版本的 irb 时中断。

    您应该考虑是否真的需要在 irb 之上构建控制台应用程序。例如,您可以使用Pry 解决此问题。它允许在开始交互式会话之前define configuration

    【讨论】:

    • 感谢您再次将我指向 Pry。之前看了一下,但是对调试功能的关注让我觉得不合适。对我来说,它可能比irb 更好,即使只是为了正确记录支持以编程方式更改配置。
    【解决方案2】:
    require 'irb'
    IRB.conf[:PROMPT_MODE] = :SIMPLE
    IRB.start
    

    上面的方法不起作用,因为conf[:PROMPT_MODE] 在一个名为IRB.init_config here 的方法中被覆盖

    IRB.start 被调用时,它会调用IRB.setup,而IRB.setup 又会调用IRB.init_config 方法——它会覆盖conf[:PROMPT_MODE] 设置。


    这是解决问题的一种方法(依赖于实现的内部知识)。

    require 'irb'
    
    module IRB
      singleton_class.send(:alias_method, :old_setup, :setup)
    
      def IRB.setup(ap_path)
        IRB.old_setup(ap_path)
    
        conf[:PROMPT_MODE] = :SIMPLE
      end
    end
    
    IRB.start
    

    【讨论】:

    • 这比我的解决方案更干净,但确实存在一个问题,即它适用于实现,而不是“官方”接口。
    • @NeilSlater 是的,这就是为什么我说它“依赖于实现的内部知识”。我猜,setup 是一个公共方法,因此是公共接口的一部分。它只是没有很好地记录。
    猜你喜欢
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 2012-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多