The ruby debugger does not halt on breakpoints I set in files different from the on the execution starts in. For example, consider these two files, foo.rb:
# foo.rb
class Foo
def bar
puts "baz"
end
end
and main.rb:
# main.rb
require './foo'
Foo.new.bar
I start debugging using ruby -r debug .\main.rb. Now, when I try to set a breakpoint on a specific line in another file using b ./foo.rb:4, I get the message Set breakpoint 1 at foo.rb:4, but when I cont, the program executes to the end, and the debugger never halts. However, if I break on a line in main.rb, e.g. b ./main.rb:3, or a method, e.g. b Foo.bar, the debugger halts as expected.
Why doesn't the debugger halt at breakpoints in files other than the main file?
Update: I have tried this with Ruby 1.9.3 on Windows 7 as well as OS X 10.8; it doesn't work in either environment.
I have also just realized that the debugger quits after the script has run till the end: I start debugging main.rb, use cont, then baz is printed on the console and I'm right back in the shell. Is this the expected behaviour, or might the debugger have crashed?
Wow, that is weird. Not sure if this helps, but maybe you could do this. Step over the require with next so that Foo is loaded then
b Foo:bar
that should at least break on bar
Related
# myapp.rb
myvar = 'Hello'
myvar += ' world'
myvar += '!'
puts myvar
puts 'Bye!'
Trying to debug it:
>ruby -rdebug myapp.rb
<...>/ruby-2.7.2-1/lib/ruby/2.7.0/x64-mingw32/continuation.so: warning: callcc is obsolete; use Fiber instead
Debug.rb
Emacs support available.
<...>/ruby-2.7.2-1/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:172: if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?)
(rdb:1) help
Debugger help v.-0.002b
Commands
b[reak] [file:|class:]<line|method>
b[reak] [class.]<line|method>
set breakpoint to some position
. . .
c[ont] run until program ends or hit breakpoint
. . .
Ok, let's do it:
(rdb:1) b myapp.rb:1
Set breakpoint 1 at D:/temp/r/myapp.rb:1
(rdb:1) cont
Hello world!
Bye!
Actual behavior: doesn't stop at breakpoints.
Expected behavior: must stop at breakpoints.
Used gdb for C/C++ and pdb for Python. They have similar interface and work.
The questions are:
Please tell if you can reproduce this problem.
What is the reason of this problem?
Is this a bug or a feature?
How to make the debugger stop at breakpoints?
Could not google the answer. There's an example here (in the end of the page) that, to my mind, doesn't expressly show the expected breakpoint behavior. As the author didn't demonstrate this simple and obvious use case then there must be a problem here.
UPDATE
Checked in Linux -- works as expected.
Try specifying the absolute filename of the program, in other words try running the program as ruby -rdebug $PWD/myapp.rb
I posted a bug report for version 2.7.2 just now:
https://bugs.ruby-lang.org/issues/17492?next_issue_id=17491
Tried with a previous version of Ruby 2.5.3 -- works as expected. The same is on Linux:
$ ruby -rdebug myapp.rb
/usr/lib/x86_64-linux-gnu/ruby/2.5.0/continuation.so: warning: callcc is obsolete; use Fiber instead
Debug.rb
Emacs support available.
myapp.rb:1:myvar = 'Hello'
(rdb:1) b 3
Set breakpoint 1 at myapp.rb:3
(rdb:1) c
Breakpoint 1, toplevel at myapp.rb:3
myapp.rb:3:myvar += '!'
Probably the problem is in the new version or with my installation in Windows.
If I have file.rb:
puts "Hello, World"
then in irb type:
require "./file.rb"
the output will be Hello, World.
Why then, if I have a sinatra file, e.g.
require "sinatra"
get "/" do
return "Hi"
end
and require that, there is no output?
Clarification
What executing the sinatra file via ruby sinatra_app.rb it will start a rack server, and not stop until CTRL+C is pressed. Why does it not do that when required in irb, but it does do that when it is explicitly run with ruby sinatra_app.rb?
Because the script doesn't output anything. There is nothing in the script you showed that would generate any sort of output, there are no calls to print, puts, or p, no writes to any file, nothing.
The first script prints something when required, because it prints something, the second prints nothing when required because, well, it prints nothing. Remove the call to puts from the first script and it won't print anything either. Add a call to puts to the second script and it will print something.
Workaround is require sinatra before requiring file.
Root file:
require "sinatra"
require "/tmp/ddd.rb"
Required file:
get "/" do
return "Hi"
end
I guess it's somehow related to Sinatra startup process. They put get method in default namespace, without namespacing it to separate module.
I have the following script in a file called foo.rb
def foo(msg)
msg
end
def bar
thing = 123
thing
end
debugger
p foo(:hai)
I run the program in debug mode, like so:
ruby --debug -r debug foo.rb
Notice I make sure the stdlib debug is loaded via -r and I also put the ruby environment into debug mode using --debug
So the first output I get is unexpected:
Debug.rb
Emacs support available.
/Users/M/.rbenv/versions/2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:57: RUBYGEMS_ACTIVATION_MONITOR.enter
After that, if I press c to 'continue' the program ends with the following error:
Exception `NameError' at foo.rb:10 - undefined local variable or method `debugger' for main:Object foo.rb:10:in `<main>': undefined local variable or method `debugger' for main:Object (NameError)
Can anyone tell me what I'm doing wrong, and how to actually get debug mode to recognise the relevant debugger command (if that's even the correct command to be using; the docs aren't clear at all on this)
Note: I'm not interested in using 3rd party gems in this instance (e.g. pry or ruby-debug). I'm only interested in understanding how to use the stdlib debugger that comes with Ruby
Update
Since this question was answered, I've gone ahead and created a gist for future reference. For anyone stumbling across this thread you might find it useful: https://gist.github.com/Integralist/5658cb218bb50494a1fa
Don't use -r. The entire mechanism by which an interactive debugging sessions is loaded is by the literal line of code require 'debug'.
Your code should look like this:
def foo(msg)
msg
end
def bar
thing = 123
thing
end
require 'debug'
p foo(:hai)
And you should run the program by simply typing ruby <program_name>.rb.
SciTE version is 2.25.
I have some ruby code to test it.
def foo
puts "hello"
sleep 5
puts "world"
end
puts foo
SciTE's output pane will show this:
>ruby scite.rb
And 5 seconds later print:
hello
world
>Exit code: 0
It's not correct and I remember the previous version SciTE is right. Why?
Try putting STDOUT.sync = true at the beginning of your program. I'm neither a Windows nor SciTE user, but I know that some of our students at Rubylearning had similar problems and apparently that was the fix (or manual calls to flush after outputting something).
Can I drop to an IRB prompt from a running Ruby script?
I want to run a script, but then have it give me an IRB prompt at a point in the program with the current state of the program, but not just by running rdebug and having a breakpoint.
Pry (an IRB alternative) also lets you do this, in fact it was designed from the ground up for exactly this use case :)
It's as easy as putting binding.pry at the point you want to start the session:
require 'pry'
x = 10
binding.pry
And inside the session:
pry(main)> puts x
=> 10
Check out the website: http://pry.github.com
Pry let's you:
drop into a session at any point in your code
view method source code
view method documentation (not using RI so you dont have to pre-generate it)
pop in and out of different contexts
syntax highlighting
gist integration
view and replay history
open editors to edit methods using edit obj.my_method syntax
A tonne more great and original features
you can use ruby-debug to get access to irb
require 'rubygems'
require 'ruby-debug'
x = 23
puts "welcome"
debugger
puts "end"
when program reaches debugger you will get access to irb.
apparently it requires a chunk of code to drop into irb.
Here's the link (seems to work well).
http://jameskilton.com/2009/04/02/embedding-irb-into-your-ruby-application
require 'irb'
module IRB
def self.start_session(binding) # call this method to drop into irb
unless #__initialized
args = ARGV
ARGV.replace(ARGV.dup)
IRB.setup(nil)
ARGV.replace(args)
#__initialized = true
end
workspace = WorkSpace.new(binding)
irb = Irb.new(workspace)
#CONF[:IRB_RC].call(irb.context) if #CONF[:IRB_RC]
#CONF[:MAIN_CONTEXT] = irb.context
catch(:IRB_EXIT) do
irb.eval_input
end
end
end
This feature is available from Ruby 2.4. You can just use binding.irb
E.g.
require 'irb'
a = 10
binding.irb
puts a
If you run above code, you will get irb console, so that you can inspect values of local variables and anything else that is in scope.
Source: http://blog.redpanthers.co/new-binding-irb-introduced-ruby-2-4/
Ruby commit: https://github.com/ruby/ruby/commit/493e48897421d176a8faf0f0820323d79ecdf94a
Just add this line to where you want the breakpoint:
require 'ruby-debug';debugger
but i suggest use pry instead of irb, which is super handy, insert the following line instead:
require 'pry'; binding.pry
I'm quite late to the game but if you're loading a script from within irb/pry already, a simple raise also works to pop you back out to the irb/pry prompt. I use this quite often when writing one off scripts within the rails console.