summaryrefslogtreecommitdiff
path: root/lib/error_highlight/base.rb
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2022-08-10 18:36:59 +0900
committergit <svn-admin@ruby-lang.org>2022-08-10 18:37:13 +0900
commit99e7fa5b3718d61d61427c67d244ec50b9eb8578 (patch)
tree34e74d18354ac62cbcd44bbdd29d791c2693e083 /lib/error_highlight/base.rb
parent1139bc8c20d243b17f159d6c6518df17fcf887fe (diff)
downloadruby-99e7fa5b3718d61d61427c67d244ec50b9eb8578.tar.gz
[ruby/error_highlight] Make ErrorHighlight.spot accept Exception (https://github.com/ruby/error_highlight/pull/25)
... and move things from core_ext.rb to base.rb. This will confine CRuby-dependent things to ErrorHighlight.spot. https://github.com/ruby/error_highlight/commit/22d1dd7824
Diffstat (limited to 'lib/error_highlight/base.rb')
-rw-r--r--lib/error_highlight/base.rb58
1 files changed, 51 insertions, 7 deletions
diff --git a/lib/error_highlight/base.rb b/lib/error_highlight/base.rb
index 8392979e24..51f1ce369d 100644
--- a/lib/error_highlight/base.rb
+++ b/lib/error_highlight/base.rb
@@ -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:
# {
@@ -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
@@ -122,6 +165,7 @@ module ErrorHighlight
last_lineno: @end_lineno,
last_column: @end_column,
snippet: @snippet,
+ script_lines: @node.script_lines,
}
else
return nil