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.



1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
# File 'lib/irb.rb', line 1515

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.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)
    binding_irb.context.irb_path = irb_path
    binding_irb.run(IRB.conf)
    binding_irb.debug_break
  end
end