Issue: RubyMine Debugging (Debugger.Start is not called yet.)

10.11.2011 08:39 by kbeckman | Comments

Every once in a while, a little bit of collective thought during the “impediments” portion of the daily scrum yields some immediate results…

 

Overview

A portion of our development team uses RubyMine as the primary source code editor / IDE for Ruby development. Our team lead (the other guy) is more of a purist and boasts a status of VIM Power User never leaving the Terminal window. Recently, RubyMine’s debugging capabilities just stopped working on both of our active Rails projects. More specifically, every time we attempted to use RubyMine’s debugger to launch a single spec or cuke with breakpoints set, the entire test file failed. Even tests that should have passed failed to execute while everything worked perfectly from the command line. The stack trace revealed nothing more than a cryptic error like the one below. I shortened it a bit to include only the important items. Pay special attention to “RuntimeError: Debugger.start is not yet called.”

/Users/kbeckman/.rvm/rubies/ruby-1.9.2-p180/bin/ruby -e at_exit{sleep(1)};$stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/ruby-debug-ide-0.4.17.beta5/bin/rdebug-ide --port 49226 -- /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/bin/rspec /Users/kbeckman/Sites/Project/spec/models/post_spec.rb --require teamcity/spec/runner/formatter/teamcity/formatter --format Spec::Runner::Formatter::TeamcityFormatter
Testing started at 10:20 PM ...
Fast Debugger (ruby-debug-ide 0.4.17.beta5, ruby-debug-base 0.11.28) listens on 127.0.0.1:49226
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/ruby-debug-base19-0.11.24/lib/ruby_debug.bundle: warning: already initialized constant VERSION

RuntimeError: Debugger.start is not called yet.
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/ruby-debug19-0.11.6/cli/ruby-debug/processor.rb:130:in `breakpoints'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/ruby-debug19-0.11.6/cli/ruby-debug/processor.rb:130:in `at_breakpoint'
(eval):5:in `block in at_breakpoint'
<internal:prelude>:10:in `synchronize'
(eval):3:in `at_breakpoint'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/ruby-debug-base19-0.11.24/lib/ruby-debug-base.rb:42:in `at_breakpoint'
/Users/kbeckman/Sites/Project/spec/models/post_spec.rb:6:in `block (2 levels) in <top (required)>'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/hooks.rb:29:in `instance_eval'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/hooks.rb:29:in `run_in'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/hooks.rb:64:in `run_all!'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/hooks.rb:112:in `run_hook!'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/example_group.rb:176:in `eval_before_alls'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/example_group.rb:230:in `run'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/command_line.rb:27:in `block (2 levels) in run'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/command_line.rb:27:in `map'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/command_line.rb:27:in `block in run'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/reporter.rb:12:in `report'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/command_line.rb:24:in `run'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/runner.rb:55:in `run_in_process'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/runner.rb:46:in `run'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/rspec-core-2.3.1/lib/rspec/core/runner.rb:10:in `block in autorun'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/ruby-debug-ide-0.4.17.beta5/lib/ruby-debug-ide.rb:112:in `debug_load'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/ruby-debug-ide-0.4.17.beta5/lib/ruby-debug-ide.rb:112:in `debug_program'
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180@Project/gems/ruby-debug-ide-0.4.17.beta5/bin/rdebug-ide:87:in `<top (required)>'
-e:1:in `load'
-e:1:in `<main>'

2 examples, 2 failures, 0 passed

Finished in 0.002311 seconds

Process finished with exit code 0

 

Investigation

Back to the “impediments” portion of the daily scrum… This issue was brought to everyone’s attention and we chatted about it for a couple of minutes. Since he wasn’t using RubyMine, our team lead was the only developer not having any issues with debugging. We soon discovered a few days ago he added a require statement for the ruby-debug gem in our RSpec spec_helper.rb file. Bingo!

 

Resolution

It turns out that RubyMine automatically adds its own reference to the ruby-debug gem during its debugging process. With the new reference in our spec_helper.rb file, all RubyMine users had a dual reference (RubyMine’s version and to our project version in the RVM gemset). The runtime was unable to determine which gem version to use for debugging. With the issue discovered, the solution is easy. Adding a conditional statement in spec_helper.rb to ignore the ruby-debug reference (for RubyMine users only) solves the problem.

 

Step 1 – Set a Mac Environment Variable Indicating RubyMine Usage

Here’s a link to a System Preferences plug-in allowing you edit system environment variables via a GUI dialog. Or you can follow the steps in this post to manually edit your environment variables file. For documentation’s sake, here’s what my .MacOSX/environment.plist file looks like.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>USE_RUBYMINE</key>
    <string>TRUE</string>
</dict>
</plist>

 

Step 2 – Update spec_helper.rb to Conditionally Add the ruby-debug Gem

require 'rubygems'
require 'spork'
require 'webmock/rspec'
unless ENV["USE_RUBYMINE"] == "TRUE"
  require 'ruby-debug'
end

Issue: RubyMine 3.1, Webmock-1.6.2 and “Spec.configure” curse

05.26.2011 00:01 by kbeckman | Comments

I ran into a nasty issue today – an issue that I have no problem saying would have been way past my abilities to resolve given my current status as a Ruby Noobie. Thank goodness for team members who are way more knowledgeable than I am! I’ll try to do my best here to set up the environment context that produced the issue and follow the steps we (“we” is used loosely here because I didn’t help much) used to resolve the issue…

 

Overview

I kept getting a error while trying to use RubyMine’s integrated debugger to test some of the changes I made to a Rails controller class. Here’s the full console output from the RubyMine debugger…

 

/Users/kbeckman/.rvm/rubies/ruby-1.9.2-p180/bin/ruby -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180/bin/rspec /Users/kbeckman/<ApplicationDir>/spec/controllers/profile_controller_spec.rb --require teamcity/spec/runner/formatter/teamcity/formatter --format Spec::Runner::Formatter::TeamcityFormatter
Testing started at 9:28 PM ...
/Users/kbeckman/.rvm/gems/ruby-1.9.2-p180/gems/webmock-1.6.2/lib/webmock/rspec.rb:23:in `<top (required)>': undefined method `configure' for Spec::Runner:Module (NoMethodError)
    from /Users/kbeckman/<ApplicationDir>/spec/spec_helper.rb:4:in `require'
    from /Users/kbeckman/<ApplicationDir>/spec/spec_helper.rb:4:in `<top (required)>'
    from /Users/kbeckman/<ApplicationDir>/spec/controllers/profile_controller_spec.rb:1:in `require'
    from /Users/kbeckman/<ApplicationDir>/spec/controllers/profile_controller_spec.rb:1:in `<top (required)>'
    from /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.3.1/lib/rspec/core/configuration.rb:388:in `load'
    from /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.3.1/lib/rspec/core/configuration.rb:388:in `block in load_spec_files'
    from /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.3.1/lib/rspec/core/configuration.rb:388:in `map'
    from /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.3.1/lib/rspec/core/configuration.rb:388:in `load_spec_files'
    from /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.3.1/lib/rspec/core/command_line.rb:18:in `run'
    from /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.3.1/lib/rspec/core/runner.rb:55:in `run_in_process'
    from /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.3.1/lib/rspec/core/runner.rb:46:in `run'
    from /Users/kbeckman/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.3.1/lib/rspec/core/runner.rb:10:in `block in autorun'
Empty test suite.

Process finished with exit code 1

 

Investigation

Below is the /webmock-1.6.2/lib/webmock/rspec.rb where the actual exception was being thrown… And here’s why:

a) On line 4, “RSpec” was defined but “RSpec:Expectations” was undefined and the code ran to line 6.

b) On line 6, “Spec” was defined so the contents of the elsif block were executed where some global RSpec variables are set to whatever webmock thinks they should be. This a technique that dynamic languages use to swap out existing functionality for some entirely different implementation. No need for IoC Containers here!

c) The code continues to execute running over the else block (what we really wanted to have execute) and runs to line 23.

d) On line 23, the code blows up because of “undefined method ‘configure’ for Spec::Runner:Module (NoMethodError)”

 

require 'webmock'

# RSpec 1.x and 2.x compatibility
if defined?(RSpec) && defined?(RSpec::Expectations)
  RSPEC_NAMESPACE = RSPEC_CONFIGURER = RSpec
elsif defined?(Spec)
  RSPEC_NAMESPACE = Spec
  RSPEC_CONFIGURER = Spec::Runner
else  
  begin
    require 'rspec/core'
    require 'rspec/expectations'
    RSPEC_NAMESPACE = RSPEC_CONFIGURER = RSpec
  rescue LoadError
    require 'spec'
    RSPEC_NAMESPACE = Spec
    RSPEC_CONFIGURER = Spec::Runner
  end
end

require 'webmock/rspec/matchers'
  
RSPEC_CONFIGURER.configure { |config|

  config.include WebMock::API
  config.include WebMock::Matchers

  config.after(:each) do
    WebMock.reset!
  end
}

WebMock::AssertionFailure.error_class = RSPEC_NAMESPACE::Expectations::ExpectationNotMetError

 

So why did this happen? It turns out that somewhere in RubyMine, a “Spec::Runner” is defined and it doesn’t have the configure() method that we need. If you look at some of the very first heinous highlight above from the stack trace, you’ll notice that RubyMine is using a --require” and “--formatter” command line arguments. The “--require" argument tells Ruby to load whatever is in that directory. I’m not going to go into all of the details, but it has something to do with output formatting for use with JetBrains’ CI server, TeamCity. Whatever is in that directory is causing our problem by defining a “Spec::Runner” before webmock can load a replacement.

 

Resolution

Fixing the issue required a slight modification to the /webmock-1.6.2/lib/webmock/rspec.rb listed above. Here’s our fully modified file. Please note the heinous highlight… We added a check to determine whether or not the “Spec.configure” method was defined since this was the one that was previously throwing the exception. Now the code evaluates “Spec.configure” as undefined and falls through to execute the else block where webmock successfully sets up its requirements using the “Spec” definition from RSpec instead of whatever was in the teamcity/spec/runner/formatter/teamcity/formatter directory. If you’re curious as to what that was in RubyMine’s internals causing the issue, help yourself with the following command. Please note your RubyMine location might differ from mine…

 

cd ~/applications/RubyMine\ 3.1.1.app/rb
grep -R Spec **

 

require 'webmock'

# RSpec 1.x and 2.x compatibility
if defined?(RSpec) && defined?(RSpec::Expectations)
  RSPEC_NAMESPACE = RSPEC_CONFIGURER = RSpec
elsif defined?(Spec) && defined?(Spec.configure)
  RSPEC_NAMESPACE = Spec
  RSPEC_CONFIGURER = Spec::Runner
else  
  begin
    require 'rspec/core'
    require 'rspec/expectations'
    RSPEC_NAMESPACE = RSPEC_CONFIGURER = RSpec
  rescue LoadError
    require 'spec'
    RSPEC_NAMESPACE = Spec
    RSPEC_CONFIGURER = Spec::Runner
  end
end

require 'webmock/rspec/matchers'
  
RSPEC_CONFIGURER.configure { |config|

  config.include WebMock::API
  config.include WebMock::Matchers

  config.after(:each) do
    WebMock.reset!
  end
}

WebMock::AssertionFailure.error_class = RSPEC_NAMESPACE::Expectations::ExpectationNotMetError

 

So, we’re not quite done yet… We’ve fixed the issue by forcing the setup block in the webmock rspec.rb file to execute, but as soon as we run “bundle install” or “gem update webmock” or any of the other countless ways you could probably update webmock’s code we’ll more than likely get the same issue. To make sure that doesn’t happen, we did the following:

a) Copy the entire /webmock-1.6.2 directory our project was originally sourcing the code from into a customization folder we keep per-project. Our new location for webmock is ../<ApplicationDirectory>/vendor/gems/webmock-1.6.2.

b) Edit the project’s gemfile so webmock is sourced from the edited copy rather than a directory that can be easily overwritten/updated. Our gemfile changes for webmock are below… I’ve commented out the old reference for our new location.

c) Make sure you “$ git commit -a” your webmock source directory…

 

...

group :test do
  #gem 'webmock'
  gem 'webmock', :path => "#{File.expand_path(__FILE__)}/../vendor/gems/webmock-1.6.2"
end

...

 

I hope this helps!!!