I’m by nature a kinesthetic learning or someone that learns by doing. One of the ways I learn new Ruby codebases or techniques is to dive into them and see how they work during every step of their processing. Pry is a great tool for allowing me to dig directly into code. While, really useful for debugging and understanding, one thing that has bothered me about using Pry is that it doesn’t work properly with classes that inherit from SimpleDelegator. Instead it ends up in a method_missing block. Luckily, I recently learned a great workaround for this issue which we’ll get into below.

What happens when calling Pry within a Decorator?

Let’s say you have the following Decorator that inherits from SimpleDelegator:

class UserDecorator < SimpleDelegator

  # @return [String] formats an email address with the User's name
  def format_email
    binding.pry # I want to know what's going on here

    "{name} <{email}>" #=> returns Josh <josh@example.com>
  end
end

You’d typically expect to see the context be within the UserDecorator above. However, what actually happens is that we end up in the Delegator#method_missing magic method. It looks like the below code:

   78: def method_missing(m, *args, &block)
   79:   r = true
   80:   target = self.__getobj__ {r = false}
   81: 
   82:   if r && target.respond_to?(m)
   83:     target.__send__(m, *args, &block)
   84:   elsif ::Kernel.respond_to?(m, true)
=> 85:     ::Kernel.instance_method(m).bind(self).(*args, &block)
   86:   else
   87:     super(m, *args, &block)
   88:   end
   89: end

SimpleDelegator workaround

Pro Tips [2]
  • ls - lists all available variables
  • next - execute the next line of code
  • ls -grep [keyword] - lists all available variables matching a pattern
  • whereami - shows the current code context in reference to Pry location
  • !!! - exits out of current and future Pry debugger commands
  • help - list of all available commands within a Pry session

Now, technically at this point you can still check variables as if you were in the UserDecorator above with commands like ls to list all the accessible variables, but you really can’t see where you are in the code. This isn’t super helpful for times when you want to next your way through the code.

However, there is a trick to getting around this which is hinted at in the method_missing response above. Instead of using the vanilla binding.pry use the classifed name of ::Kernel.binding.pry[1]. Now you’ll be within your method’s context and be able to see your current breakpoint position.

   83: def method_to_pry_into
=> 84:   ::Kernel.binding.pry
   85:   # more logic here
   86: end

Nice! Know any other cool tricks you’ve learned while using Pry? Maybe you know about another tool that has been useful to your learning? I’d love to hear about it in the comments below.

Thanks for reading.

Additional Resources

  1. Original Pry Github Issue & Fix
  2. Pry Command System

Join the conversation

comments powered by Disqus