Maintenance Ruby 3.4 gets fixes, but no new features. Switch to Ruby 4.0 →
class method
ErrorHighlight.spot
spot(obj, **opts)
lib/error_highlight/base.rb
View on GitHub ↗
# File tmp/rubies/ruby-3.4.1/lib/error_highlight/base.rb, line 33
def self.spot(obj, **opts)
case obj
when Exception
exc = obj
loc = opts[:backtrace_location]
opts = { point_type: opts.fetch(:point_type, :name) }
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
return nil unless Thread::Backtrace::Location === loc
node =
begin
RubyVM::AbstractSyntaxTree.of(loc, keep_script_lines: true)
rescue RuntimeError => error
# RubyVM::AbstractSyntaxTree.of raises an error with a message that
# includes "prism" when the ISEQ was compiled with the prism compiler.
# In this case, we'll try to parse again with prism instead.
raise unless error.message.include?("prism")
prism_find(loc)
end
Spotter.new(node, **opts).spot
when RubyVM::AbstractSyntaxTree::Node, Prism::Node
Spotter.new(obj, **opts).spot
else
raise TypeError, "Exception is expected"
end
rescue SyntaxError,
SystemCallError, # file not found or something
ArgumentError # eval'ed code
return nil
end
Identify the code fragment at that a given exception occurred.
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:
Example
{
first_lineno: Integer,
first_column: Integer,
last_lineno: Integer,
last_column: Integer,
snippet: String,
script_lines: [String],
} | nil
Limitations:
Currently, ErrorHighlight.spot only supports a single-line code fragment. Therefore, if the return value is not nil, first_lineno and last_lineno will have the same value. If the relevant code fragment spans multiple lines (e.g., Array#[] of +ary[(newline)expr(newline)]+), the method will return nil. This restriction may be removed in the future.