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

begin_pos[R]
end_pos[R]
source_buffer[R]

Public Class Methods

new(source_buffer, begin_pos, end_pos) click to toggle source

@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

<=>(other) click to toggle source

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
adjust(begin_pos: 0, end_pos: 0) click to toggle source

@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
begin() click to toggle source

@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
column() click to toggle source

@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
column_range() click to toggle source

@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
contained?(other) click to toggle source

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
contains?(other) click to toggle source

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
crossing?(other) click to toggle source

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
disjoint?(other) click to toggle source

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
empty?() click to toggle source

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
end() click to toggle source

@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
first_line()
Alias for: line
hash() click to toggle source

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
inspect() click to toggle source

@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
intersect(other) click to toggle source

@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?(*what) click to toggle source

`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
join(other) click to toggle source

@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
last_column() click to toggle source

@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
last_line() click to toggle source

@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
length()
Alias for: size
line() click to toggle source

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
Also aliased as: first_line
overlaps?(other) click to toggle source

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
resize(new_size) click to toggle source

@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
size() click to toggle source

@return [Integer] amount of characters included in this range.

# File lib/parser/source/range.rb, line 70
def size
  @end_pos - @begin_pos
end
Also aliased as: length
source() click to toggle source

@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
source_line() click to toggle source

@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
to_a() click to toggle source

@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
to_range() click to toggle source

@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
to_s() click to toggle source

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
with(begin_pos: @begin_pos, end_pos: @end_pos) click to toggle source

@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