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_0.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"\\] | # escaped special characters: \\["\\\/bfnrt] | \\u[0-9a-fA-F]{4} | # match all but escaped special characters: \\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\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.

[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:       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 85
 85:       def parse
 86:         reset
 87:         obj = nil
 88:         until eos?
 89:           case
 90:           when scan(OBJECT_OPEN)
 91:             obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
 92:             @current_nesting = 1
 93:             obj = parse_object
 94:           when scan(ARRAY_OPEN)
 95:             obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
 96:             @current_nesting = 1
 97:             obj = parse_array
 98:           when skip(IGNORE)
 99:             ;
100:           else
101:             raise ParserError, "source '#{peek(20)}' not in JSON!"
102:           end
103:         end
104:         obj or raise ParserError, "source did not contain any JSON!"
105:         obj
106:       end

Private Instance methods

[Source]

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

[Source]

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

[Source]

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

[Source]

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

[Validate]