Class: Psych::Pure::Source

Inherits:
Object
  • Object
show all
Defined in:
lib/psych/pure.rb

Overview

A source wraps the input string and provides methods to access line and column information from a byte offset.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(string) ⇒ Source

Returns a new instance of Source.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/psych/pure.rb', line 47

def initialize(string)
  @string = string
  offsets = [0]
  @last_line_index = 0
  @last_line_offset = 0

  idx = 0
  while (found = string.index("\n", idx))
    offsets << (idx = found + 1)
  end

  offsets << string.bytesize if offsets.last != string.bytesize
  @line_offsets = offsets
end

Instance Attribute Details

#trim_lineObject (readonly)

The line index computed by the most recent call to #trim.



45
46
47
# File 'lib/psych/pure.rb', line 45

def trim_line
  @trim_line
end

Instance Method Details

#column(offset, known_line = nil) ⇒ Object



130
131
132
# File 'lib/psych/pure.rb', line 130

def column(offset, known_line = nil)
  offset - @line_offsets[known_line || line(offset)]
end

#line(offset) ⇒ Object



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
# File 'lib/psych/pure.rb', line 102

def line(offset)
  # Fast path: linear scan forward from the last lookup position.
  # The parser generally moves forward through the input, so this
  # avoids the O(log n) bsearch in the common case.
  cached = @last_line_index
  offsets = @line_offsets

  if offset >= @last_line_offset
    max = offsets.size - 1
    while cached < max && offsets[cached + 1] <= offset
      cached += 1
    end

    @last_line_index = cached
    @last_line_offset = offsets[cached]
    cached
  else
    # Backward seek — linear scan backward from cached position
    while cached > 0 && offsets[cached] > offset
      cached -= 1
    end

    @last_line_index = cached
    @last_line_offset = offsets[cached]
    cached
  end
end

#point(offset) ⇒ Object



134
135
136
# File 'lib/psych/pure.rb', line 134

def point(offset)
  "line #{line(offset) + 1} column #{column(offset)}"
end

#trim(offset) ⇒ Object

Trim trailing whitespace-only and comment-only lines from the given offset. After calling, @trim_line holds the line index of the returned offset so callers can avoid a redundant line() lookup.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/psych/pure.rb', line 65

def trim(offset)
  offsets = @line_offsets
  string = @string
  l = line(offset)

  while l != 0 && offset == offsets[l]
    prev_start = offsets[l - 1]
    prev_end = offsets[l] - 1
    idx = prev_start
    idx += 1 while idx < prev_end && string.getbyte(idx) == 0x20 # space
    break unless idx >= prev_end || string.getbyte(idx) == 0x23 # #
    offset = prev_start
    l -= 1
  end

  @trim_line = l
  offset
end

#trim_comments(offset) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/psych/pure.rb', line 84

def trim_comments(offset)
  offsets = @line_offsets
  string = @string
  l = line(offset)

  while l != 0 && offset == offsets[l]
    prev_start = offsets[l - 1]
    prev_end = offsets[l] - 1
    idx = prev_start
    idx += 1 while idx < prev_end && string.getbyte(idx) == 0x20 # space
    break unless idx < prev_end && string.getbyte(idx) == 0x23 # #
    offset = prev_start
    l -= 1
  end

  offset
end