Class JSON::Pure::Parser
In: lib/json/pure/parser.rb
Parent: StringScanner
JSONError GeneratorError ParserError MissingUnicodeSupport CircularDatastructure NestingError StandardError Gtk StringScanner Parser State lib/json/common.rb Ext Editor lib/json/pure/parser.rb lib/json/pure/generator.rb Object Integer FalseClass Array Hash Float NilClass TrueClass Extend String GeneratorMethods Generator Pure JSON dot/m_9_3.png

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

Methods

Constants

STRING = /" ((?:[^\x0-\x1f"\\] | \\["\\\/bfnrt] | \\u[0-9a-fA-F]{4} | \\[\x20-\xff])*) "/nx
INTEGER = /(-?0|-?[1-9]\d*)/
FLOAT = /(-? (?:0|[1-9]\d*) (?: \.\d+(?i:e[+-]?\d+) | \.\d+ | (?i:e[+-]?\d+) ) )/x
NAN = /NaN/
INFINITY = /Infinity/
MINUS_INFINITY = /-Infinity/
OBJECT_OPEN = /\{/
OBJECT_CLOSE = /\}/
ARRAY_OPEN = /\[/
ARRAY_CLOSE = /\]/
PAIR_DELIMITER = /:/
COLLECTION_DELIMITER = /,/
TRUE = /true/
FALSE = /false/
NULL = /null/
IGNORE = %r( (?: //[^\n\r]*[\n\r]| # line comments /\* # c-style comments (?: [^*/]| # normal chars /[^*]| # slashes that do not start a nested comment \*[^/]| # asterisks that do not end this comment /(?=\*/) # single slash before this comment's end )* \*/ # the End of this comment |[ \t\r\n]+ # whitespaces: space, horicontal tab, lf, cr )+ )mx
UNPARSED = Object.new
UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }   Unescape characters in strings.

External Aliases

string -> source

Public Class methods

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.
  • 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

[Source]

    # File lib/json/pure/parser.rb, line 66
66:       def initialize(source, opts = {})
67:         super
68:         if !opts.key?(:max_nesting) # defaults to 19
69:           @max_nesting = 19
70:         elsif opts[:max_nesting]
71:           @max_nesting = opts[:max_nesting]
72:         else
73:           @max_nesting = 0
74:         end
75:         @allow_nan = !!opts[:allow_nan]
76:         ca = true
77:         ca = opts[:create_additions] if opts.key?(:create_additions)
78:         @create_id = ca ? JSON.create_id : nil
79:         @object_class = opts[:object_class] || Hash
80:         @array_class = opts[:array_class] || Array
81:       end

Public Instance methods

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

[Source]

     # File lib/json/pure/parser.rb, line 87
 87:       def parse
 88:         reset
 89:         obj = nil
 90:         until eos?
 91:           case
 92:           when scan(OBJECT_OPEN)
 93:             obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
 94:             @current_nesting = 1
 95:             obj = parse_object
 96:           when scan(ARRAY_OPEN)
 97:             obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
 98:             @current_nesting = 1
 99:             obj = parse_array
100:           when skip(IGNORE)
101:             ;
102:           else
103:             raise ParserError, "source '#{peek(20)}' not in JSON!"
104:           end
105:         end
106:         obj or raise ParserError, "source did not contain any JSON!"
107:         obj
108:       end

Private Instance methods

[Source]

     # File lib/json/pure/parser.rb, line 188
188:       def parse_array
189:         raise NestingError, "nesting of #@current_nesting is to deep" if
190:           @max_nesting.nonzero? && @current_nesting > @max_nesting
191:         result = @array_class.new
192:         delim = false
193:         until eos?
194:           case
195:           when (value = parse_value) != UNPARSED
196:             delim = false
197:             result << value
198:             skip(IGNORE)
199:             if scan(COLLECTION_DELIMITER)
200:               delim = true
201:             elsif match?(ARRAY_CLOSE)
202:               ;
203:             else
204:               raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
205:             end
206:           when scan(ARRAY_CLOSE)
207:             if delim
208:               raise ParserError, "expected next element in array at '#{peek(20)}'!"
209:             end
210:             break
211:           when skip(IGNORE)
212:             ;
213:           else
214:             raise ParserError, "unexpected token in array at '#{peek(20)}'!"
215:           end
216:         end
217:         result
218:       end

[Source]

     # File lib/json/pure/parser.rb, line 220
220:       def parse_object
221:         raise NestingError, "nesting of #@current_nesting is to deep" if
222:           @max_nesting.nonzero? && @current_nesting > @max_nesting
223:         result = @object_class.new
224:         delim = false
225:         until eos?
226:           case
227:           when (string = parse_string) != UNPARSED
228:             skip(IGNORE)
229:             unless scan(PAIR_DELIMITER)
230:               raise ParserError, "expected ':' in object at '#{peek(20)}'!"
231:             end
232:             skip(IGNORE)
233:             unless (value = parse_value).equal? UNPARSED
234:               result[string] = value
235:               delim = false
236:               skip(IGNORE)
237:               if scan(COLLECTION_DELIMITER)
238:                 delim = true
239:               elsif match?(OBJECT_CLOSE)
240:                 ;
241:               else
242:                 raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
243:               end
244:             else
245:               raise ParserError, "expected value in object at '#{peek(20)}'!"
246:             end
247:           when scan(OBJECT_CLOSE)
248:             if delim
249:               raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!"
250:             end
251:             if @create_id and klassname = result[@create_id]
252:               klass = JSON.deep_const_get klassname
253:               break unless klass and klass.json_creatable?
254:               result = klass.json_create(result)
255:             end
256:             break
257:           when skip(IGNORE)
258:             ;
259:           else
260:             raise ParserError, "unexpected token in object at '#{peek(20)}'!"
261:           end
262:         end
263:         result
264:       end

[Source]

     # File lib/json/pure/parser.rb, line 126
126:       def parse_string
127:         if scan(STRING)
128:           return '' if self[1].empty?
129:           string = self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
130:             if u = UNESCAPE_MAP[$&[1]]
131:               u
132:             else # \uXXXX
133:               bytes = ''
134:               i = 0
135:               while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
136:                 bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
137:                 i += 1
138:               end
139:               JSON::UTF16toUTF8.iconv(bytes)
140:             end
141:           end
142:           if string.respond_to?(:force_encoding)
143:             string.force_encoding(Encoding::UTF_8)
144:           end
145:           string
146:         else
147:           UNPARSED
148:         end
149:       rescue Iconv::Failure => e
150:         raise GeneratorError, "Caught #{e.class}: #{e}"
151:       end

[Source]

     # File lib/json/pure/parser.rb, line 153
153:       def parse_value
154:         case
155:         when scan(FLOAT)
156:           Float(self[1])
157:         when scan(INTEGER)
158:           Integer(self[1])
159:         when scan(TRUE)
160:           true
161:         when scan(FALSE)
162:           false
163:         when scan(NULL)
164:           nil
165:         when (string = parse_string) != UNPARSED
166:           string
167:         when scan(ARRAY_OPEN)
168:           @current_nesting += 1
169:           ary = parse_array
170:           @current_nesting -= 1
171:           ary
172:         when scan(OBJECT_OPEN)
173:           @current_nesting += 1
174:           obj = parse_object
175:           @current_nesting -= 1
176:           obj
177:         when @allow_nan && scan(NAN)
178:           NaN
179:         when @allow_nan && scan(INFINITY)
180:           Infinity
181:         when @allow_nan && scan(MINUS_INFINITY)
182:           MinusInfinity
183:         else
184:           UNPARSED
185:         end
186:       end

[Validate]