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.