module ErrorHighlight
Constants
- VERSION
Public Class Methods
formatter()
click to toggle source
# File error_highlight/formatter.rb, line 67 def self.formatter Ractor.current[:__error_highlight_formatter__] || DefaultFormatter end
formatter=(formatter)
click to toggle source
# File error_highlight/formatter.rb, line 71 def self.formatter=(formatter) Ractor.current[:__error_highlight_formatter__] = formatter end
spot(obj, **opts)
click to toggle source
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:
{ 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+), the method will return nil. This restriction may be removed in the future.
# File 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
Private Class Methods
prism_find(location)
click to toggle source
Accepts a Thread::Backtrace::Location object and returns a Prism::Node corresponding to the backtrace location in the source code.
# File error_highlight/base.rb, line 86 def self.prism_find(location) require "prism" return nil if Prism::VERSION < "1.0.0" absolute_path = location.absolute_path return unless absolute_path node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location) Prism.parse_file(absolute_path).value.breadth_first_search { |node| node.node_id == node_id } end