Skip to content

Commit

Permalink
Make ErrorHighlight.spot accept Exception (#25)
Browse files Browse the repository at this point in the history
... and move things from core_ext.rb to base.rb.
This will confine CRuby-dependent things to ErrorHighlight.spot.
  • Loading branch information
mame authored Aug 10, 2022
1 parent 671b7c6 commit 22d1dd7
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 38 deletions.
58 changes: 51 additions & 7 deletions lib/error_highlight/base.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
require_relative "version"

module ErrorHighlight
# Identify the code fragment that seems associated with a given error
# Identify the code fragment at that a given exception occurred.
#
# Arguments:
# node: RubyVM::AbstractSyntaxTree::Node (script_lines should be enabled)
# point_type: :name | :args
# name: The name associated with the NameError/NoMethodError
# Options:
#
# point_type: :name | :args
# :name (default) points the method/variable name that the exception occurred.
# :args points the arguments of the method call that the exception occurred.
#
# backtrace_location: Thread::Backtrace::Location
# It locates the code fragment of the given backtrace_location.
# By default, it uses the first frame of backtrace_locations of the given exception.
#
# Returns:
# {
Expand All @@ -15,9 +20,47 @@ module ErrorHighlight
# last_lineno: Integer,
# last_column: Integer,
# snippet: String,
# script_lines: [String],
# } | nil
def self.spot(...)
Spotter.new(...).spot
def self.spot(obj, **opts)
case obj
when Exception
exc = obj
opts = { point_type: opts.fetch(:point_type, :name) }

loc = opts[:backtrace_location]
unless loc
case exc
when TypeError, ArgumentError
opts[:point_type] = :args
end

locs = exc.backtrace_locations
return nil unless locs

loc = locs.first
return nil unless loc

opts[:name] = exc.name if NameError === obj
end

node = RubyVM::AbstractSyntaxTree.of(loc, keep_script_lines: true)

Spotter.new(node, **opts).spot

when RubyVM::AbstractSyntaxTree::Node
# Just for compatibility
Spotter.new(node, **opts).spot

else
raise TypeError, "Exception is expected"
end

rescue SyntaxError,
SystemCallError, # file not found or something
ArgumentError # eval'ed code

return nil
end

class Spotter
Expand Down Expand Up @@ -122,6 +165,7 @@ def spot
last_lineno: @end_lineno,
last_column: @end_column,
snippet: @snippet,
script_lines: @node.script_lines,
}
else
return nil
Expand Down
33 changes: 3 additions & 30 deletions lib/error_highlight/core_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,9 @@
module ErrorHighlight
module CoreExt
private def generate_snippet
locs = backtrace_locations
return "" unless locs

loc = locs.first
return "" unless loc

begin
node = RubyVM::AbstractSyntaxTree.of(loc, keep_script_lines: true)
opts = {}

case self
when NoMethodError, NameError
opts[:point_type] = :name
opts[:name] = name
when TypeError, ArgumentError
opts[:point_type] = :args
end

spot = ErrorHighlight.spot(node, **opts)

rescue SyntaxError
rescue SystemCallError # file not found or something
rescue ArgumentError # eval'ed code
end

if spot
return ErrorHighlight.formatter.message_for(spot)
end

""
spot = ErrorHighlight.spot(self)
return "" unless spot
return ErrorHighlight.formatter.message_for(spot)
end

if Exception.method_defined?(:detailed_message)
Expand Down
2 changes: 1 addition & 1 deletion test/test_error_highlight.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1150,7 +1150,7 @@ def v.foo; 1; end
def test_custom_formatter
custom_formatter = Object.new
def custom_formatter.message_for(spot)
"\n\n" + spot.inspect
"\n\n" + spot.except(:script_lines).inspect
end

original_formatter, ErrorHighlight.formatter = ErrorHighlight.formatter, custom_formatter
Expand Down

0 comments on commit 22d1dd7

Please sign in to comment.