/usr/lib/ruby/vendor_ruby/rspec/core/formatters/snippet_extractor.rb is in ruby-rspec-core 3.5.0c3e0m0s0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | RSpec::Support.require_rspec_core "source"
module RSpec
module Core
module Formatters
# @private
class SnippetExtractor
NoSuchFileError = Class.new(StandardError)
NoSuchLineError = Class.new(StandardError)
def self.extract_line_at(file_path, line_number)
source = source_from_file(file_path)
line = source.lines[line_number - 1]
raise NoSuchLineError unless line
line
end
def self.source_from_file(path)
raise NoSuchFileError unless File.exist?(path)
RSpec.world.source_cache.source_from_file(path)
end
if RSpec::Support::RubyFeatures.ripper_supported?
NoExpressionAtLineError = Class.new(StandardError)
attr_reader :source, :beginning_line_number, :max_line_count
def self.extract_expression_lines_at(file_path, beginning_line_number, max_line_count=nil)
if max_line_count == 1
[extract_line_at(file_path, beginning_line_number)]
else
source = source_from_file(file_path)
new(source, beginning_line_number, max_line_count).expression_lines
end
end
def initialize(source, beginning_line_number, max_line_count=nil)
@source = source
@beginning_line_number = beginning_line_number
@max_line_count = max_line_count
end
def expression_lines
line_range = line_range_of_expression
if max_line_count && line_range.count > max_line_count
line_range = (line_range.begin)..(line_range.begin + max_line_count - 1)
end
source.lines[(line_range.begin - 1)..(line_range.end - 1)]
rescue SyntaxError, NoExpressionAtLineError
[self.class.extract_line_at(source.path, beginning_line_number)]
end
private
def line_range_of_expression
@line_range_of_expression ||= begin
line_range = line_range_of_location_nodes_in_expression
initial_unclosed_tokens = unclosed_tokens_in_line_range(line_range)
unclosed_tokens = initial_unclosed_tokens
until (initial_unclosed_tokens & unclosed_tokens).empty?
line_range = (line_range.begin)..(line_range.end + 1)
unclosed_tokens = unclosed_tokens_in_line_range(line_range)
end
line_range
end
end
def unclosed_tokens_in_line_range(line_range)
tokens = FlatMap.flat_map(line_range) do |line_number|
source.tokens_by_line_number[line_number]
end
tokens.each_with_object([]) do |token, unclosed_tokens|
if token.opening?
unclosed_tokens << token
else
index = unclosed_tokens.rindex do |unclosed_token|
unclosed_token.closed_by?(token)
end
unclosed_tokens.delete_at(index) if index
end
end
end
def line_range_of_location_nodes_in_expression
line_numbers = expression_node.each_with_object(Set.new) do |node, set|
set << node.location.line if node.location
end
line_numbers.min..line_numbers.max
end
def expression_node
raise NoExpressionAtLineError if location_nodes_at_beginning_line.empty?
@expression_node ||= begin
common_ancestor_nodes = location_nodes_at_beginning_line.map do |node|
node.each_ancestor.to_a
end.reduce(:&)
common_ancestor_nodes.find { |node| expression_outmost_node?(node) }
end
end
def expression_outmost_node?(node)
return true unless node.parent
return false if node.type.to_s.start_with?('@')
![node, node.parent].all? do |n|
# See `Ripper::PARSER_EVENTS` for the complete list of sexp types.
type = n.type.to_s
type.end_with?('call') || type.start_with?('method_add_')
end
end
def location_nodes_at_beginning_line
source.nodes_by_line_number[beginning_line_number]
end
else
# :nocov:
def self.extract_expression_lines_at(file_path, beginning_line_number, *)
[extract_line_at(file_path, beginning_line_number)]
end
# :nocov:
end
def self.least_indentation_from(lines)
lines.map { |line| line[/^[ \t]*/] }.min
end
end
end
end
end
|