Class JSON::Pure::Parser
In: lib/json/pure/parser.rb
Parent: StringScanner
ParserError NestingError GeneratorError CircularDatastructure StandardError JSONError MissingUnicodeSupport StringScanner Parser Gtk State lib/json/common.rb Ext lib/json/pure/parser.rb lib/json/pure/generator.rb Integer FalseClass Array Hash Float NilClass Object TrueClass Extend String GeneratorMethods Generator Pure Editor 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"\\] | \\["\\\/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.

[Source]

    # File lib/json/pure/parser.rb, line 64
64:       def initialize(source, opts = {})
65:         super
66:         if !opts.key?(:max_nesting) # defaults to 19
67:           @max_nesting = 19
68:         elsif opts[:max_nesting]
69:           @max_nesting = opts[:max_nesting]
70:         else
71:           @max_nesting = 0
72:         end
73:         @allow_nan = !!opts[:allow_nan]
74:         ca = true
75:         ca = opts[:create_additions] if opts.key?(:create_additions)
76:         @create_id = ca ? JSON.create_id : nil
77:       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 83
 83:       def parse
 84:         reset
 85:         obj = nil
 86:         until eos?
 87:           case
 88:           when scan(OBJECT_OPEN)
 89:             obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
 90:             @current_nesting = 1
 91:             obj = parse_object
 92:           when scan(ARRAY_OPEN)
 93:             obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
 94:             @current_nesting = 1
 95:             obj = parse_array
 96:           when skip(IGNORE)
 97:             ;
 98:           else
 99:             raise ParserError, "source '#{peek(20)}' not in JSON!"
100:           end
101:         end
102:         obj or raise ParserError, "source did not contain any JSON!"
103:         obj
104:       end

Private Instance methods

[Source]

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

[Source]

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

[Source]

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

[Source]

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

[Validate]