Module ActiveSupport::OkJson
In: vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb

Methods

abbrev   arrenc   arrparse   decode   eat   encode   falsetok   hexdec4   keyenc   lex   nibble   nulltok   numenc   numtok   objenc   objparse   pairparse   strenc   strtok   subst   surrogate?   textparse   tok   truetok   ucharcopy   ucharenc   unquote   valenc   valparse  

Classes and Modules

Class ActiveSupport::OkJson::Error
Class ActiveSupport::OkJson::Utf8Error

Constants

Upstream = 'LTD7LBKLZWFF7OZK'
Utagx = 0x80
Utag2 = 0xc0
Utag3 = 0xe0
Utag4 = 0xf0
Utag5 = 0xF8
Umaskx = 0x3f
Umask2 = 0x1f
Umask3 = 0x0f
Umask4 = 0x07
Uchar1max = (1<<7) - 1
Uchar2max = (1<<11) - 1
Uchar3max = (1<<16) - 1
Ucharerr = 0xFFFD
Ustrerr = "\xef\xbf\xbd"
Usurrself = 0x10000
Usurr1 = 0xd800
Usurr2 = 0xdc00
Usurr3 = 0xe000
Spc = ' '[0]
Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t}

Public Instance methods

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 255
255:     def abbrev(s)
256:       t = s[0,10]
257:       p = t['`']
258:       t = t[0,p] if p
259:       t = t + '...' if t.length < s.length
260:       '`' + t + '`'
261:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 437
437:     def arrenc(a)
438:       '[' + a.map{|x| valenc(x)}.join(',') + ']'
439:     end

Parses an "array" in the sense of RFC 4627. Returns the parsed value and any trailing tokens.

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 137
137:     def arrparse(ts)
138:       ts = eat('[', ts)
139:       arr = []
140: 
141:       if ts[0][0] == ']'
142:         return arr, ts[1..-1]
143:       end
144: 
145:       v, ts = valparse(ts)
146:       arr << v
147: 
148:       if ts[0][0] == ']'
149:         return arr, ts[1..-1]
150:       end
151: 
152:       loop do
153:         ts = eat(',', ts)
154: 
155:         v, ts = valparse(ts)
156:         arr << v
157: 
158:         if ts[0][0] == ']'
159:           return arr, ts[1..-1]
160:         end
161:       end
162:     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.

[Source]

    # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 45
45:     def decode(s)
46:       ts = lex(s)
47:       v, ts = textparse(ts)
48:       if ts.length > 0
49:         raise Error, 'trailing garbage'
50:       end
51:       v
52:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 165
165:     def eat(typ, ts)
166:       if ts[0][0] != typ
167:         raise Error, "expected #{typ} (got #{ts[0].inspect})"
168:       end
169:       ts[1..-1]
170:     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.

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 407
407:     def encode(x)
408:       case x
409:       when Hash    then objenc(x)
410:       when Array   then arrenc(x)
411:       else
412:         raise Error, 'root value must be an Array or a Hash'
413:       end
414:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 227
227:     def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 366
366:     def hexdec4(s)
367:       if s.length != 4
368:         raise Error, 'short'
369:       end
370:       (nibble(s[0])<<12) | (nibble(s[1])<<8) | (nibble(s[2])<<4) | nibble(s[3])
371:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 442
442:     def keyenc(k)
443:       case k
444:       when String then strenc(k)
445:       else
446:         raise Error, "Hash key is not a string: #{k.inspect}"
447:       end
448:     end

Scans s and returns a list of json tokens, excluding white space (as defined in RFC 4627).

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 175
175:     def lex(s)
176:       ts = []
177:       while s.length > 0
178:         typ, lexeme, val = tok(s)
179:         if typ == nil
180:           raise Error, "invalid character at #{s[0,10].inspect}"
181:         end
182:         if typ != :space
183:           ts << [typ, lexeme, val]
184:         end
185:         s = s[lexeme.length..-1]
186:       end
187:       ts
188:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 387
387:     def nibble(c)
388:       case true
389:       when ?0 <= c && c <= ?9 then c.ord - ?0.ord
390:       when ?a <= c && c <= ?z then c.ord - ?a.ord + 10
391:       when ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
392:       else
393:         raise Error, "invalid hex code #{c}"
394:       end
395:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 225
225:     def nulltok(s);  s[0,4] == 'null'  ? [:val, 'null',  nil]   : [] end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 492
492:     def numenc(x)
493:       if ((x.nan? || x.infinite?) rescue false)
494:         raise Error, "Numeric cannot be represented: #{x}"
495:       end
496:       "#{x}"
497:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 230
230:     def numtok(s)
231:       m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
232:       if m && m.begin(0) == 0
233:         if m[3] && !m[2]
234:           [:val, m[0], Integer(m[1])*(10**Integer(m[3][1..-1]))]
235:         elsif m[2]
236:           [:val, m[0], Float(m[0])]
237:         else
238:           [:val, m[0], Integer(m[0])]
239:         end
240:       else
241:         []
242:       end
243:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 432
432:     def objenc(x)
433:       '{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}'
434:     end

Parses an "object" in the sense of RFC 4627. Returns the parsed value and any trailing tokens.

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 94
 94:     def objparse(ts)
 95:       ts = eat('{', ts)
 96:       obj = {}
 97: 
 98:       if ts[0][0] == '}'
 99:         return obj, ts[1..-1]
100:       end
101: 
102:       k, v, ts = pairparse(ts)
103:       obj[k] = v
104: 
105:       if ts[0][0] == '}'
106:         return obj, ts[1..-1]
107:       end
108: 
109:       loop do
110:         ts = eat(',', ts)
111: 
112:         k, v, ts = pairparse(ts)
113:         obj[k] = v
114: 
115:         if ts[0][0] == '}'
116:           return obj, ts[1..-1]
117:         end
118:       end
119:     end

Parses a "member" in the sense of RFC 4627. Returns the parsed values and any trailing tokens.

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 124
124:     def pairparse(ts)
125:       (typ, _, k), ts = ts[0], ts[1..-1]
126:       if typ != :str
127:         raise Error, "unexpected #{k.inspect}"
128:       end
129:       ts = eat(':', ts)
130:       v, ts = valparse(ts)
131:       [k, v, ts]
132:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 451
451:     def strenc(s)
452:       t = StringIO.new
453:       t.putc(?")
454:       r = 0
455: 
456:       # In ruby >= 1.9, s[r] is a codepoint, not a byte.
457:       rubydoesenc = s.class.method_defined?(:encoding)
458: 
459:       while r < s.length
460:         case s[r]
461:         when ?"  then t.print('\\"')
462:         when ?\\ then t.print('\\\\')
463:         when ?\b then t.print('\\b')
464:         when ?\f then t.print('\\f')
465:         when ?\n then t.print('\\n')
466:         when ?\r then t.print('\\r')
467:         when ?\t then t.print('\\t')
468:         else
469:           c = s[r]
470:           case true
471:           when rubydoesenc
472:             begin
473:               c.ord # will raise an error if c is invalid UTF-8
474:               t.write(c)
475:             rescue
476:               t.write(Ustrerr)
477:             end
478:           when Spc <= c && c <= ?~
479:             t.putc(c)
480:           else
481:             n = ucharcopy(t, s, r) # ensure valid UTF-8 output
482:             r += n - 1 # r is incremented below
483:           end
484:         end
485:         r += 1
486:       end
487:       t.putc(?")
488:       t.string
489:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 246
246:     def strtok(s)
247:       m = /"([^"\\]|\\["\/\\bfnrt]|\\u[0-9a-fA-F]{4})*"/.match(s)
248:       if ! m
249:         raise Error, "invalid string literal at #{abbrev(s)}"
250:       end
251:       [:str, m[0], unquote(m[0])]
252:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 374
374:     def subst(u1, u2)
375:       if Usurr1 <= u1 && u1 < Usurr2 && Usurr2 <= u2 && u2 < Usurr3
376:         return ((u1-Usurr1)<<10) | (u2-Usurr2) + Usurrself
377:       end
378:       return Ucharerr
379:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 382
382:     def surrogate?(u)
383:       Usurr1 <= u && u < Usurr3
384:     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.

[Source]

    # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 59
59:     def textparse(ts)
60:       if ts.length < 0
61:         raise Error, 'empty'
62:       end
63: 
64:       typ, _, val = ts[0]
65:       case typ
66:       when '{' then objparse(ts)
67:       when '[' then arrparse(ts)
68:       else
69:         raise Error, "unexpected #{val.inspect}"
70:       end
71:     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.

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 204
204:     def tok(s)
205:       case s[0]
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 ?[  then ['[', s[0,1], s[0,1]]
211:       when ?]  then [']', s[0,1], s[0,1]]
212:       when ?n  then nulltok(s)
213:       when ?t  then truetok(s)
214:       when ?f  then falsetok(s)
215:       when ?"  then strtok(s)
216:       when Spc then [:space, s[0,1], s[0,1]]
217:       when ?\t then [:space, s[0,1], s[0,1]]
218:       when ?\n then [:space, s[0,1], s[0,1]]
219:       when ?\r then [:space, s[0,1], s[0,1]]
220:       else          numtok(s)
221:       end
222:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 226
226:     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.

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 505
505:     def ucharcopy(t, s, i)
506:       n = s.length - i
507:       raise Utf8Error if n < 1
508: 
509:       c0 = s[i].ord
510: 
511:       # 1-byte, 7-bit sequence?
512:       if c0 < Utagx
513:         t.putc(c0)
514:         return 1
515:       end
516: 
517:       raise Utf8Error if c0 < Utag2 # unexpected continuation byte?
518: 
519:       raise Utf8Error if n < 2 # need continuation byte
520:       c1 = s[i+1].ord
521:       raise Utf8Error if c1 < Utagx || Utag2 <= c1
522: 
523:       # 2-byte, 11-bit sequence?
524:       if c0 < Utag3
525:         raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max
526:         t.putc(c0)
527:         t.putc(c1)
528:         return 2
529:       end
530: 
531:       # need second continuation byte
532:       raise Utf8Error if n < 3
533: 
534:       c2 = s[i+2].ord
535:       raise Utf8Error if c2 < Utagx || Utag2 <= c2
536: 
537:       # 3-byte, 16-bit sequence?
538:       if c0 < Utag4
539:         u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx)
540:         raise Utf8Error if u <= Uchar2max
541:         t.putc(c0)
542:         t.putc(c1)
543:         t.putc(c2)
544:         return 3
545:       end
546: 
547:       # need third continuation byte
548:       raise Utf8Error if n < 4
549:       c3 = s[i+3].ord
550:       raise Utf8Error if c3 < Utagx || Utag2 <= c3
551: 
552:       # 4-byte, 21-bit sequence?
553:       if c0 < Utag5
554:         u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx)
555:         raise Utf8Error if u <= Uchar3max
556:         t.putc(c0)
557:         t.putc(c1)
558:         t.putc(c2)
559:         t.putc(c3)
560:         return 4
561:       end
562: 
563:       raise Utf8Error
564:     rescue Utf8Error
565:       t.write(Ustrerr)
566:       return 1
567:     end

Encodes unicode character u as UTF-8 bytes in string a at position i. Returns the number of bytes written.

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 342
342:     def ucharenc(a, i, u)
343:       case true
344:       when u <= Uchar1max
345:         a[i] = (u & 0xff).chr
346:         1
347:       when u <= Uchar2max
348:         a[i+0] = (Utag2 | ((u>>6)&0xff)).chr
349:         a[i+1] = (Utagx | (u&Umaskx)).chr
350:         2
351:       when u <= Uchar3max
352:         a[i+0] = (Utag3 | ((u>>12)&0xff)).chr
353:         a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr
354:         a[i+2] = (Utagx | (u&Umaskx)).chr
355:         3
356:       else
357:         a[i+0] = (Utag4 | ((u>>18)&0xff)).chr
358:         a[i+1] = (Utagx | ((u>>12)&Umaskx)).chr
359:         a[i+2] = (Utagx | ((u>>6)&Umaskx)).chr
360:         a[i+3] = (Utagx | (u&Umaskx)).chr
361:         4
362:       end
363:     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.

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 267
267:     def unquote(q)
268:       q = q[1...-1]
269:       a = q.dup # allocate a big enough string
270:       rubydoesenc = false
271:       # In ruby >= 1.9, a[w] is a codepoint, not a byte.
272:       if a.class.method_defined?(:force_encoding)
273:         a.force_encoding('UTF-8')
274:         rubydoesenc = true
275:       end
276:       r, w = 0, 0
277:       while r < q.length
278:         c = q[r]
279:         case true
280:         when c == ?\\
281:           r += 1
282:           if r >= q.length
283:             raise Error, "string literal ends with a \"\\\": \"#{q}\""
284:           end
285: 
286:           case q[r]
287:           when ?",?\\,?/,?'
288:             a[w] = q[r]
289:             r += 1
290:             w += 1
291:           when ?b,?f,?n,?r,?t
292:             a[w] = Unesc[q[r]]
293:             r += 1
294:             w += 1
295:           when ?u
296:             r += 1
297:             uchar = begin
298:               hexdec4(q[r,4])
299:             rescue RuntimeError => e
300:               raise Error, "invalid escape sequence \\u#{q[r,4]}: #{e}"
301:             end
302:             r += 4
303:             if surrogate? uchar
304:               if q.length >= r+6
305:                 uchar1 = hexdec4(q[r+2,4])
306:                 uchar = subst(uchar, uchar1)
307:                 if uchar != Ucharerr
308:                   # A valid pair; consume.
309:                   r += 6
310:                 end
311:               end
312:             end
313:             if rubydoesenc
314:               a[w] = '' << uchar
315:               w += 1
316:             else
317:               w += ucharenc(a, w, uchar)
318:             end
319:           else
320:             raise Error, "invalid escape char #{q[r]} in \"#{q}\""
321:           end
322:         when c == ?", c < Spc
323:           raise Error, "invalid character in string literal \"#{q}\""
324:         else
325:           # Copy anything else byte-for-byte.
326:           # Valid UTF-8 will remain valid UTF-8.
327:           # Invalid UTF-8 will remain invalid UTF-8.
328:           # In ruby >= 1.9, c is a codepoint, not a byte,
329:           # in which case this is still what we want.
330:           a[w] = c
331:           r += 1
332:           w += 1
333:         end
334:       end
335:       a[0,w]
336:     end

[Source]

     # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 417
417:     def valenc(x)
418:       case x
419:       when Hash    then objenc(x)
420:       when Array   then arrenc(x)
421:       when String  then strenc(x)
422:       when Numeric then numenc(x)
423:       when true    then "true"
424:       when false   then "false"
425:       when nil     then "null"
426:       else
427:         raise Error, "cannot encode #{x.class}: #{x.inspect}"
428:       end
429:     end

Parses a "value" in the sense of RFC 4627. Returns the parsed value and any trailing tokens.

[Source]

    # File vendor/rails/activesupport/lib/active_support/json/backends/okjson.rb, line 76
76:     def valparse(ts)
77:       if ts.length < 0
78:         raise Error, 'empty'
79:       end
80: 
81:       typ, _, val = ts[0]
82:       case typ
83:       when '{' then objparse(ts)
84:       when '[' then arrparse(ts)
85:       when :val,:str then [val, ts[1..-1]]
86:       else
87:         raise Error, "unexpected #{val.inspect}"
88:       end
89:     end

[Validate]