StringScanner
This class implements the JSON parser that is used to parse a JSON string into a Ruby data structure.
Unescape characters in strings.
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
# File lib/json/pure/parser.rb, line 71
71: def initialize(source, opts = {})
72: opts ||= {}
73: if defined?(::Encoding)
74: if source.encoding == ::Encoding::ASCII_8BIT
75: b = source[0, 4].bytes.to_a
76: source = case
77: when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
78: source.dup.force_encoding(::Encoding::UTF_32BE).encode!(::Encoding::UTF_8)
79: when b.size >= 4 && b[0] == 0 && b[2] == 0
80: source.dup.force_encoding(::Encoding::UTF_16BE).encode!(::Encoding::UTF_8)
81: when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
82: source.dup.force_encoding(::Encoding::UTF_32LE).encode!(::Encoding::UTF_8)
83:
84: when b.size >= 4 && b[1] == 0 && b[3] == 0
85: source.dup.force_encoding(::Encoding::UTF_16LE).encode!(::Encoding::UTF_8)
86: else
87: source.dup
88: end
89: else
90: source = source.encode(::Encoding::UTF_8)
91: end
92: source.force_encoding(::Encoding::ASCII_8BIT)
93: else
94: b = source
95: source = case
96: when b.size >= 4 && b[0] == 0 && b[1] == 0 && b[2] == 0
97: JSON.iconv('utf-8', 'utf-32be', b)
98: when b.size >= 4 && b[0] == 0 && b[2] == 0
99: JSON.iconv('utf-8', 'utf-16be', b)
100: when b.size >= 4 && b[1] == 0 && b[2] == 0 && b[3] == 0
101: JSON.iconv('utf-8', 'utf-32le', b)
102: when b.size >= 4 && b[1] == 0 && b[3] == 0
103: JSON.iconv('utf-8', 'utf-16le', b)
104: else
105: b
106: end
107: end
108: super source
109: if !opts.key?(:max_nesting) # defaults to 19
110: @max_nesting = 19
111: elsif opts[:max_nesting]
112: @max_nesting = opts[:max_nesting]
113: else
114: @max_nesting = 0
115: end
116: @allow_nan = !!opts[:allow_nan]
117: @symbolize_names = !!opts[:symbolize_names]
118: ca = true
119: ca = opts[:create_additions] if opts.key?(:create_additions)
120: @create_id = ca ? JSON.create_id : nil
121: @object_class = opts[:object_class] || Hash
122: @array_class = opts[:array_class] || Array
123: end
Parses the current JSON string source and returns the complete data structure as a result.
# File lib/json/pure/parser.rb, line 129
129: def parse
130: reset
131: obj = nil
132: until eos?
133: case
134: when scan(OBJECT_OPEN)
135: obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
136: @current_nesting = 1
137: obj = parse_object
138: when scan(ARRAY_OPEN)
139: obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
140: @current_nesting = 1
141: obj = parse_array
142: when skip(IGNORE)
143: ;
144: else
145: raise ParserError, "source '#{peek(20)}' not in JSON!"
146: end
147: end
148: obj or raise ParserError, "source did not contain any JSON!"
149: obj
150: end
# File lib/json/pure/parser.rb, line 230
230: def parse_array
231: raise NestingError, "nesting of #@current_nesting is too deep" if
232: @max_nesting.nonzero? && @current_nesting > @max_nesting
233: result = @array_class.new
234: delim = false
235: until eos?
236: case
237: when (value = parse_value) != UNPARSED
238: delim = false
239: result << value
240: skip(IGNORE)
241: if scan(COLLECTION_DELIMITER)
242: delim = true
243: elsif match?(ARRAY_CLOSE)
244: ;
245: else
246: raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
247: end
248: when scan(ARRAY_CLOSE)
249: if delim
250: raise ParserError, "expected next element in array at '#{peek(20)}'!"
251: end
252: break
253: when skip(IGNORE)
254: ;
255: else
256: raise ParserError, "unexpected token in array at '#{peek(20)}'!"
257: end
258: end
259: result
260: end
# File lib/json/pure/parser.rb, line 262
262: def parse_object
263: raise NestingError, "nesting of #@current_nesting is too deep" if
264: @max_nesting.nonzero? && @current_nesting > @max_nesting
265: result = @object_class.new
266: delim = false
267: until eos?
268: case
269: when (string = parse_string) != UNPARSED
270: skip(IGNORE)
271: unless scan(PAIR_DELIMITER)
272: raise ParserError, "expected ':' in object at '#{peek(20)}'!"
273: end
274: skip(IGNORE)
275: unless (value = parse_value).equal? UNPARSED
276: result[@symbolize_names ? string.to_sym : string] = value
277: delim = false
278: skip(IGNORE)
279: if scan(COLLECTION_DELIMITER)
280: delim = true
281: elsif match?(OBJECT_CLOSE)
282: ;
283: else
284: raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
285: end
286: else
287: raise ParserError, "expected value in object at '#{peek(20)}'!"
288: end
289: when scan(OBJECT_CLOSE)
290: if delim
291: raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!"
292: end
293: if @create_id and klassname = result[@create_id]
294: klass = JSON.deep_const_get klassname
295: break unless klass and klass.json_creatable?
296: result = klass.json_create(result)
297: end
298: break
299: when skip(IGNORE)
300: ;
301: else
302: raise ParserError, "unexpected token in object at '#{peek(20)}'!"
303: end
304: end
305: result
306: end
# File lib/json/pure/parser.rb, line 168
168: def parse_string
169: if scan(STRING)
170: return '' if self[1].empty?
171: string = self[1].gsub(%((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))) do |c|
172: if u = UNESCAPE_MAP[$&[1]]
173: u
174: else # \uXXXX
175: bytes = ''
176: i = 0
177: while c[6 * i] == \\\ && c[6 * i + 1] == uu
178: bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
179: i += 1
180: end
181: JSON::UTF16toUTF8.iconv(bytes)
182: end
183: end
184: if string.respond_to?(:force_encoding)
185: string.force_encoding(::Encoding::UTF_8)
186: end
187: string
188: else
189: UNPARSED
190: end
191: rescue Iconv::Failure => e
192: raise GeneratorError, "Caught #{e.class}: #{e}"
193: end
# File lib/json/pure/parser.rb, line 195
195: def parse_value
196: case
197: when scan(FLOAT)
198: Float(self[1])
199: when scan(INTEGER)
200: Integer(self[1])
201: when scan(TRUE)
202: true
203: when scan(FALSE)
204: false
205: when scan(NULL)
206: nil
207: when (string = parse_string) != UNPARSED
208: string
209: when scan(ARRAY_OPEN)
210: @current_nesting += 1
211: ary = parse_array
212: @current_nesting -= 1
213: ary
214: when scan(OBJECT_OPEN)
215: @current_nesting += 1
216: obj = parse_object
217: @current_nesting -= 1
218: obj
219: when @allow_nan && scan(NAN)
220: NaN
221: when @allow_nan && scan(INFINITY)
222: Infinity
223: when @allow_nan && scan(MINUS_INFINITY)
224: MinusInfinity
225: else
226: UNPARSED
227: end
228: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.