The default IRB completion code that ships with Ruby does not work well when being invoked from the debugger prompt: >: ruby /test_script.rb [-2, 7] in /test_script.rb 1 require 'ruby-debug' 2 debugger => 3 :foo /test_script.rb:3 :foo (rdb:1) INTERNAL ERROR!!! undefined method `workspace' for nil:NilClass /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/irb/completion.rb:38 /Users/tomtt/.gem/ruby/1.8/gems/ruby-debug-0.10.3/cli/ruby-debug/interface.rb:112:in `call' /Users/tomtt/.gem/ruby/1.8/gems/ruby-debug-0.10.3/cli/ruby-debug/interface.rb:112:in `readline' /Users/tomtt/.gem/ruby/1.8/gems/ruby-debug-0.10.3/cli/ruby-debug/interface.rb:112:in `readline' /Users/tomtt/.gem/ruby/1.8/gems/ruby-debug-0.10.3/cli/ruby-debug/interface.rb:62:in `read_command' /Users/tomtt/.gem/ruby/1.8/gems/ruby-debug-0.10.3/cli/ruby-debug/processor.rb:246:in `process_commands' /Users/tomtt/.gem/ruby/1.8/gems/ruby-debug-0.10.3/cli/ruby-debug/processor.rb:171:in `__at_line' (eval):5:in `at_line' (eval):3:in `synchronize' (eval):3:in `at_line' /Users/tomtt/.gem/ruby/1.8/gems/ruby-debug-base-0.10.3/lib/ruby-debug-base.rb:54:in `at_line' /test_script.rb:3

The reason why this happens is that the completion code assumes that IRB.conf[:MAIN_CONTEXT] is defined, but this is not the case when debugger is used. All we are really after is a valid binding, so to patch we can just use self.binding when the irb context is not available. An example patch can be found on my fork of an unofficial ruby repository.

In these days where rvm allows multiple ruby versions to be used, patching is not a patch-once-and-forget issue any longer. Therefore I felt the need to write a utility for this. It checks if your current version of ruby is patched and if not, shows the filename that needs to be updated and the suggest code change. It is bundled as the patch_irb_completion gem: simply “gem install patch_irb_completion;patch_irb_completion”. But that gives the overhead of having to install a gem for every ruby version. So maybe an executable script is a better solution. Here is one: #!/usr/bin/env ruby require 'find' module PatchIRBCompletion class Suggest def self.find_ruby_lib_path ruby_bin_path = `which ruby` ruby_path = File.expand_path(File.join(ruby_bin_path, "..", "..", "lib")) unless File.exist?(ruby_path) ruby_path = `ruby -e "puts $:[0]"` end end def self.find_completion_source_in_dir(dir) Find.find(dir) do |filename| # puts filename next unless File.basename(filename) == "completion.rb" return filename end nil end def self.find_completion_source_in_current_ruby_version $:.each do |lib_dir| completion_file = find_completion_source_in_dir(lib_dir) next unless completion_file return completion_file end end def self.check_if_completion_source_file_has_offending_code(filename) unpatched_code = "IRB.conf[:MAIN_CONTEXT].workspace" File.read(filename).include?(unpatched_code) end def self.call filename = find_completion_source_in_current_ruby_version if check_if_completion_source_file_has_offending_code(filename) puts <