Class: JsonProjection::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/json-projection/parser.rb

Overview

A streaming JSON parser that generates SAX-like events for state changes. Use the json gem for small documents. Use this for huge documents that won’t fit in memory.

Constant Summary collapse

BUF_SIZE =
4096
CONTROL =
/[\x00-\x1F]/
WS =
/[ \n\t\r]/
HEX =
/[0-9a-fA-F]/
DIGIT =
/[0-9]/
DIGIT_1_9 =
/[1-9]/
DIGIT_END =
/\d$/
TRUE_RE =
/[rue]/
FALSE_RE =
/[alse]/
NULL_RE =
/[ul]/
TRUE_KEYWORD =
'true'
FALSE_KEYWORD =
'false'
NULL_KEYWORD =
'null'
LEFT_BRACE =
'{'
RIGHT_BRACE =
'}'
LEFT_BRACKET =
'['
RIGHT_BRACKET =
']'
BACKSLASH =
'\\'
SLASH =
'/'
QUOTE =
'"'
COMMA =
','
COLON =
':'
ZERO =
'0'
MINUS =
'-'
PLUS =
'+'
POINT =
'.'
EXPONENT =
/[eE]/

Instance Method Summary collapse

Constructor Details

#initialize(stream) ⇒ Parser

Initialize a new parser with a stream. The stream cursor is advanced as events are drawn from the parser. The parser maintains a small data cache of bytes read from the stream.

stream

IO IO stream to read data from.

Returns nothing.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/json-projection/parser.rb', line 74

def initialize(stream)
  @stream = stream

  @event_buffer = Fifo.new

  @bytes_buffer = Buffer.new
  @bytes = nil

  @pos = -1
  @state = :start_document
  @stack = []

  @value_buffer = ""
  @unicode = ""
end

Instance Method Details

#next_eventObject

Draw bytes from the stream until an event can be constructed. May raise IO errors.

Returns a JsonProject::StreamEvent subclass or raises StandardError.



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
# File 'lib/json-projection/parser.rb', line 94

def next_event()
  # Are there any already read events, return the oldest
  @event_buffer, event = @event_buffer.pop
  return event unless event.nil?

  if @state == :end_document
    error("already EOF, no more events")
  end

  while true do
    if @bytes.nil? || @bytes.empty?
      data = stream.read(BUF_SIZE)
      if data == nil # hit EOF
        error("unexpected EOF")
      end

      @bytes = @bytes_buffer.<<(data).each_char.to_a
    end

    head = @bytes.first
    tail = @bytes.slice!(1, @bytes.size - 1)

    @bytes = tail
    @pos += 1

    new_state, events = handle_character(@state, head)

    @state = new_state
    @event_buffer = events.append(@event_buffer)

    unless @event_buffer.empty?
      @event_buffer, event = @event_buffer.pop
      return event
    end
  end
end