Class: Binding

Inherits:
Object show all
Defined in:
lib/irb.rb

Instance Method Summary collapse

Instance Method Details

#irb(show_code: true) ⇒ Object

Opens an IRB session where ‘binding.irb` is called which allows for interactive debugging. You can call any methods or variables available in the current scope, and mutate state if you need to.

Given a Ruby file called ‘potato.rb` containing the following code:

class Potato
  def initialize
    @cooked = false
    binding.irb
    puts "Cooked potato: #{@cooked}"
  end
end

Potato.new

Running ‘ruby potato.rb` will open an IRB session where `binding.irb` is called, and you will see the following:

$ ruby potato.rb

From: potato.rb @ line 4 :

    1: class Potato
    2:   def initialize
    3:     @cooked = false
 => 4:     binding.irb
    5:     puts "Cooked potato: #{@cooked}"
    6:   end
    7: end
    8:
    9: Potato.new

irb(#<Potato:0x00007feea1916670>):001:0>

You can type any valid Ruby code and it will be evaluated in the current context. This allows you to debug without having to run your code repeatedly:

irb(#<Potato:0x00007feea1916670>):001:0> @cooked
=> false
irb(#<Potato:0x00007feea1916670>):002:0> self.class
=> Potato
irb(#<Potato:0x00007feea1916670>):003:0> caller.first
=> ".../2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:in `eval'"
irb(#<Potato:0x00007feea1916670>):004:0> @cooked = true
=> true

You can exit the IRB session with the ‘exit` command. Note that exiting will resume execution where `binding.irb` had paused it, as you can see from the output printed to standard output in this example:

irb(#<Potato:0x00007feea1916670>):005:0> exit
Cooked potato: true

See IRB for more information.

[View source]

706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
# File 'lib/irb.rb', line 706

def irb(show_code: true)
  # Setup IRB with the current file's path and no command line arguments
  IRB.setup(source_location[0], argv: []) unless IRB.initialized?
  # Create a new workspace using the current binding
  workspace = IRB::WorkSpace.new(self)
  # Print the code around the binding if show_code is true
  STDOUT.print(workspace.code_around_binding) if show_code
  # Get the original IRB instance
  debugger_irb = IRB.instance_variable_get(:@debugger_irb)

  irb_path = File.expand_path(source_location[0])

  if debugger_irb
    # If we're already in a debugger session, set the workspace and irb_path for the original IRB instance
    debugger_irb.context.replace_workspace(workspace)
    debugger_irb.context.irb_path = irb_path
    # If we've started a debugger session and hit another binding.irb, we don't want
    # to start an IRB session instead, we want to resume the irb:rdbg session.
    IRB::Debug.setup(debugger_irb)
    IRB::Debug.insert_debug_break
    debugger_irb.debug_break
  else
    # If we're not in a debugger session, create a new IRB instance with the current
    # workspace
    binding_irb = IRB::Irb.new(workspace, from_binding: true)
    binding_irb.context.irb_path = irb_path
    binding_irb.run(IRB.conf)
    binding_irb.debug_break
  end
end