【问题标题】:Ruby: run irb from trap context?Ruby:从陷阱上下文运行 irb?
【发布时间】:2018-11-20 19:14:16
【问题描述】:

Programming Ruby 1.9 & 2.0一书中给出了以下示例:

require 'irb'

trap "INT" do
  IRB.start
end

count = 0
loop do
  count += 1
  puts count
  puts "Value = #{@value}" if defined? @value
  sleep 1
end

不幸的是,如果我使用我的 Ruby 2.5.1 设置运行此代码,我会得到以下 ThreadErrorrun_irb.rb 是上面代码的文件名):

    24: from run_irb.rb:8:in `<main>'
    23: from run_irb.rb:8:in `loop'
    22: from run_irb.rb:12:in `block in <main>'
    21: from run_irb.rb:12:in `sleep'
    20: from run_irb.rb:4:in `block in <main>'
    19: from /usr/lib/ruby/2.5.0/irb.rb:376:in `start'
    18: from /usr/lib/ruby/2.5.0/irb/init.rb:17:in `setup'
    17: from /usr/lib/ruby/2.5.0/irb/init.rb:112:in `init_config'
    16: from /usr/lib/ruby/2.5.0/irb/init.rb:112:in `new'
    15: from /usr/lib/ruby/2.5.0/irb/locale.rb:32:in `initialize'
    14: from /usr/lib/ruby/2.5.0/irb/locale.rb:108:in `load'
    13: from /usr/lib/ruby/2.5.0/irb/locale.rb:124:in `find'
    12: from /usr/lib/ruby/2.5.0/irb/locale.rb:145:in `search_file'
    11: from /usr/lib/ruby/2.5.0/irb/locale.rb:157:in `each_localized_path'
    10: from /usr/lib/ruby/2.5.0/irb/locale.rb:167:in `each_sublocale'
     9: from /usr/lib/ruby/2.5.0/irb/locale.rb:158:in `block in each_localized_path'
     8: from /usr/lib/ruby/2.5.0/irb/locale.rb:150:in `block in search_file'
     7: from /usr/lib/ruby/2.5.0/rubygems.rb:213:in `try_activate'
     6: from /usr/lib/ruby/2.5.0/rubygems/specification.rb:1063:in `find_by_path'
     5: from /usr/lib/ruby/2.5.0/rubygems/specification.rb:1063:in `find'
     4: from /usr/lib/ruby/2.5.0/rubygems/specification.rb:1063:in `each'
     3: from /usr/lib/ruby/2.5.0/rubygems/specification.rb:1064:in `block in find_by_path'
     2: from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:40:in `require'
     1: from /usr/lib/ruby/2.5.0/monitor.rb:185:in `mon_enter'
/usr/lib/ruby/2.5.0/monitor.rb:185:in `lock': can't be called from trap context (ThreadError)

有没有办法使用 Ruby 2.5.1 从陷阱上下文中运行 irb?

【问题讨论】:

  • 我可以理解为什么会出现错误。用例是什么?

标签: ruby irb


【解决方案1】:

Ruby 2.0 不允许在信号处理程序中使用 Mutex#lock

根据 ruby​​ lang 中的 bug 7917,这是“预期的”行为。所以你基本上发现了一个语言错误和一个书籍错误,因为作者没有在 ruby​​ 2.0 中测试这个示例(确认它在 1.9 中有效。)

另一种方法是使用异常/救援并从这样的中断中执行IRB 会话:

require 'irb'

count = 0
loop do
  count += 1
  puts count
  puts "Value = #{@value}" if defined? @value
  sleep 1
rescue Interrupt => e
  IRB.start
  break
end 

以上将正确捕获中断并允许启动IRB 会话。我确实注意到IRB.start 不会为您提供本地执行上下文,因此您可能需要查看binding.irb,它可以让您开始一个更有用的调试会话,如下所示:

$ ruby thread-test.rb
1
2
^C
[1] irb(main)>

From: /work/_scratch/thread-test/thread-test.rb @ line 11 :

     6:   puts count
     7:   puts "Value = #{@value}" if defined? @value
     8:   sleep 1
     9: rescue Interrupt => e
    10:   binding.irb
 => 11:   break
    12: end

[2] irb(main)> e
=> Interrupt
[3] irb(main)> count
=> 2

我发现了一些关于处理 Signals, Traps, and RescuesGraceful Shutdown 的博文,它们可能会帮助您进一步解决问题。

【讨论】:

  • 从 Ruby 2.4 开始,binding.irb 可以获取本地上下文。你不需要撬。
  • @Max 没办法!?!?直到!
  • 谢谢。效果很好。但是如果我将break 更改为retrynext 我只能将Ctrl-C 更改为irb,以下Ctrl-Cs 将被忽略。知道为什么吗?
猜你喜欢
  • 2012-10-14
  • 2015-03-02
  • 2012-05-10
  • 2011-03-27
  • 2010-09-22
  • 1970-01-01
  • 2011-02-06
  • 1970-01-01
  • 2017-03-27
相关资源
最近更新 更多