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

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, chunk_size = 4096) ⇒ 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.

chunk_size

Integer Number of bytes to read from the stream at a time.

Returns nothing.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/json-projection/parser.rb', line 76

def initialize(stream, chunk_size = 4096)
  @stream = stream
  @chunk_size = chunk_size

  @event_buffer = Fifo.new

  @character_buffer = Buffer.new

  @characters_cursor = -1
  @characters = nil

  @stream_position = -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.



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

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

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

  while true do
    if @characters.nil? || @characters_cursor == @characters.size
      data = stream.read(@chunk_size)
      if data == nil # hit EOF
        error("unexpected EOF")
      end

      @characters = @character_buffer.<<(data).each_char.to_a
      @characters_cursor = 0
    end

    character = @characters[@characters_cursor]
    @characters_cursor += 1

    @stream_position += 1

    new_state, new_events = handle_character(@state, character)

    @state = new_state
    @event_buffer.prepend!(new_events)

    event = @event_buffer.pop!
    return event unless event.nil?
  end
end