Parent

Files

JSON::Pure::Parser

This class implements the JSON parser that is used to parse a JSON string into a Ruby data structure.

Constants

STRING
INTEGER
FLOAT
NAN
INFINITY
MINUS_INFINITY
OBJECT_OPEN
OBJECT_CLOSE
ARRAY_OPEN
ARRAY_CLOSE
PAIR_DELIMITER
COLLECTION_DELIMITER
TRUE
FALSE
NULL
IGNORE
UNPARSED
UNESCAPE_MAP

Unescape characters in strings.

EMPTY_8BIT_STRING

Public Class Methods

new(source, opts = {}) click to toggle source

Creates a new JSON::Pure::Parser instance for the string source.

It will be configured by the opts hash. opts can have the following keys:

  • max_nesting: The maximum depth of nesting allowed in the parsed data structures. Disable depth checking with :max_nesting => false|nil|0, it defaults to 19.

  • allow_nan: If set to true, allow NaN, Infinity and -Infinity in defiance of RFC 4627 to be parsed by the Parser. This option defaults to false.

  • symbolize_names: If set to true, returns symbols for the names (keys) in a JSON object. Otherwise strings are returned, which is also the default.

  • create_additions: If set to false, the Parser doesn’t create additions even if a matchin class and create_id was found. This option defaults to true.

  • object_class: Defaults to Hash

  • array_class: Defaults to Array

  • quirks_mode: Enables quirks_mode for parser, that is for example parsing single JSON values instead of documents is possible.

    # File lib/json/pure/parser.rb, line 73
73:       def initialize(source, opts = {})
74:         opts ||= {}
75:         unless @quirks_mode = opts[:quirks_mode]
76:           source = convert_encoding source
77:         end
78:         super source
79:         if !opts.key?(:max_nesting) # defaults to 19
80:           @max_nesting = 19
81:         elsif opts[:max_nesting]
82:           @max_nesting = opts[:max_nesting]
83:         else
84:           @max_nesting = 0
85:         end
86:         @allow_nan = !!opts[:allow_nan]
87:         @symbolize_names = !!opts[:symbolize_names]
88:         if opts.key?(:create_additions)
89:           @create_additions = !!opts[:create_additions]
90:         else
91:           @create_additions = true
92:         end
93:         @create_id = @create_additions ? JSON.create_id : nil
94:         @object_class = opts[:object_class] || Hash
95:         @array_class  = opts[:array_class] || Array
96:         @match_string = opts[:match_string]
97:       end

Public Instance Methods

parse() click to toggle source

Parses the current JSON string source and returns the complete data structure as a result.

     # File lib/json/pure/parser.rb, line 112
112:       def parse
113:         reset
114:         obj = nil
115:         if @quirks_mode
116:           while !eos? && skip(IGNORE)
117:           end
118:           if eos?
119:             raise ParserError, "source did not contain any JSON!"
120:           else
121:             obj = parse_value
122:             obj == UNPARSED and raise ParserError, "source did not contain any JSON!"
123:           end
124:         else
125:           until eos?
126:             case
127:             when scan(OBJECT_OPEN)
128:               obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
129:               @current_nesting = 1
130:               obj = parse_object
131:             when scan(ARRAY_OPEN)
132:               obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
133:               @current_nesting = 1
134:               obj = parse_array
135:             when skip(IGNORE)
136:               ;
137:             else
138:               raise ParserError, "source '#{peek(20)}' not in JSON!"
139:             end
140:           end
141:           obj or raise ParserError, "source did not contain any JSON!"
142:         end
143:         obj
144:       end
quirks_mode?() click to toggle source
     # File lib/json/pure/parser.rb, line 101
101:       def quirks_mode?
102:         !!@quirks_mode
103:       end
reset() click to toggle source
     # File lib/json/pure/parser.rb, line 105
105:       def reset
106:         super
107:         @current_nesting = 0
108:       end

Private Instance Methods

convert_encoding(source) click to toggle source
     # File lib/json/pure/parser.rb, line 148
148:       def convert_encoding(source)
149:         if source.respond_to?(:to_str)
150:           source = source.to_str
151:         else
152:           raise TypeError, "#{source.inspect} is not like a string"
153:         end
154:         if defined?(::Encoding)
155:           if source.encoding == ::Encoding::ASCII_8BIT
156:             b = source[0, 4].bytes.to_a
157:             source =
158:               case
159:               when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
160:                 source.dup.force_encoding(::Encoding::UTF_32BE).encode!(::Encoding::UTF_8)
161:               when b.size >= 4 && b[0] == 0 && b[2] == 0
162:                 source.dup.force_encoding(::Encoding::UTF_16BE).encode!(::Encoding::UTF_8)
163:               when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
164:                 source.dup.force_encoding(::Encoding::UTF_32LE).encode!(::Encoding::UTF_8)
165:               when b.size >= 4 && b[1] == 0 && b[3] == 0
166:                 source.dup.force_encoding(::Encoding::UTF_16LE).encode!(::Encoding::UTF_8)
167:               else
168:                 source.dup
169:               end
170:           else
171:             source = source.encode(::Encoding::UTF_8)
172:           end
173:           source.force_encoding(::Encoding::ASCII_8BIT)
174:         else
175:           b = source
176:           source =
177:             case
178:             when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
179:               JSON.iconv('utf-8', 'utf-32be', b)
180:             when b.size >= 4 && b[0] == 0 && b[2] == 0
181:               JSON.iconv('utf-8', 'utf-16be', b)
182:             when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
183:               JSON.iconv('utf-8', 'utf-32le', b)
184:             when b.size >= 4 && b[1] == 0 && b[3] == 0
185:               JSON.iconv('utf-8', 'utf-16le', b)
186:             else
187:               b
188:             end
189:         end
190:         source
191:       end
parse_array() click to toggle source
     # File lib/json/pure/parser.rb, line 280
280:       def parse_array
281:         raise NestingError, "nesting of #@current_nesting is too deep" if
282:           @max_nesting.nonzero? && @current_nesting > @max_nesting
283:         result = @array_class.new
284:         delim = false
285:         until eos?
286:           case
287:           when (value = parse_value) != UNPARSED
288:             delim = false
289:             result << value
290:             skip(IGNORE)
291:             if scan(COLLECTION_DELIMITER)
292:               delim = true
293:             elsif match?(ARRAY_CLOSE)
294:               ;
295:             else
296:               raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
297:             end
298:           when scan(ARRAY_CLOSE)
299:             if delim
300:               raise ParserError, "expected next element in array at '#{peek(20)}'!"
301:             end
302:             break
303:           when skip(IGNORE)
304:             ;
305:           else
306:             raise ParserError, "unexpected token in array at '#{peek(20)}'!"
307:           end
308:         end
309:         result
310:       end
parse_object() click to toggle source
     # File lib/json/pure/parser.rb, line 312
312:       def parse_object
313:         raise NestingError, "nesting of #@current_nesting is too deep" if
314:           @max_nesting.nonzero? && @current_nesting > @max_nesting
315:         result = @object_class.new
316:         delim = false
317:         until eos?
318:           case
319:           when (string = parse_string) != UNPARSED
320:             skip(IGNORE)
321:             unless scan(PAIR_DELIMITER)
322:               raise ParserError, "expected ':' in object at '#{peek(20)}'!"
323:             end
324:             skip(IGNORE)
325:             unless (value = parse_value).equal? UNPARSED
326:               result[@symbolize_names ? string.to_sym : string] = value
327:               delim = false
328:               skip(IGNORE)
329:               if scan(COLLECTION_DELIMITER)
330:                 delim = true
331:               elsif match?(OBJECT_CLOSE)
332:                 ;
333:               else
334:                 raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
335:               end
336:             else
337:               raise ParserError, "expected value in object at '#{peek(20)}'!"
338:             end
339:           when scan(OBJECT_CLOSE)
340:             if delim
341:               raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!"
342:             end
343:             if @create_additions and klassname = result[@create_id]
344:               klass = JSON.deep_const_get klassname
345:               break unless klass and klass.json_creatable?
346:               result = klass.json_create(result)
347:             end
348:             break
349:           when skip(IGNORE)
350:             ;
351:           else
352:             raise ParserError, "unexpected token in object at '#{peek(20)}'!"
353:           end
354:         end
355:         result
356:       end
parse_string() click to toggle source
     # File lib/json/pure/parser.rb, line 212
212:       def parse_string
213:         if scan(STRING)
214:           return '' if self[1].empty?
215:           string = self[1].gsub(%((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))) do |c|
216:             if u = UNESCAPE_MAP[$&[1]]
217:               u
218:             else # \uXXXX
219:               bytes = EMPTY_8BIT_STRING.dup
220:               i = 0
221:               while c[6 * i] == \\\ && c[6 * i + 1] == uu
222:                 bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
223:                 i += 1
224:               end
225:               JSON.iconv('utf-8', 'utf-16be', bytes)
226:             end
227:           end
228:           if string.respond_to?(:force_encoding)
229:             string.force_encoding(::Encoding::UTF_8)
230:           end
231:           if @create_additions and @match_string
232:             for (regexp, klass) in @match_string
233:               klass.json_creatable? or next
234:               string =~ regexp and return klass.json_create(string)
235:             end
236:           end
237:           string
238:         else
239:           UNPARSED
240:         end
241:       rescue => e
242:         raise ParserError, "Caught #{e.class} at '#{peek(20)}': #{e}"
243:       end
parse_value() click to toggle source
     # File lib/json/pure/parser.rb, line 245
245:       def parse_value
246:         case
247:         when scan(FLOAT)
248:           Float(self[1])
249:         when scan(INTEGER)
250:           Integer(self[1])
251:         when scan(TRUE)
252:           true
253:         when scan(FALSE)
254:           false
255:         when scan(NULL)
256:           nil
257:         when (string = parse_string) != UNPARSED
258:           string
259:         when scan(ARRAY_OPEN)
260:           @current_nesting += 1
261:           ary = parse_array
262:           @current_nesting -= 1
263:           ary
264:         when scan(OBJECT_OPEN)
265:           @current_nesting += 1
266:           obj = parse_object
267:           @current_nesting -= 1
268:           obj
269:         when @allow_nan && scan(NAN)
270:           NaN
271:         when @allow_nan && scan(INFINITY)
272:           Infinity
273:         when @allow_nan && scan(MINUS_INFINITY)
274:           MinusInfinity
275:         else
276:           UNPARSED
277:         end
278:       end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.