# File lib/multi_json/vendor/okjson.rb, line 253 253: def abbrev(s) 254: t = s[0,10] 255: p = t['`'] 256: t = t[0,p] if p 257: t = t + '...' if t.length < s.length 258: '`' + t + '`' 259: end
# File lib/multi_json/vendor/okjson.rb, line 439 439: def arrenc(a) 440: '[' + a.map{|x| valenc(x)}.join(',') + ']' 441: end
Parses an “array” in the sense of RFC 4627. Returns the parsed value and any trailing tokens.
# File lib/multi_json/vendor/okjson.rb, line 135 135: def arrparse(ts) 136: ts = eat('[', ts) 137: arr = [] 138: 139: if ts[0][0] == ']' 140: return arr, ts[1..1] 141: end 142: 143: v, ts = valparse(ts) 144: arr << v 145: 146: if ts[0][0] == ']' 147: return arr, ts[1..1] 148: end 149: 150: loop do 151: ts = eat(',', ts) 152: 153: v, ts = valparse(ts) 154: arr << v 155: 156: if ts[0][0] == ']' 157: return arr, ts[1..1] 158: end 159: end 160: end
Decodes a json document in string s and returns the corresponding ruby value. String s must be valid UTF-8. If you have a string in some other encoding, convert it first.
String values in the resulting structure will be UTF-8.
# File lib/multi_json/vendor/okjson.rb, line 43 43: def decode(s) 44: ts = lex(s) 45: v, ts = textparse(ts) 46: if ts.length > 0 47: raise Error, 'trailing garbage' 48: end 49: v 50: end
# File lib/multi_json/vendor/okjson.rb, line 163 163: def eat(typ, ts) 164: if ts[0][0] != typ 165: raise Error, "expected #{typ} (got #{ts[0].inspect})" 166: end 167: ts[1..1] 168: end
Encodes x into a json text. It may contain only Array, Hash, String, Numeric, true, false, nil. (Note, this list excludes Symbol.) X itself must be an Array or a Hash. No other value can be encoded, and an error will be raised if x contains any other value, such as Nan, Infinity, Symbol, and Proc, or if a Hash key is not a String. Strings contained in x must be valid UTF-8.
# File lib/multi_json/vendor/okjson.rb, line 405 405: def encode(x) 406: case x 407: when Hash then objenc(x) 408: when Array then arrenc(x) 409: else 410: raise Error, 'root value must be an Array or a Hash' 411: end 412: end
# File lib/multi_json/vendor/okjson.rb, line 225 225: def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end
# File lib/multi_json/vendor/okjson.rb, line 364 364: def hexdec4(s) 365: if s.length != 4 366: raise Error, 'short' 367: end 368: (nibble(s[0])<<12) | (nibble(s[1])<<8) | (nibble(s[2])<<4) | nibble(s[3]) 369: end
# File lib/multi_json/vendor/okjson.rb, line 444 444: def keyenc(k) 445: case k 446: when String then strenc(k) 447: else 448: raise Error, "Hash key is not a string: #{k.inspect}" 449: end 450: end
Scans s and returns a list of json tokens, excluding white space (as defined in RFC 4627).
# File lib/multi_json/vendor/okjson.rb, line 173 173: def lex(s) 174: ts = [] 175: while s.length > 0 176: typ, lexeme, val = tok(s) 177: if typ == nil 178: raise Error, "invalid character at #{s[0,10].inspect}" 179: end 180: if typ != :space 181: ts << [typ, lexeme, val] 182: end 183: s = s[lexeme.length..1] 184: end 185: ts 186: end
# File lib/multi_json/vendor/okjson.rb, line 385 385: def nibble(c) 386: case true 387: when 00 <= c && c <= 99 then c.ord - 00.ord 388: when aa <= c && c <= zz then c.ord - aa.ord + 10 389: when AA <= c && c <= ZZ then c.ord - AA.ord + 10 390: else 391: raise Error, "invalid hex code #{c}" 392: end 393: end
# File lib/multi_json/vendor/okjson.rb, line 223 223: def nulltok(s); s[0,4] == 'null' ? [:val, 'null', nil] : [] end
# File lib/multi_json/vendor/okjson.rb, line 494 494: def numenc(x) 495: if ((x.nan? || x.infinite?) rescue false) 496: raise Error, "Numeric cannot be represented: #{x}" 497: end 498: "#{x}" 499: end
# File lib/multi_json/vendor/okjson.rb, line 228 228: def numtok(s) 229: m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s) 230: if m && m.begin(0) == 0 231: if m[3] && !m[2] 232: [:val, m[0], Integer(m[1])*(10**Integer(m[3][1..1]))] 233: elsif m[2] 234: [:val, m[0], Float(m[0])] 235: else 236: [:val, m[0], Integer(m[0])] 237: end 238: else 239: [] 240: end 241: end
# File lib/multi_json/vendor/okjson.rb, line 434 434: def objenc(x) 435: '{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}' 436: end
Parses an “object” in the sense of RFC 4627. Returns the parsed value and any trailing tokens.
# File lib/multi_json/vendor/okjson.rb, line 92 92: def objparse(ts) 93: ts = eat('{', ts) 94: obj = {} 95: 96: if ts[0][0] == '}' 97: return obj, ts[1..1] 98: end 99: 100: k, v, ts = pairparse(ts) 101: obj[k] = v 102: 103: if ts[0][0] == '}' 104: return obj, ts[1..1] 105: end 106: 107: loop do 108: ts = eat(',', ts) 109: 110: k, v, ts = pairparse(ts) 111: obj[k] = v 112: 113: if ts[0][0] == '}' 114: return obj, ts[1..1] 115: end 116: end 117: end
Parses a “member” in the sense of RFC 4627. Returns the parsed values and any trailing tokens.
# File lib/multi_json/vendor/okjson.rb, line 122 122: def pairparse(ts) 123: (typ, _, k), ts = ts[0], ts[1..1] 124: if typ != :str 125: raise Error, "unexpected #{k.inspect}" 126: end 127: ts = eat(':', ts) 128: v, ts = valparse(ts) 129: [k, v, ts] 130: end
# File lib/multi_json/vendor/okjson.rb, line 453 453: def strenc(s) 454: t = StringIO.new 455: t.putc("") 456: r = 0 457: 458: # In ruby >= 1.9, s[r] is a codepoint, not a byte. 459: rubydoesenc = s.class.method_defined?(:encoding) 460: 461: while r < s.length 462: case s[r] 463: when "" then t.print('\"') 464: when \\\ then t.print('\\') 465: when \b\ then t.print('\b') 466: when \f\ then t.print('\f') 467: when \n\ then t.print('\n') 468: when \r\ then t.print('\r') 469: when \t\ then t.print('\t') 470: else 471: c = s[r] 472: case true 473: when rubydoesenc 474: begin 475: c.ord # will raise an error if c is invalid UTF-8 476: t.write(c) 477: rescue 478: t.write(Ustrerr) 479: end 480: when Spc <= c && c <= ~~ 481: t.putc(c) 482: else 483: n = ucharcopy(t, s, r) # ensure valid UTF-8 output 484: r += n - 1 # r is incremented below 485: end 486: end 487: r += 1 488: end 489: t.putc("") 490: t.string 491: end
# File lib/multi_json/vendor/okjson.rb, line 244 244: def strtok(s) 245: m = /"([^"\\]|\\["\/\\bfnrt]|\\u[0-9a-fA-F]{4})*"/.match(s) 246: if ! m 247: raise Error, "invalid string literal at #{abbrev(s)}" 248: end 249: [:str, m[0], unquote(m[0])] 250: end
# File lib/multi_json/vendor/okjson.rb, line 372 372: def subst(u1, u2) 373: if Usurr1 <= u1 && u1 < Usurr2 && Usurr2 <= u2 && u2 < Usurr3 374: return ((u1-Usurr1)<<10) | (u2-Usurr2) + Usurrself 375: end 376: return Ucharerr 377: end
# File lib/multi_json/vendor/okjson.rb, line 380 380: def surrogate?(u) 381: Usurr1 <= u && u < Usurr3 382: end
Parses a “json text” in the sense of RFC 4627. Returns the parsed value and any trailing tokens. Note: this is almost the same as valparse, except that it does not accept atomic values.
# File lib/multi_json/vendor/okjson.rb, line 57 57: def textparse(ts) 58: if ts.length < 0 59: raise Error, 'empty' 60: end 61: 62: typ, _, val = ts[0] 63: case typ 64: when '{' then objparse(ts) 65: when '[' then arrparse(ts) 66: else 67: raise Error, "unexpected #{val.inspect}" 68: end 69: end
Scans the first token in s and returns a 3-element list, or nil if s does not begin with a valid token.
The first list element is one of ’{’, ’}’, ’:’, ’,’, ’[’, ’]’, :val, :str, and :space.
The second element is the lexeme.
The third element is the value of the token for :val and :str, otherwise it is the lexeme.
# File lib/multi_json/vendor/okjson.rb, line 202 202: def tok(s) 203: case s[0] 204: when {{ then ['{', s[0,1], s[0,1]] 205: when }} then ['}', s[0,1], s[0,1]] 206: when :: then [':', s[0,1], s[0,1]] 207: when ,, then [',', s[0,1], s[0,1]] 208: when [[ then ['[', s[0,1], s[0,1]] 209: when ]] then [']', s[0,1], s[0,1]] 210: when nn then nulltok(s) 211: when tt then truetok(s) 212: when ff then falsetok(s) 213: when "" then strtok(s) 214: when Spc then [:space, s[0,1], s[0,1]] 215: when \t\ then [:space, s[0,1], s[0,1]] 216: when \n\ then [:space, s[0,1], s[0,1]] 217: when \r\ then [:space, s[0,1], s[0,1]] 218: else numtok(s) 219: end 220: end
# File lib/multi_json/vendor/okjson.rb, line 224 224: def truetok(s); s[0,4] == 'true' ? [:val, 'true', true] : [] end
Copies the valid UTF-8 bytes of a single character from string s at position i to I/O object t, and returns the number of bytes copied. If no valid UTF-8 char exists at position i, ucharcopy writes Ustrerr and returns 1.
# File lib/multi_json/vendor/okjson.rb, line 507 507: def ucharcopy(t, s, i) 508: n = s.length - i 509: raise Utf8Error if n < 1 510: 511: c0 = s[i].ord 512: 513: # 1-byte, 7-bit sequence? 514: if c0 < Utagx 515: t.putc(c0) 516: return 1 517: end 518: 519: raise Utf8Error if c0 < Utag2 # unexpected continuation byte? 520: 521: raise Utf8Error if n < 2 # need continuation byte 522: c1 = s[i+1].ord 523: raise Utf8Error if c1 < Utagx || Utag2 <= c1 524: 525: # 2-byte, 11-bit sequence? 526: if c0 < Utag3 527: raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max 528: t.putc(c0) 529: t.putc(c1) 530: return 2 531: end 532: 533: # need second continuation byte 534: raise Utf8Error if n < 3 535: 536: c2 = s[i+2].ord 537: raise Utf8Error if c2 < Utagx || Utag2 <= c2 538: 539: # 3-byte, 16-bit sequence? 540: if c0 < Utag4 541: u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx) 542: raise Utf8Error if u <= Uchar2max 543: t.putc(c0) 544: t.putc(c1) 545: t.putc(c2) 546: return 3 547: end 548: 549: # need third continuation byte 550: raise Utf8Error if n < 4 551: c3 = s[i+3].ord 552: raise Utf8Error if c3 < Utagx || Utag2 <= c3 553: 554: # 4-byte, 21-bit sequence? 555: if c0 < Utag5 556: u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx) 557: raise Utf8Error if u <= Uchar3max 558: t.putc(c0) 559: t.putc(c1) 560: t.putc(c2) 561: t.putc(c3) 562: return 4 563: end 564: 565: raise Utf8Error 566: rescue Utf8Error 567: t.write(Ustrerr) 568: return 1 569: end
Encodes unicode character u as UTF-8 bytes in string a at position i. Returns the number of bytes written.
# File lib/multi_json/vendor/okjson.rb, line 340 340: def ucharenc(a, i, u) 341: case true 342: when u <= Uchar1max 343: a[i] = (u & 0xff).chr 344: 1 345: when u <= Uchar2max 346: a[i+0] = (Utag2 | ((u>>6)&0xff)).chr 347: a[i+1] = (Utagx | (u&Umaskx)).chr 348: 2 349: when u <= Uchar3max 350: a[i+0] = (Utag3 | ((u>>12)&0xff)).chr 351: a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr 352: a[i+2] = (Utagx | (u&Umaskx)).chr 353: 3 354: else 355: a[i+0] = (Utag4 | ((u>>18)&0xff)).chr 356: a[i+1] = (Utagx | ((u>>12)&Umaskx)).chr 357: a[i+2] = (Utagx | ((u>>6)&Umaskx)).chr 358: a[i+3] = (Utagx | (u&Umaskx)).chr 359: 4 360: end 361: end
Converts a quoted json string literal q into a UTF-8-encoded string. The rules are different than for Ruby, so we cannot use eval. Unquote will raise an error if q contains control characters.
# File lib/multi_json/vendor/okjson.rb, line 265 265: def unquote(q) 266: q = q[1...1] 267: a = q.dup # allocate a big enough string 268: rubydoesenc = false 269: # In ruby >= 1.9, a[w] is a codepoint, not a byte. 270: if a.class.method_defined?(:force_encoding) 271: a.force_encoding('UTF-8') 272: rubydoesenc = true 273: end 274: r, w = 0, 0 275: while r < q.length 276: c = q[r] 277: case true 278: when c == \\\ 279: r += 1 280: if r >= q.length 281: raise Error, "string literal ends with a \"\\\": \"#{q}\"" 282: end 283: 284: case q[r] 285: when "",\\\,//,'' 286: a[w] = q[r] 287: r += 1 288: w += 1 289: when bb,ff,nn,rr,tt 290: a[w] = Unesc[q[r]] 291: r += 1 292: w += 1 293: when uu 294: r += 1 295: uchar = begin 296: hexdec4(q[r,4]) 297: rescue RuntimeError => e 298: raise Error, "invalid escape sequence \\u#{q[r,4]}: #{e}" 299: end 300: r += 4 301: if surrogate? uchar 302: if q.length >= r+6 303: uchar1 = hexdec4(q[r+2,4]) 304: uchar = subst(uchar, uchar1) 305: if uchar != Ucharerr 306: # A valid pair; consume. 307: r += 6 308: end 309: end 310: end 311: if rubydoesenc 312: a[w] = '' << uchar 313: w += 1 314: else 315: w += ucharenc(a, w, uchar) 316: end 317: else 318: raise Error, "invalid escape char #{q[r]} in \"#{q}\"" 319: end 320: when c == "", c < Spc 321: raise Error, "invalid character in string literal \"#{q}\"" 322: else 323: # Copy anything else byte-for-byte. 324: # Valid UTF-8 will remain valid UTF-8. 325: # Invalid UTF-8 will remain invalid UTF-8. 326: # In ruby >= 1.9, c is a codepoint, not a byte, 327: # in which case this is still what we want. 328: a[w] = c 329: r += 1 330: w += 1 331: end 332: end 333: a[0,w] 334: end
# File lib/multi_json/vendor/okjson.rb, line 415 415: def valenc(x) 416: case x 417: when Hash then objenc(x) 418: when Array then arrenc(x) 419: when String then strenc(x) 420: when Numeric then numenc(x) 421: when true then "true" 422: when false then "false" 423: when nil then "null" 424: else 425: if x.respond_to?(:to_json) 426: x.to_json 427: else 428: raise Error, "cannot encode #{x.class}: #{x.inspect}" 429: end 430: end 431: end
Parses a “value” in the sense of RFC 4627. Returns the parsed value and any trailing tokens.
# File lib/multi_json/vendor/okjson.rb, line 74 74: def valparse(ts) 75: if ts.length < 0 76: raise Error, 'empty' 77: end 78: 79: typ, _, val = ts[0] 80: case typ 81: when '{' then objparse(ts) 82: when '[' then arrparse(ts) 83: when :val,:str then [val, ts[1..1]] 84: else 85: raise Error, "unexpected #{val.inspect}" 86: end 87: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.