rspec/rspec-core

rspec doesn't work with Default gem SyntaxSuggest due to not-re-raising SyntaxError

schneems opened this issue · 2 comments

Subject of the issue

The default gem SyntaxSuggest (previously DeadEnd) works to find syntax errors in Ruby code and show you where the error likely lives. This was added in Ruby 3.2 which was just released. Prior to Ruby 3.2 it worked by hooking into require and load. With Ruby 3.2 it has a deeper integration with SyntaxError instead. So to get a helpful error result the SyntaxError must be raised.

This issue with RSpec was reported in ruby/syntax_suggest#171. Here's the root cause:

rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
relative_file = Metadata.relative_path(file)
reporter.notify_non_example_exception(ex, "An error occurred while loading #{relative_file}.")
RSpec.world.wants_to_quit = true

On these lines you can see that the error is swallowed and never re-raised. If you add this line at the end:

      rescue Support::AllExceptionsExceptOnesWeMustNotRescue => ex
        relative_file = Metadata.relative_path(file)
        reporter.notify_non_example_exception(ex, "An error occurred while loading #{relative_file}.")
        RSpec.world.wants_to_quit = true
        raise ex # <===== HERE

The output will be correct:

bundler: failed to load command: rspec (/Users/rubyku/.gem/ruby/3.2.0/bin/rspec)
/Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/configuration.rb:2117:in `load': --> /Users/rubyku/richard/projects/syntax_suggest_sandbox/spec/sample_spec.rb
Unmatched `end', missing keyword (`do', `def`, `if`, etc.) ?
  1  RSpec.describe 'sample' do
> 2    exampledo
> 4    end
  5  end
/Users/rubyku/richard/projects/syntax_suggest_sandbox/spec/sample_spec.rb:5: syntax error, unexpected `end' (SyntaxError)

Your environment

  • Ruby version: 3.2.0
  • rspec-core version: 3.12.0

Steps to reproduce

git clone https://github.com/JunichiIto/syntax_suggest_sandbox
cd syntax_suggest_sandbox
bundle install
bundle exec rspec

Expected behavior

bundler: failed to load command: rspec (/Users/rubyku/.gem/ruby/3.2.0/bin/rspec)
/Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/configuration.rb:2117:in `load': --> /Users/rubyku/richard/projects/syntax_suggest_sandbox/spec/sample_spec.rb
Unmatched `end', missing keyword (`do', `def`, `if`, etc.) ?
  1  RSpec.describe 'sample' do
> 2    exampledo
> 4    end
  5  end
/Users/rubyku/richard/projects/syntax_suggest_sandbox/spec/sample_spec.rb:5: syntax error, unexpected `end' (SyntaxError)

Actual behavior

$ bundle exec rspec

An error occurred while loading ./spec/sample_spec.rb.
Failure/Error: __send__(method, file)

SyntaxError:
  /Users/rubyku/richard/projects/syntax_suggest_sandbox/spec/sample_spec.rb:5: syntax error, unexpected `end'
# /Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/configuration.rb:2117:in `load'
# /Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/configuration.rb:2117:in `load_file_handling_errors'
# /Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/configuration.rb:1617:in `block in load_spec_files'
# /Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/configuration.rb:1615:in `each'
# /Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/configuration.rb:1615:in `load_spec_files'
# /Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/runner.rb:102:in `setup'
# /Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/runner.rb:86:in `run'
# /Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/runner.rb:71:in `run'
# /Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/lib/rspec/core/runner.rb:45:in `invoke'
# /Users/rubyku/.gem/ruby/3.2.0/gems/rspec-core-3.12.0/exe/rspec:4:in `<top (required)>'
# /Users/rubyku/.gem/ruby/3.2.0/bin/rspec:25:in `load'
# /Users/rubyku/.gem/ruby/3.2.0/bin/rspec:25:in `<top (required)>'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/cli/exec.rb:58:in `load'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/cli/exec.rb:58:in `kernel_load'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/cli/exec.rb:23:in `run'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/cli.rb:491:in `exec'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/cli.rb:34:in `dispatch'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/cli.rb:28:in `start'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.1/libexec/bundle:45:in `block in <top (required)>'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/3.2.0/bundler/friendly_errors.rb:117:in `with_friendly_errors'
# /Users/rubyku/.rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.1/libexec/bundle:33:in `<top (required)>'
# /Users/rubyku/.rubies/ruby-3.2.0/bin/bundle:25:in `load'
# /Users/rubyku/.rubies/ruby-3.2.0/bin/bundle:25:in `<main>'

I'm out on vacation right now with my family otherwise I would have sent a patch. I still wanted to leave an issue. Hopefully someone else can pick it up and test my one line fix to see if tests still pass. There is likely a good reason the error isn't re-raised which needs investigation and possibly some work. If no one can get to it, then I'll try to make a patch later, but it won't be soon.

I think we just need to add SyntaxError as a special case no? We don't want to raise other errors, thats the whole point of capturing them, so either we never rescue SyntaxError (add it to the list we already maintain for SystemExit et al) or we only re-raise that one error.

Seems good. If needed: We can also gate on the SyntaxError#respond_to?(:path) which is not present prior to Ruby 3.2