Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
July 29, 2021 03:22 pm GMT

A Sneak Peek of Ruby's New Debugger!

GitHub logo ruby / debug

Debugging functionality for Ruby

debug is Ruby's new debugger and will be included in Ruby 3.1. Since I've been both contributing to and using it for a while, I feel it's time to give you guys a sneak peek before its 1.0 release

(Since it's not officially released yet, any feature mentioned in this article could still be modified/removed in the released version)

Introduction

As I have mentioned, it's planned to be a standard library of Ruby 3.1. And currently, you can install it as a gem, like:

$ gem install debug --pre

or

# Gemfile# it's under active development, so I suggest using GitHub as source when possiblegem "debug", github: "ruby/debug" 

Functionality-wise, debug is similar to the famous GDB debugger and Ruby's byebug gem. It provides a rich set of debug commands and has some unique features.

Quoted from its README:

New debug.rb has several advantages:-   Fast: No performance penalty on non-stepping mode and non-breakpoints.-   Remote debugging: Support remote debugging natively.    -   UNIX domain socket    -   TCP/IP    -   VSCode/DAP integration (VSCode rdbg Ruby Debugger - Visual Studio Marketplace)-   Extensible: application can introduce debugging support with several ways:    -   By `rdbg` command    -   By loading libraries with `-r` command line option    -   By calling Ruby's method explicitly-   Misc    -   Support threads (almost done) and ractors (TODO).    -   Support suspending and entering to the console debugging with `Ctrl-C` at most of timing.    -   Show parameters on backtrace command.

And these are my favorite features:

  • It's colorized.

Colorize Example

  • When showing backtrace with the backtrace command, it also shows method arguments, block arguments, and the return value.
=>#0    Foo#forth_call(num1=20, num2=10) at target.rb:20 #=> 30  #1    block {|ten=10|} in second_call at target.rb:8
  • It's possible to script your debug commands with binding.break and reduce manual operations. (See the combinations section for examples)
  • There are several commands to set breakpoints that trigger under different conditions, like break, catch, and watch.

binding.break (alias: binding.b)

If you're a heavy pry user like me, you can use a familiar binding.break (or just binding.b) to kick off the debug session as usual.

But binding.break is actually more powerful than binding.pry, because it can take commands!

For example:

  • binding.b(do: "catch CustomException") - debugger will execute the command (catch customExeption) and continue the program.
  • binding.b(pre: "catch CustomException") - debugger will execute the command (catch customExeption) and stop at the line.

(To execute multiple commands, use ;; as the separator: "cmd1 ;; cmd2 ;; cmd3")

Fequently Used Commands

The new debugger has many powerful commands. And here are the ones I use the most:

break (alias: b)

class A  def foo; end  def self.bar; endendclass B < A; endclass C < A; endB.barC.barb1 = B.newb2 = B.newc = C.newb1.foob2.fooc.foo

Basic Usages

  • b A#foo - stops when b1.foo, b2.foo, and c.foo is called
  • b A.bar - stops when B.bar and C.bar is called
  • b B#foo - stops when b1.foo and b2.foo is called
  • b B.bar - stops when B.bar is called
  • b b1.foo - stops when b1.foo is called

Commands

  • b b1.foo do: cmd - executes cmd when b1.foo is called but doesn't stop
  • b b1.foo pre: cmd - executes cmd when b1.foo is called and stops

catch

class FooException < StandardError; endclass BarException < StandardError; enddef raise_foo  raise FooExceptionenddef raise_bar  raise BarExceptionendraise_fooraise_bar
  • catch StandardError - stops when any instance of StandardError is raised, including FooException and BarException
  • catch FooException - stops when FooException is raised

backtrace (alias bt)

Example Output:

=>#0    Foo#forth_call(num1=20, num2=10) at target.rb:20 #=> 30  #1    block {|ten=10|} in second_call at target.rb:8  #2    Foo#third_call_with_block(block=#<Proc:0x00007f9283101568 target.rb:7>) at target.rb:15  #3    Foo#second_call(num=20) at target.rb:7  #4    Foo#first_call at target.rb:3  #5    <main> at target.rb:23
  • bt - shows all frames on the stack
  • bt 10 - only shows the first 10 frames
  • bt /my_lib/ - only shows the frames with path that matches my_lib

outline (alias ls)

Similar to the ls command in irb or pry.

binding.b + Command Combinations

binding.b(do: "b Foo#bar do: bt")

It allows you to inspect a method call's backtrace without touching the method definition or typing commands manually.

Script:

binding.b(do: "b Foo#bar do: bt")class Foo  def bar  endenddef some_method  Foo.new.barendsome_method

Output:

DEBUGGER: Session start (pid: 75555)[1, 10] in target.rb=>    1| binding.b(do: "b Foo#bar do: bt")      2|      3| class Foo      4|   def bar      5|   end      6| end      7|      8| def some_method      9|   Foo.new.bar     10| end=>#0    <main> at target.rb:1(rdbg:binding.break) b Foo#bar do: btuninitialized constant Foo#0  BP - Method (pending)  Foo#bar do: btDEBUGGER:  BP - Method  Foo#bar at target.rb:4 do: bt is activated.[1, 10] in target.rb      1| binding.b(do: "b Foo#bar do: bt")      2|      3| class Foo=>    4|   def bar      5|   end      6| end      7|      8| def some_method      9|   Foo.new.bar     10| end=>#0    Foo#bar at target.rb:4  #1    Object#some_method at target.rb:9  # and 1 frames (use `bt' command for all frames)Stop by #0  BP - Method  Foo#bar at target.rb:4 do: bt(rdbg:break) bt=>#0    Foo#bar at target.rb:4  #1    Object#some_method at target.rb:9  #2    <main> at target.rb:12

binding.b(do: "b Foo#bar do: info")

It allows you to inspect a method's environment (e.g. argument) when called:

Script:

binding.b(do: "b Foo#bar do: info")class Foo  def bar(a)    a   endenddef some_method  Foo.new.bar(10)endsome_method

Output:

DEBUGGER: Session start (pid: 75924)[1, 10] in target.rb=>    1| binding.b(do: "b Foo#bar do: info")      2|      3| class Foo      4|   def bar(a)      5|     a      6|   end      7| end      8|      9| def some_method     10|   Foo.new.bar(10)=>#0    <main> at target.rb:1(rdbg:binding.break) b Foo#bar do: infouninitialized constant Foo#0  BP - Method (pending)  Foo#bar do: infoDEBUGGER:  BP - Method  Foo#bar at target.rb:4 do: info is activated.[1, 10] in target.rb      1| binding.b(do: "b Foo#bar do: info")      2|      3| class Foo      4|   def bar(a)=>    5|     a      6|   end      7| end      8|      9| def some_method     10|   Foo.new.bar(10)=>#0    Foo#bar(a=10) at target.rb:5  #1    Object#some_method at target.rb:10  # and 1 frames (use `bt' command for all frames)Stop by #0  BP - Method  Foo#bar at target.rb:4 do: info(rdbg:break) info%self = #<Foo:0x00007fdac491c200>a = 10

I'm a Rails developer, so I usually put the combination code at the beginning of a controller action, like:

class SomeController < ApplicationController  def index    binding.b(pre: "b User#buggy_method do: info")    # other code  endend

And then the debugger would execute the command and/or stops at the method I expected.
I don't need to jump between multiple files for adding binding.pry or puts anymore

A Small Drawback

However, the new debugger isn't all perfect (yet). Unlike in byebug or pry, you can't directly evaluate a Ruby expression in the debug session:

(rdbg) 1 + 1unknown command: 1 + 1

To evaluate an expression, you need to use p or pp command:

(rdbg) p 1 + 1=> 2

But according to the project's maintainer @ko1's 'comment, expression evaluation may be supported before the official 1.0 release.

Final Thoughts

Although it's not officially released yet, I've started using it at work daily. And I believe it'll soon become an must-have tool in every Rubyists' toolbox. So if you're curious about its capability, I encourage to give it a try


Original Link: https://dev.to/st0012/a-sneak-peek-of-ruby-s-new-debugger-5caa

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To