Skip to content

Commit

Permalink
[close #31] Annotate syntax error without require
Browse files Browse the repository at this point in the history
As pointed out in #31 the current version of dead_end only works if the developer requires dead_end and then invokes `require`. This PR takes advantage of this change in Ruby 3.2 ruby/ruby#5516 to modify the `SyntaxError` directly. 

This behavior will only be fixed for Ruby 3.2+ 

Additionally we are still not able to handle the case where a program is streamed to ruby and does not exist on disk:

```
$ echo "def foo" | ruby
```

As the SyntaxError does not provide us with the contents of the script.

```
$ echo "def foo" | ruby
-:1: syntax error, unexpected end-of-input
def foo
```
  • Loading branch information
schneems committed May 18, 2022
1 parent 45349f3 commit 449afb8
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 28 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## HEAD (unreleased)

- Support Ruby 3.2 integration with SyntaxError (https://github.com/zombocom/dead_end/pull/139)

## 3.1.2

- Fixed internal class AroundBlockScan, minor changes in outputs (https://github.com/zombocom/dead_end/pull/131)
Expand Down
80 changes: 52 additions & 28 deletions lib/dead_end/core_ext.rb
Original file line number Diff line number Diff line change
@@ -1,35 +1,59 @@
# frozen_string_literal: true

# Monkey patch kernel to ensure that all `require` calls call the same
# method
module Kernel
module_function

alias_method :dead_end_original_require, :require
alias_method :dead_end_original_require_relative, :require_relative
alias_method :dead_end_original_load, :load

def load(file, wrap = false)
dead_end_original_load(file)
rescue SyntaxError => e
DeadEnd.handle_error(e)
end
if SyntaxError.new.respond_to?(:detailed_message)
require "stringio"

def require(file)
dead_end_original_require(file)
rescue SyntaxError => e
DeadEnd.handle_error(e)
end
SyntaxError.prepend Module.new {
def detailed_message(highlight: nil, **)
message = super

if (file = PathnameFromMessage.new(e.message, io: io).call.name)
io = StringIO.new
DeadEnd.call(
io: io,
source: file.read,
filename: file
)
annotation = io.string

annotation + message
else
message
end
end
}
else
# Monkey patch kernel to ensure that all `require` calls call the same
# method
module Kernel
module_function

alias_method :dead_end_original_require, :require
alias_method :dead_end_original_require_relative, :require_relative
alias_method :dead_end_original_load, :load

def load(file, wrap = false)
dead_end_original_load(file)
rescue SyntaxError => e
DeadEnd.handle_error(e)
end

def require(file)
dead_end_original_require(file)
rescue SyntaxError => e
DeadEnd.handle_error(e)
end

def require_relative(file)
if Pathname.new(file).absolute?
dead_end_original_require file
else
relative_from = caller_locations(1..1).first
relative_from_path = relative_from.absolute_path || relative_from.path
dead_end_original_require File.expand_path("../#{file}", relative_from_path)
def require_relative(file)
if Pathname.new(file).absolute?
dead_end_original_require file
else
relative_from = caller_locations(1..1).first
relative_from_path = relative_from.absolute_path || relative_from.path
dead_end_original_require File.expand_path("../#{file}", relative_from_path)
end
rescue SyntaxError => e
DeadEnd.handle_error(e)
end
rescue SyntaxError => e
DeadEnd.handle_error(e)
end
end

0 comments on commit 449afb8

Please # to comment.