Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
The community reviewed whether to reopen this question last year and left it closed:
Improve this questionOriginal close reason(s) w开发者_开发技巧ere not resolved
I copied the following Ruby code from the Internet and made a few changes but it doesn't work.
What can I do to debug the program by myself?
Use Pry (GitHub).
Install via:
$ gem install pry
$ pry
Then add:
require 'pry'; binding.pry
into your program.
As of pry
0.12.2 however, there are no navigation commands such as next
, break
, etc. Some other gems additionally provide this, see for example pry-byebug
.
In Ruby:
ruby -rdebug myscript.rb
then,
b <line>
: put break-point- and
n(ext)
ors(tep)
andc(ontinue)
p(uts)
for display
(like perl debug)
In Rails: Launch the server with
script/server --debugger
and add
debugger
in the code.
As banister recommended: use pry! I can only agree on this.
pry is a much better repl than irb.
You need to add
require 'pry'
to your source file and then insert a breakpoint in your source code by adding
binding.pry
at the place where you want to have a look at the things (this is like triggering a breakpoint in a classic IDE environment)
Once your program hits the
binding.pry
line, you'll be thrown right into the pry repl, with all the context of your program right at hand, so that you can simply explore everything around, investigate all objects, change state, and even change code on the fly.
I believe you can not change the code of the method that you are currently in, so you can sadly not change the next line to be executed. But good ruby code tends to be single line anyway ;-)
Debugging by raising exceptions is far easier than squinting through print
log statements, and for most bugs, its generally much faster than opening up an irb debugger like pry
or byebug
. Those tools should not always be your first step.
Debugging Ruby/Rails Quickly:
1. Fast Method: Raise an Exception
then and .inspect
its result
The fastest way to debug Ruby (especially Rails) code is to raise
an exception along the execution path of your code while calling .inspect
on the method or object (e.g. foo
):
raise foo.inspect
In the above code, raise
triggers an Exception
that halts execution of your code, and returns an error message that conveniently contains .inspect
information about the object/method (i.e. foo
) on the line that you're trying to debug.
This technique is useful for quickly examining an object or method (e.g. is it nil
?) and for immediately confirming whether a line of code is even getting executed at all within a given context.
2. Fallback: Use a ruby IRB debugger like byebug
or pry
Only after you have information about the state of your codes execution flow should you consider moving to a ruby gem irb debugger like pry
or byebug
where you can delve more deeply into the state of objects within your execution path.
General Beginner Advice
When you are trying to debug a problem, good advice is to always: Read The !@#$ing Error Message (RTFM)
That means reading error messages carefully and completely before acting so that you understand what it's trying to tell you. When you debug, ask the following mental questions, in this order, when reading an error message:
- What class does the error reference? (i.e. do I have the correct object class or is my object
nil
?) - What method does the error reference? (i.e. is their a type in the method; can I call this method on this type/class of object?)
- Finally, using what I can infer from my last two questions, what lines of code should I investigate? (remember: the last line of code in the stack trace is not necessarily where the problem lies.)
In the stack trace pay particular attention to lines of code that come from your project (e.g. lines starting with app/...
if you are using Rails). 99% of the time the problem is with your own code.
To illustrate why interpreting in this order is important...
E.g. a Ruby error message that confuses many beginners:
You execute code that at some point executes as such:
@foo = Foo.new
...
@foo.bar
and you get an error that states:
undefined method "bar" for Nil:nilClass
Beginners see this error and think the problem is that the method bar
is undefined. It's not. In this error the real part that matters is:
for Nil:nilClass
for Nil:nilClass
means that @foo
is Nil! @foo
is not a Foo
instance variable! You have an object that is Nil
. When you see this error, it's simply ruby trying to tell you that the method bar
doesn't exist for objects of the class Nil
. (well duh! since we are trying to use a method for an object of the class Foo
not Nil
).
Unfortunately, due to how this error is written (undefined method "bar" for Nil:nilClass
) its easy to get tricked into thinking this error has to do with bar
being undefined
. When not read carefully this error causes beginners to mistakenly go digging into the details of the bar
method on Foo
, entirely missing the part of the error that hints that the object is of the wrong class (in this case: nil). It's a mistake that's easily avoided by reading error messages in their entirety.
Summary:
Always carefully read the entire error message before beginning any debugging. That means: Always check the class type of an object in an error message first, then its methods, before you begin sleuthing into any stacktrace or line of code where you think the error may be occurring. Those 5 seconds can save you 5 hours of frustration.
tl;dr: Don't squint at print logs: raise exceptions or use an irb debugger instead. Avoid rabbit holes by reading errors carefully before debugging.
Print out the variables whenever possible. (This is called printf debugging) You can do this by running
STDERR.puts x.inspect
or
STDERR.puts "Variable x is #{x.inspect}"
If you want to make this easier to type, then you may want to use the exemplor gem.
Turn warnings on. If you're running
ruby
then run it with the-w
switch (egruby -w script.rb
). If you're running it from irb, and you're using a version of ruby prior to 1.9.2, type$VERBOSE = true
at the start of your session. If you misspell an instance variable, once warnings are on you'll getwarning: instance variable
@valeus
not initializedUnderstand the concept of a binary chop (the following quote is from Practices of an Agile Developer)
Divide the problem space in half, and see which half contains the problem. Then divide that half in half again, and repeat.
If you're successful with a binary chop, you may find that there's a single line that doesn't do what you expect it to do. For example
[1, 2, 3].include?([1,2])
gives a value of
false
, even though you'd think it'd returntrue
. In that case, you may want to look at the documentation. Web sites for documentation include ruby-doc.org, or APIdock. In the latter case, you'd typeinclude?
next to the magnifying glass near the top right corner, choose theinclude?
which hasArray
underneath it (if you don't know what class[1, 2, 3]
is, type[1, 2, 3].class
in irb), and you get to include? (Array), which describes what it does.However, if the documentation doesn't help, you're more likely to get a good answer if you can ask a question on how a specific line isn't doing what it should, rather than why an entire script isn't doing what it should.
To easily debug Ruby shell script, just change its first line from:
#!/usr/bin/env ruby
to:
#!/usr/bin/env ruby -rdebug
Then every time when debugger console is shown, you can choose:
c
for Continue (to the next Exception, breakpoint or line with:debugger
),n
for Next line,w
/where
to Display frame/call stack,l
to Show the current code,cat
to show catchpoints.h
for more Help.
See also: Debugging with ruby-debug, Key shortcuts for ruby-debug gem.
In case the script just hangs and you need a backtrace, try using lldb
/gdb
like:
echo 'call (void)rb_backtrace()' | lldb -p $(pgrep -nf ruby)
and then check your process foreground.
Replace lldb
with gdb
if works better. Prefix with sudo
to debug non-owned process.
I just discovered this gem ( turns Pry into a debugger for MRI Ruby 2.0+ )
https://github.com/deivid-rodriguez/pry-byebug
Install with:
gem install pry-byebug
then use exactly like pry
, mark the line you want to break at:
require 'pry'; binding.pry
Unlike vanilla pry however, this gem has some key GDB-like navigation commands such as next
, step
and break
:
break SomeClass#run # Break at the start of `SomeClass#run`.
break Foo#bar if baz? # Break at `Foo#bar` only if `baz?`.
break app/models/user.rb:15 # Break at line 15 in user.rb.
break 14 # Break at line 14 in the current file.
I strongly recommend this video, in order to pick the proper tool at the moment to debug our code.
https://www.youtube.com/watch?v=GwgF8GcynV0
Personally, I'd highlight two big topics in this video.
- Pry is awesome for debug data, "pry is a data explorer" (sic)
- Debugger seems to be better to debug step by step.
That's my two cents!
All other answers already give almost everything... Just a little addition.
If you want some more IDE-like debugger (non-CLI) and are not afraid of using Vim as editor, I suggest Vim Ruby Debugger plugin for it.
Its documentation is pretty straightforward, so follow the link and see. In short, it allows you to set breakpoint at current line in editor, view local variables in nifty window on pause, step over/into — almost all usual debugger features.
For me it was pretty enjoyable to use this vim debugger for debugging a Rails app, although rich logger abilities of Rails almost eliminates the need for it.
As of Ruby 2.4.0, it is easier to start an IRB REPL session in the middle of any Ruby program. Put these lines at the point in the program that you want to debug:
require 'irb'
binding.irb
You can run Ruby code and print out local variables. Type Ctrl+D or quit
to end the REPL and let Ruby program keep running.
You can also use puts
and p
to print out values from your program as it is running.
deletes all the things
Welcome to 2017 ^_^
Okay, so if you're not opposed to trying out a new IDE you can do the following for free.
Quick Instructions
- Install vscode
- Install Ruby Dev Kit if you haven't already
- Install Ruby, ruby-linter, and ruby-rubocop extensions for vscode
- Manually install whatever gems rubyide/vscode-ruby specifies, if needed
- Configure your
launch.json
to use"cwd"
and and"program"
fields using the{workspaceRoot}
macro - Add a field called
"showDebuggerOutput"
and set it totrue
- Enable breakpoints everywhere in your Debug preferences as
"debug.allowBreakpointsEverywhere": true
Detailed Instructions
- Download Visual Studio Code aka
vscode
; this is not the same as Visual Studio. It's free, light-weight, and generally positively regarded. - Install the Ruby Dev Kit; you should follow the instructions at their repo here: https://github.com/oneclick/rubyinstaller/wiki/Development-Kit
- Next you can either install extensions via a web browser, or inside the IDE; this is for inside the IDE. If you choose the other, you can go here. Navigate to the Extensions part of vscode; you can do this a couple ways, but the most future-proof method will probably be hitting F1, and typing out ext until an option called Extensions: Install Extensions becomes available. Alternatives are CtrlShiftx and from the top menu bar,
View->Extensions
- Next you're going to want the following extensions; these aren't 100% necessary, but I'll let you decide what to keep after you've tinkered some:
- Ruby; extension author Peng Lv
- ruby-rubocop; extension author misogi
- ruby-linter; extension author Cody Hoover
- Inside your ruby script's directory, we're going to make a directory via command-line called
.vscode
and in there we'll but a file calledlaunch.json
where we're going to store some config options.launch.json
contents
{
"version": "0.2.0",
"configurations":
[
{
"name": "Debug Local File",
"type":"Ruby",
"request": "launch",
"cwd": "${workspaceRoot}",
"program": "{workspaceRoot}/../script_name.rb",
"args": [],
"showDebuggerOutput": true
}
]
}
- Follow the instructions from the extension authors for manual gem installations. It's located here for now: https://github.com/rubyide/vscode-ruby#install-ruby-dependencies
- You'll probably want the ability to put breakpoints wherever you like; not having this option enabled can cause confusion. To do this, we'll go to the top menu bar and select
File->Preferences->Settings
(or Ctrl, ) and scroll until you reach theDebug
section. Expand it and look for a field called"debug.allowBreakpointsEverywhere"
-- select that field and click on the little pencil-looking icon and set it totrue
.
After doing all that fun stuff, you should be able to set breakpoints and debug in a menu similar to this for mid-2017 and a darker theme:
with all the fun stuff like your call stack, variable viewer, etc.The biggest PITA is 1) installing the pre-reqs and 2) Remembering to configure the .vscode\launch.json
file. Only #2 should add any baggage to future projects, and you can just copy a generic enough config like the one listed above. There's probably a more general config location, but I don't know off the top of my head.
- You can print your variables out along the way
- Turn on the
-w
(warnings) flag - Use a tool such as ruby-debug
If you are using RubyMine, debugging ruby scripts is simple and straightforward.
Suppose you have a Ruby script hello_world.rb
1. Set breakpoints
Set a breakpoint at line 6 as below.
2. Start debugging
Now you can just start the debugger to run the script:
3. Inspect variables, etc.
Then when the execution hits a breakpoint, you'll be able to inspect variables, etc.
Further information for your reference
- If you would like to use RubyMine to do remote debugging, you can do so.
- If you would like to use RubyMine to remote debug rails running inside a docker, it is also straightforward.
Well, ruby standard lib has an easy to use gdb-like console debugger: http://ruby-doc.org/stdlib-2.1.0/libdoc/debug/rdoc/DEBUGGER__.html No need to install any extra gems. Rails scripts can be debugged that way too.
e.g.
def say(word)
require 'debug'
puts word
end
printf debugging
There has always been a controversy around debugging techniques, some people like to debug by print statements, some other ones like to dig deep with a debugger.
I'd suggest that you try both approaches.
Actually one of the old Unix men recently said, that printf debugging was a faster way to go for him at some points.
But if you are new at some job and need to understand a big blob of code, then it's really usefull to step throughout there, putting some breakpoints here and there, going along with it how it works.
It should give you some understanding how the code is weaved.
If you are new to some other peoples software, It might help you to step through there.
You'll quickly find out if they arranged it in a clever way, or if that's just a bunch of shit.
The mother of all debugger is plain old print screen. Most of the time, you probably only want to inspect some simple objects, a quick and easy way is like this:
@result = fetch_result
p "--------------------------"
p @result
This will print out the contents of @result to STDOUT with a line in front for easy identification.
Bonus if you use a autoload / reload capable framework like Rails, you won't even need to restart your app. (Unless the code you are debugging is not reloaded due to framework specific settings)
I find this works for 90% of the use case for me. You can also use ruby-debug, but I find it overkill most of the time.
There is many debuggers with different features, based on which you make choice. My priorities was satisfied with pry-moves which was:
- quickly comprehensible info on how to use
- intuitive steps (like easy stepping into blocks)
- "stepping back" (pry-moves partially satisfies the need)
精彩评论