class RuboCop::RSpec::ExpectOffense::AnnotatedSource
Parsed representation of code annotated with the ‘^^^ Message` style
Constants
- ABBREV
- ANNOTATION_PATTERN
-
Ignore escaped carets, don’t treat as annotations
Attributes
Public Class Methods
Source
# File lib/rubocop/rspec/expect_offense.rb, line 265 def initialize(lines, annotations) @lines = lines.freeze @annotations = annotations.sort.freeze end
@param lines [Array<String>] @param annotations [Array<(Integer, String
)>]
each entry is the annotated line number and the annotation text
@note annotations are sorted so that reconstructing the annotation
text via {#to_s} is deterministic
Source
# File lib/rubocop/rspec/expect_offense.rb, line 243 def self.parse(annotated_source) source = [] annotations = [] annotated_source.each_line do |source_line| if ANNOTATION_PATTERN.match?(source_line) annotations << [source.size, source_line] else source << source_line end end annotations.each { |a| a[0] = 1 } if source.empty? new(source, annotations) end
@param annotated_source [String] string passed to the matchers
Separates annotation lines from source lines. Tracks the real source line number that each annotation corresponds to.
@return [AnnotatedSource]
Public Instance Methods
Source
# File lib/rubocop/rspec/expect_offense.rb, line 270 def ==(other) other.is_a?(self.class) && other.lines == lines && match_annotations?(other) end
Source
# File lib/rubocop/rspec/expect_offense.rb, line 276 def match_annotations?(other) annotations.zip(other.annotations) do |(_actual_line, actual_annotation), (_expected_line, expected_annotation)| if expected_annotation&.end_with?(ABBREV) && actual_annotation.start_with?(expected_annotation[0...-ABBREV.length]) expected_annotation.replace(actual_annotation) end end annotations == other.annotations end
Dirty hack: expectations with […] are rewritten when they match This way the diff is clean.
Source
# File lib/rubocop/rspec/expect_offense.rb, line 326 def plain_source lines.join end
Return the plain source code without annotations
@return [String]
Source
# File lib/rubocop/rspec/expect_offense.rb, line 312 def to_s reconstructed = lines.dup annotations.reverse_each do |line_number, annotation| reconstructed.insert(line_number, annotation) end reconstructed.join end
Construct annotated source string (like what we parse)
Reconstruct a deterministic annotated source string. This is useful for eliminating semantically irrelevant annotation ordering differences.
@example standardization
source1 = AnnotatedSource.parse(<<-RUBY) line1 ^ Annotation 1 ^^ Annotation 2 RUBY source2 = AnnotatedSource.parse(<<-RUBY) line1 ^^ Annotation 2 ^ Annotation 1 RUBY source1.to_s == source2.to_s # => true
@return [String]
Source
# File lib/rubocop/rspec/expect_offense.rb, line 335 def with_offense_annotations(offenses) offense_annotations = offenses.map do |offense| indent = ' ' * offense.column carets = '^' * offense.column_length carets = '^{}' if offense.column_length.zero? [offense.line, "#{indent}#{carets} #{offense.message}\n"] end self.class.new(lines, offense_annotations) end
Annotate the source code with the RuboCop
offenses provided
@param offenses [Array<RuboCop::Cop::Offense>]
@return [self]