You might have run, or might run in the future (or never run for that mater)
into the following issue. Let's do bundle init, create 1.rb:
require 'rubygems'
require 'bundler'
Bundler.setup(:default)Then add require 'byebug'; debugger to the beginning of the
Bundler.setup method, and run it with ruby 1.rb.
That gives us:
Traceback (most recent call last):
10920: from 1.rb:7:in `<main>'
10919: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:106:in `setup'
10918: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:127:in `require'
10917: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:106:in `setup'
10916: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:127:in `require'
10915: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:106:in `setup'
10914: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:127:in `require'
10913: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:106:in `setup'
... 10908 levels...
4: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:127:in `require'
3: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:106:in `setup'
2: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:127:in `require'
1: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:106:in `setup'
/home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:127:in `require': stack level too deep (SystemStackError)
So we see that Bundler module has require method that was called
in place of the usual one we expected.
Let's execute it within the top-level context then:
TOPLEVEL_BINDING.eval("require 'byebug'"); debuggerBut Bundler.require somehow gets called again:
Traceback (most recent call last):
11232: from 1.rb:7:in `<main>'
11231: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:109:in `setup'
11230: from /home/yuri/.gem/ruby/2.6.3/gems/byebug-11.0.1/lib/byebug/attacher.rb:36:in `byebug'
11229: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:130:in `require'
11228: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:109:in `setup'
11227: from /home/yuri/.gem/ruby/2.6.3/gems/byebug-11.0.1/lib/byebug/attacher.rb:36:in `byebug'
11226: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:130:in `require'
11225: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:109:in `setup'
... 11220 levels...
4: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:107:in `eval'
3: from <main>:in `<main>'
2: from /home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:36:in `require'
1: from /home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:36:in `puts'
/home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:36:in `puts': stack level too deep (SystemStackError)To understand that we've got to know a little about how byebug works.
byebug.rb is not particularly big:
require_relative "byebug/attacher"...
module Kernel
def byebug
require "byebug/core"
Byebug.attach unless Byebug.mode == :off
end
alias debugger byebug
...So, calling debugger from Bundler.setup leads to require 'byebug/core'.
And the thing is, self is Bundler when the last statement gets invoked.
Let's invoke the debugger this way then:
TOPLEVEL_BINDING.eval("require 'byebug'; debugger")
This time everything goes as planned:
[107, 116] in /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb
107: # TOPLEVEL_BINDING.eval("require 'byebug'")
108: puts '-' * 10
109: # debugger
110: TOPLEVEL_BINDING.eval("require 'byebug'; debugger")
111: # Return if all groups are already loaded
=> 112: return @setup if defined?(@setup) && @setup
113:
114: definition.validate_runtime!
115:
116: SharedHelpers.print_major_deprecations!
(byebug) cBut that's not all. The funny thing about bundler is that it cleans up
$LOAD_PATH at some point. $LOAD_PATH to ruby is what PATH is to your
average shell. It's a list of paths relative to which ruby resolves
arguments to require. So, let's leave the statement we added
at the beginning of Bundler.setup method, and add our customary
TOPLEVEL_BINDING.eval("require 'byebug'; debugger") after
the following line. That results into:
Traceback (most recent call last):
6: from 1.rb:7:in `<main>'
5: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:122:in `setup'
4: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler/runtime.rb:21:in `setup'
3: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler/runtime.rb:21:in `eval'
2: from <main>:in `<main>'
1: from /home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:56:in `require'
/home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:56:in `require': cannot load such file -- byebug (LoadError)
7: from 1.rb:7:in `<main>'
6: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:122:in `setup'
5: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler/runtime.rb:21:in `setup'
4: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler/runtime.rb:21:in `eval'
3: from <main>:in `<main>'
2: from /home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:34:in `require'
1: from /home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:132: in `rescue in require'
/home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:132:in `require': cannot load such file -- byebug (LoadError)
The output is a bit funny, but one can argue that ruby tries to
require byebug, fails because
it's not in the $LOAD_PATH, tries to activate it, and
requires it again hoping that
corresponding gem's lib dir was added to $LOAD_PATH.
A little stepaside here to explain things. Activating a gem is choosing
a version of the gem, and adding
its lib dir to $LOAD_PATH. Every time you require the first file
from an installed gem, it goes through this
require—rescue—activate—require routine. The second file gets required
right away, since corresponding gem's lib
dir is already in $LOAD_PATH.
But the thing is we've already required—and hence activated—byebug gem before.
After which bundler removed its dir from $LOAD_PATH. So, now it's marked
as activated, and as such rubygems doesn't
add it to $LOAD_PATH again. Therefore, when it comes to requiring
the file again, it fails.
Okay, let's not require byebug twice:
Traceback (most recent call last):
7: from 1.rb:7:in `<main>'
6: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:122:in `setup'
5: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler/runtime.rb:21:in `setup'
4: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler/runtime.rb:21:in `eval'
3: from <main>:in `<main>'
2: from /home/yuri/.gem/ruby/2.6.3/gems/byebug-11.0.1/lib/byebug/attacher.rb:36:in `byebug'
1: from /home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:56:in `require'
/home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:56:in `require': cannot load such file -- byebug/core (LoadError)
8: from 1.rb:7:in `<main>'
7: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler.rb:122:in `setup'
6: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler/runtime.rb:21:in `setup'
5: from /home/yuri/.gem/ruby/2.6.3/gems/bundler-2.0.2/lib/bundler/runtime.rb:21:in `eval'
4: from <main>:in `<main>'
3: from /home/yuri/.gem/ruby/2.6.3/gems/byebug-11.0.1/lib/byebug/attacher.rb:36:in `byebug'
2: from /home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:34:in `require'
1: from /home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:136: in `rescue in require'
/home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:136:in `require': cannot load such file -- byebug/core (LoadError)
We've moved on a bit, but now the issue is with Kernel.byebug requiring byebug/core. So,
let's add byebug back. In my case that would be:
clean_load_path
$LOAD_PATH.unshift(
"/home/yuri/.gem/ruby/2.6.3/gems/byebug-11.0.1/lib",
"/home/yuri/.gem/ruby/2.6.3/extensions/x86_64-linux/2.6.0-static/byebug-11.0.1")
TOPLEVEL_BINDING.eval("debugger")And that worked. But couldn't we just add byebug to the Gemfile? Well,
that would help to some extent. Meaning,
with byebug in the Gemfile bundler would add byebug's lib dir to
$LOAD_PATH at some point. But that leaves
the following zone uncovered. To be able to put debugger
between those lines, We've got to add byebug
to $LOAD_PATH.
Happy debugging :)