MultiJson::OkJson

Constants

Utagx
Utag2
Utag3
Utag4
Utag5
Umaskx
Umask2
Umask3
Umask4
Uchar1max
Uchar2max
Uchar3max
Ucharerr
Ustrerr
Usurrself
Usurr1
Usurr2
Usurr3
Spc
Unesc

Public Instance Methods

abbrev(s) click to toggle source
     # 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
arrenc(a) click to toggle source
     # File lib/multi_json/vendor/okjson.rb, line 439
439:     def arrenc(a)
440:       '[' + a.map{|x| valenc(x)}.join(',') + ']'
441:     end
arrparse(ts) click to toggle source

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
decode(s) click to toggle source

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
eat(typ, ts) click to toggle source
     # 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
encode(x) click to toggle source

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
falsetok(s) click to toggle source
     # File lib/multi_json/vendor/okjson.rb, line 225
225:     def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end
hexdec4(s) click to toggle source
     # 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
keyenc(k) click to toggle source
     # 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
lex(s) click to toggle source

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
nibble(c) click to toggle source
     # 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
nulltok(s) click to toggle source
     # File lib/multi_json/vendor/okjson.rb, line 223
223:     def nulltok(s);  s[0,4] == 'null'  ? [:val, 'null',  nil]   : [] end
numenc(x) click to toggle source
     # 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
numtok(s) click to toggle source
     # 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
objenc(x) click to toggle source
     # 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
objparse(ts) click to toggle source

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
pairparse(ts) click to toggle source

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
strenc(s) click to toggle source
     # 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
strtok(s) click to toggle source
     # 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
subst(u1, u2) click to toggle source
     # 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
surrogate?(u) click to toggle source
     # File lib/multi_json/vendor/okjson.rb, line 380
380:     def surrogate?(u)
381:       Usurr1 <= u && u < Usurr3
382:     end
textparse(ts) click to toggle source

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
tok(s) click to toggle source

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
truetok(s) click to toggle source
     # File lib/multi_json/vendor/okjson.rb, line 224
224:     def truetok(s);  s[0,4] == 'true'  ? [:val, 'true',  true]  : [] end
ucharcopy(t, s, i) click to toggle source

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
ucharenc(a, i, u) click to toggle source

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
unquote(q) click to toggle source

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
valenc(x) click to toggle source
     # 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
valparse(ts) click to toggle source

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.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.