-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[close #31] Annotate syntax error without require
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
Showing
2 changed files
with
54 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |