class Parser::Source::Range
A range of characters in a particular source buffer.
The range is always exclusive, i.e. a range with `begin_pos` of 3 and `end_pos` of 5 will contain the following characters:
example ^^
@!attribute [r] source_buffer
@return [Parser::Source::Buffer]
@!attribute [r] begin_pos
@return [Integer] index of the first character in the range
@!attribute [r] end_pos
@return [Integer] index of the character after the last character in the range
@api public
Attributes
Public Class Methods
@param [Buffer] source_buffer
@param [Integer] begin_pos
@param [Integer] end_pos
# File lib/parser/source/range.rb, line 37 def initialize(source_buffer, begin_pos, end_pos) if end_pos < begin_pos raise ArgumentError, 'Parser::Source::Range: end_pos must not be less than begin_pos' end if source_buffer.nil? raise ArgumentError, 'Parser::Source::Range: source_buffer must not be nil' end @source_buffer = source_buffer @begin_pos, @end_pos = begin_pos, end_pos freeze end
Public Instance Methods
Compare ranges, first by begin_pos
, then by end_pos.
# File lib/parser/source/range.rb, line 301 def <=>(other) return nil unless other.is_a?(::Parser::Source::Range) && @source_buffer == other.source_buffer (@begin_pos <=> other.begin_pos).nonzero? || (@end_pos <=> other.end_pos) end
@param [Hash] Endpoint(s) to change, any combination of :begin_pos or :end_pos @return [Range] the same range as this range but with the given end point(s) adjusted by the given amount(s)
# File lib/parser/source/range.rb, line 193 def adjust(begin_pos: 0, end_pos: 0) Range.new(@source_buffer, @begin_pos + begin_pos, @end_pos + end_pos) end
@return [Range] a zero-length range located just before the beginning
of this range.
# File lib/parser/source/range.rb, line 55 def begin with(end_pos: @begin_pos) end
@return [Integer] zero-based column number of the beginning of this range.
# File lib/parser/source/range.rb, line 92 def column @source_buffer.column_for_position(@begin_pos) end
@return [::Range] a range of columns spanned by this range. @raise RangeError
# File lib/parser/source/range.rb, line 114 def column_range if line != last_line raise RangeError, "#{self.inspect} spans more than one line" end column...last_column end
Return `other.contains?(self)`
Two ranges must be one and only one of ==, disjoint?, contains?, contained? or crossing?
@param [Range] other @return [Boolean]
# File lib/parser/source/range.rb, line 274 def contained?(other) other.contains?(self) end
Returns true iff this range contains (strictly) `other`.
Two ranges must be one and only one of ==, disjoint?, contains?, contained? or crossing?
@param [Range] other @return [Boolean]
# File lib/parser/source/range.rb, line 262 def contains?(other) (other.begin_pos <=> @begin_pos) + (@end_pos <=> other.end_pos) >= (other.empty? ? 2 : 1) end
Returns true iff both ranges intersect and also have different elements from one another.
Two ranges must be one and only one of ==, disjoint?, contains?, contained? or crossing?
@param [Range] other @return [Boolean]
# File lib/parser/source/range.rb, line 286 def crossing?(other) return false unless overlaps?(other) (@begin_pos <=> other.begin_pos) * (@end_pos <=> other.end_pos) == 1 end
Return `true` iff this range and `other` are disjoint.
Two ranges must be one and only one of ==, disjoint?, contains?, contained? or crossing?
@param [Range] other @return [Boolean]
# File lib/parser/source/range.rb, line 236 def disjoint?(other) if empty? && other.empty? @begin_pos != other.begin_pos else @begin_pos >= other.end_pos || other.begin_pos >= @end_pos end end
Checks if a range is empty; if it contains no characters @return [Boolean]
# File lib/parser/source/range.rb, line 294 def empty? @begin_pos == @end_pos end
@return [Range] a zero-length range located just after the end
of this range.
# File lib/parser/source/range.rb, line 63 def end with(begin_pos: @end_pos) end
Support for Ranges be used in as Hash indices and in Sets.
# File lib/parser/source/range.rb, line 313 def hash [@source_buffer, @begin_pos, @end_pos].hash end
@return [String] a human-readable representation of this range.
# File lib/parser/source/range.rb, line 320 def inspect "#<Parser::Source::Range #{@source_buffer.name} #{@begin_pos}...#{@end_pos}>" end
@param [Range] other @return [Range] overlapping region of this range and `other`, or `nil`
if they do not overlap
# File lib/parser/source/range.rb, line 220 def intersect(other) unless disjoint?(other) Range.new(@source_buffer, [@begin_pos, other.begin_pos].max, [@end_pos, other.end_pos].min) end end
`is?` provides a concise way to compare the source corresponding to this range. For example, `r.source == '(' || r.source == 'begin'` is equivalent to `r.is?('(', 'begin')`.
# File lib/parser/source/range.rb, line 141 def is?(*what) what.include?(source) end
@param [Range] other @return [Range] smallest possible range spanning both this range and `other`.
# File lib/parser/source/range.rb, line 209 def join(other) Range.new(@source_buffer, [@begin_pos, other.begin_pos].min, [@end_pos, other.end_pos].max) end
@return [Integer] zero-based column number of the end of this range.
# File lib/parser/source/range.rb, line 106 def last_column @source_buffer.column_for_position(@end_pos) end
@return [Integer] line number of the end of this range.
# File lib/parser/source/range.rb, line 99 def last_line @source_buffer.line_for_position(@end_pos) end
Line number of the beginning of this range. By default, the first line of a buffer is 1; as such, line numbers are most commonly one-based.
@see Buffer
@return [Integer] line number of the beginning of this range.
# File lib/parser/source/range.rb, line 83 def line @source_buffer.line_for_position(@begin_pos) end
Return `true` iff this range is not disjoint from `other`.
@param [Range] other @return [Boolean] `true` if this range and `other` overlap
# File lib/parser/source/range.rb, line 250 def overlaps?(other) !disjoint?(other) end
@param [Integer] new_size @return [Range] a range beginning at the same point as this range and length `new_size`.
# File lib/parser/source/range.rb, line 201 def resize(new_size) with(end_pos: @begin_pos + new_size) end
@return [Integer] amount of characters included in this range.
# File lib/parser/source/range.rb, line 70 def size @end_pos - @begin_pos end
@return [String] all source code covered by this range.
# File lib/parser/source/range.rb, line 132 def source @source_buffer.slice(self.begin_pos...self.end_pos) end
@return [String] a line of source code containing the beginning of this range.
# File lib/parser/source/range.rb, line 125 def source_line @source_buffer.source_line(line) end
@return [Array<Integer>] a set of character indexes contained in this range.
# File lib/parser/source/range.rb, line 148 def to_a (@begin_pos...@end_pos).to_a end
@return [Range] a Ruby range with the same `begin_pos` and `end_pos`
# File lib/parser/source/range.rb, line 155 def to_range self.begin_pos...self.end_pos end
Composes a GNU/Clang-style string representation of the beginning of this range.
For example, for the following range in file `foo.rb`,
def foo ^^^
`to_s` will return `foo.rb:1:5`. Note that the column index is one-based.
@return [String]
# File lib/parser/source/range.rb, line 173 def to_s line, column = @source_buffer.decompose_position(@begin_pos) [@source_buffer.name, line, column + 1].join(':') end
@param [Hash] Endpoint(s) to change, any combination of :begin_pos or :end_pos @return [Range] the same range as this range but with the given end point(s) changed to the given value(s).
# File lib/parser/source/range.rb, line 184 def with(begin_pos: @begin_pos, end_pos: @end_pos) Range.new(@source_buffer, begin_pos, end_pos) end