Understanding binding.pry

I have been using Pry as a repl and as a debugging tool for Ruby for as long as I can remember. I am a proficient user of the tool, but so far, I haven't put any effort to understand how Pry debugger works.

Together, let's learn how Pry debugger works, but before we dive into that, we need to do some ground work and learn what binding is.

From Ruby documentation,

Objects of class Binding encapsulate the execution context at some particular place in the code and retain this context for future use. The variables, methods, value of self , and possibly an iterator block that can be accessed in this context are all retained.

Let us use (a modified version) the sample code given in the documentation to understand this concept a bit more.

class Demo
  def initialize(message)
    @message = message
  end
  
  def get_binding
    binding
  end
end

irb:xx> demo_binding = Demo.new('fantastic').get_binding
irb:xx> puts demo_binding.eval("It has been a #{@message} demo")
It has been a fantastic demo
nil
irb:xx>

In essence, binding.eval executes any 'code-string' in the context of the object at the point at which the binding was captured.

What is binding.pry?

Pry debugger extends Ruby's Binding class to start a REPL whenever #pry is called on a binding. The REPL is started in such a way that the REPL's context is the binding itself.

Let's try to mimic this, with a barebones implementation.

class Binding
  # We are opening and patching Ruby's in-built Binding class
  # and adding a new method: #pry
  
  def pry
    # Our humble read-eval-print-loop
    loop do
      puts self.eval(gets)
    end
  end
end

class Demo
  def initialize(message)
    @message = message
  end

  def get_binding
    binding
  end
  
  def start_pry
    binding.pry
  end
end

irb:xx> demo = Demo.new("simple repl")
=> #<Demo:0x00007fa8d61677a0 @message="simple repl">

irb:xx> demo.start_pry
puts "This is a #{@message}"
This is a simple repl

At its core, Pry  is as simple as this, but in its entirety, Pry is much more. Our barebones implementation lacks a prompt and bombs when we try to evaluate multi-line code. Pry uses Ruby Readline to handle all these cases and as a cherry on top, uses coderay to highlight the code.