multi_json 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +0 -2
- data/lib/multi_json.rb +51 -28
- data/lib/multi_json/{engines → adapters}/json_common.rb +5 -7
- data/lib/multi_json/{engines → adapters}/json_gem.rb +3 -3
- data/lib/multi_json/{engines → adapters}/json_pure.rb +3 -3
- data/lib/multi_json/{engines → adapters}/nsjsonserialization.rb +6 -6
- data/lib/multi_json/adapters/oj.rb +20 -0
- data/lib/multi_json/{engines → adapters}/ok_json.rb +4 -4
- data/lib/multi_json/{engines → adapters}/yajl.rb +4 -4
- data/lib/multi_json/vendor/{ok_json.rb → okjson.rb} +81 -66
- data/lib/multi_json/version.rb +1 -1
- data/multi_json.gemspec +17 -0
- data/spec/{engine_shared_example.rb → adapter_shared_example.rb} +28 -28
- data/spec/helper.rb +3 -3
- data/spec/multi_json_spec.rb +20 -20
- metadata +20 -14
- data/lib/multi_json/engines/oj.rb +0 -22
data/README.md
CHANGED
@@ -88,12 +88,10 @@ implementations:
|
|
88
88
|
* Ruby 1.9.3
|
89
89
|
* [JRuby][]
|
90
90
|
* [Rubinius][]
|
91
|
-
* [Ruby Enterprise Edition][ree]
|
92
91
|
* [MacRuby][] (not tested on Travis CI)
|
93
92
|
|
94
93
|
[jruby]: http://www.jruby.org/
|
95
94
|
[rubinius]: http://rubini.us/
|
96
|
-
[ree]: http://www.rubyenterpriseedition.com/
|
97
95
|
[macruby]: http://www.macruby.org/
|
98
96
|
|
99
97
|
If something doesn't work on one of these interpreters, it should be considered
|
data/lib/multi_json.rb
CHANGED
@@ -10,14 +10,7 @@ module MultiJson
|
|
10
10
|
|
11
11
|
module_function
|
12
12
|
|
13
|
-
@
|
14
|
-
|
15
|
-
# Get the current engine class.
|
16
|
-
def engine
|
17
|
-
return @engine if @engine
|
18
|
-
self.engine = self.default_engine
|
19
|
-
@engine
|
20
|
-
end
|
13
|
+
@adapter = nil
|
21
14
|
|
22
15
|
REQUIREMENT_MAP = [
|
23
16
|
["oj", :oj],
|
@@ -26,65 +19,95 @@ module MultiJson
|
|
26
19
|
["json/pure", :json_pure]
|
27
20
|
]
|
28
21
|
|
29
|
-
|
30
|
-
|
31
|
-
# The default engine based on what you currently
|
22
|
+
# The default adapter based on what you currently
|
32
23
|
# have loaded and installed. First checks to see
|
33
|
-
# if any
|
24
|
+
# if any adapters are already loaded, then checks
|
34
25
|
# to see which are installed if none are loaded.
|
35
|
-
def
|
26
|
+
def default_adapter
|
36
27
|
return :oj if defined?(::Oj)
|
37
28
|
return :yajl if defined?(::Yajl)
|
38
29
|
return :json_gem if defined?(::JSON)
|
39
30
|
|
40
|
-
REQUIREMENT_MAP.each do |(library,
|
31
|
+
REQUIREMENT_MAP.each do |(library, adapter)|
|
41
32
|
begin
|
42
33
|
require library
|
43
|
-
return
|
34
|
+
return adapter
|
44
35
|
rescue LoadError
|
45
36
|
next
|
46
37
|
end
|
47
38
|
end
|
48
39
|
|
49
|
-
Kernel.warn
|
40
|
+
Kernel.warn "[WARNING] MultiJson is using the default adapter (ok_json). We recommend loading a different JSON library to improve performance."
|
50
41
|
:ok_json
|
51
42
|
end
|
52
43
|
|
44
|
+
# TODO: Remove for 2.0 release (but no sooner)
|
45
|
+
def engine
|
46
|
+
Kernel.warn "#{Kernel.caller.first}: [DEPRECATION] MultiJson.engine is deprecated and will be removed in the next major version. Use MultiJson.adapter instead."
|
47
|
+
self.adapter
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get the current adapter class.
|
51
|
+
def adapter
|
52
|
+
return @adapter if @adapter
|
53
|
+
self.use self.default_adapter
|
54
|
+
@adapter
|
55
|
+
end
|
56
|
+
|
57
|
+
# TODO: Remove for 2.0 release (but no sooner)
|
58
|
+
def adapter=(new_adapter)
|
59
|
+
Kernel.warn "#{Kernel.caller.first}: [DEPRECATION] MultiJson.adapter= is deprecated and will be removed in the next major version. Use MultiJson.use instead."
|
60
|
+
self.use(new_adapter)
|
61
|
+
end
|
62
|
+
|
53
63
|
# Set the JSON parser utilizing a symbol, string, or class.
|
54
64
|
# Supported by default are:
|
55
65
|
#
|
66
|
+
# * <tt>:oj</tt>
|
56
67
|
# * <tt>:json_gem</tt>
|
57
68
|
# * <tt>:json_pure</tt>
|
58
69
|
# * <tt>:ok_json</tt>
|
59
70
|
# * <tt>:yajl</tt>
|
60
71
|
# * <tt>:nsjsonserialization</tt> (MacRuby only)
|
61
|
-
def
|
62
|
-
case
|
72
|
+
def use(new_adapter)
|
73
|
+
case new_adapter
|
63
74
|
when String, Symbol
|
64
|
-
require "multi_json/
|
65
|
-
@
|
75
|
+
require "multi_json/adapters/#{new_adapter}"
|
76
|
+
@adapter = MultiJson::Adapters.const_get("#{new_adapter.to_s.split('_').map{|s| s.capitalize}.join('')}")
|
66
77
|
when NilClass
|
67
|
-
@
|
78
|
+
@adapter = nil
|
68
79
|
when Class
|
69
|
-
@
|
80
|
+
@adapter = new_adapter
|
70
81
|
else
|
71
|
-
raise "Did not recognize your
|
82
|
+
raise "Did not recognize your adapter specification. Please specify either a symbol or a class."
|
72
83
|
end
|
73
84
|
end
|
74
85
|
|
86
|
+
# TODO: Remove for 2.0 release (but no sooner)
|
87
|
+
def decode(string, options={})
|
88
|
+
Kernel.warn "#{Kernel.caller.first}: [DEPRECATION] MultiJson.decode is deprecated and will be removed in the next major version. Use MultiJson.load instead."
|
89
|
+
self.load(string, options)
|
90
|
+
end
|
91
|
+
|
75
92
|
# Decode a JSON string into Ruby.
|
76
93
|
#
|
77
94
|
# <b>Options</b>
|
78
95
|
#
|
79
96
|
# <tt>:symbolize_keys</tt> :: If true, will use symbols instead of strings for the keys.
|
80
|
-
def
|
81
|
-
|
82
|
-
rescue
|
97
|
+
def load(string, options={})
|
98
|
+
adapter.load(string, options)
|
99
|
+
rescue adapter::ParseError => exception
|
83
100
|
raise DecodeError.new(exception.message, exception.backtrace, string)
|
84
101
|
end
|
85
102
|
|
103
|
+
# TODO: Remove for 2.0 release (but no sooner)
|
104
|
+
def encode(object, options={})
|
105
|
+
Kernel.warn "#{Kernel.caller.first}: [DEPRECATION] MultiJson.encode is deprecated and will be removed in the next major version. Use MultiJson.dump instead."
|
106
|
+
self.dump(object, options)
|
107
|
+
end
|
108
|
+
|
86
109
|
# Encodes a Ruby object as JSON.
|
87
|
-
def
|
88
|
-
|
110
|
+
def dump(object, options={})
|
111
|
+
adapter.dump(object, options)
|
89
112
|
end
|
90
113
|
end
|
@@ -1,15 +1,13 @@
|
|
1
1
|
module MultiJson
|
2
|
-
module
|
2
|
+
module Adapters
|
3
3
|
module JsonCommon
|
4
4
|
|
5
|
-
def
|
6
|
-
opts = {}
|
7
|
-
opts[:symbolize_names] = options[:symbolize_keys]
|
5
|
+
def load(string, options={})
|
8
6
|
string = string.read if string.respond_to?(:read)
|
9
|
-
::JSON.parse(string,
|
7
|
+
::JSON.parse(string, :symbolize_names => options[:symbolize_keys])
|
10
8
|
end
|
11
9
|
|
12
|
-
def
|
10
|
+
def dump(object, options={})
|
13
11
|
object.to_json(process_options(options))
|
14
12
|
end
|
15
13
|
|
@@ -19,7 +17,7 @@ module MultiJson
|
|
19
17
|
return options if options.empty?
|
20
18
|
opts = {}
|
21
19
|
opts.merge!(JSON::PRETTY_STATE_PROTOTYPE.to_h) if options.delete(:pretty)
|
22
|
-
opts.merge!
|
20
|
+
opts.merge!(options)
|
23
21
|
end
|
24
22
|
|
25
23
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'json' unless defined?(::JSON)
|
2
|
-
require 'multi_json/
|
2
|
+
require 'multi_json/adapters/json_common'
|
3
3
|
|
4
4
|
module MultiJson
|
5
|
-
module
|
6
|
-
# Use the JSON gem to
|
5
|
+
module Adapters
|
6
|
+
# Use the JSON gem to dump/load.
|
7
7
|
class JsonGem
|
8
8
|
ParseError = ::JSON::ParserError
|
9
9
|
extend JsonCommon
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'json/pure' unless defined?(::JSON)
|
2
|
-
require 'multi_json/
|
2
|
+
require 'multi_json/adapters/json_common'
|
3
3
|
|
4
4
|
module MultiJson
|
5
|
-
module
|
6
|
-
# Use JSON pure to
|
5
|
+
module Adapters
|
6
|
+
# Use JSON pure to dump/load.
|
7
7
|
class JsonPure
|
8
8
|
ParseError = ::JSON::ParserError
|
9
9
|
extend JsonCommon
|
@@ -1,12 +1,12 @@
|
|
1
1
|
framework 'Foundation'
|
2
|
-
require 'multi_json/
|
2
|
+
require 'multi_json/adapters/ok_json'
|
3
3
|
|
4
4
|
module MultiJson
|
5
|
-
module
|
6
|
-
class Nsjsonserialization < MultiJson::
|
5
|
+
module Adapters
|
6
|
+
class Nsjsonserialization < MultiJson::Adapters::OkJson
|
7
7
|
ParseError = ::MultiJson::OkJson::Error
|
8
8
|
|
9
|
-
def self.
|
9
|
+
def self.load(string, options={})
|
10
10
|
string = string.read if string.respond_to?(:read)
|
11
11
|
data = string.dataUsingEncoding(NSUTF8StringEncoding)
|
12
12
|
object = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves, error: nil)
|
@@ -14,11 +14,11 @@ module MultiJson
|
|
14
14
|
object = symbolize_keys(object) if options[:symbolize_keys]
|
15
15
|
object
|
16
16
|
else
|
17
|
-
super(string, options
|
17
|
+
super(string, options={})
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
def self.
|
21
|
+
def self.dump(object, options={})
|
22
22
|
pretty = options[:pretty] ? NSJSONWritingPrettyPrinted : 0
|
23
23
|
object = object.as_json if object.respond_to?(:as_json)
|
24
24
|
if NSJSONSerialization.isValidJSONObject(object)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'oj' unless defined?(::Oj)
|
2
|
+
|
3
|
+
module MultiJson
|
4
|
+
module Adapters
|
5
|
+
# Use the Oj library to dump/load.
|
6
|
+
class Oj
|
7
|
+
ParseError = SyntaxError
|
8
|
+
|
9
|
+
::Oj.default_options = {:mode => :compat}
|
10
|
+
|
11
|
+
def self.load(string, options={}) #:nodoc:
|
12
|
+
::Oj.load(string, :symbol_keys => options[:symbolize_keys])
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.dump(object, options={}) #:nodoc:
|
16
|
+
::Oj.dump(object, options)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,17 +1,17 @@
|
|
1
|
-
require 'multi_json/vendor/
|
1
|
+
require 'multi_json/vendor/okjson'
|
2
2
|
|
3
3
|
module MultiJson
|
4
|
-
module
|
4
|
+
module Adapters
|
5
5
|
class OkJson
|
6
6
|
ParseError = ::MultiJson::OkJson::Error
|
7
7
|
|
8
|
-
def self.
|
8
|
+
def self.load(string, options={}) #:nodoc:
|
9
9
|
string = string.read if string.respond_to?(:read)
|
10
10
|
result = ::MultiJson::OkJson.decode(string)
|
11
11
|
options[:symbolize_keys] ? symbolize_keys(result) : result
|
12
12
|
end
|
13
13
|
|
14
|
-
def self.
|
14
|
+
def self.dump(object, options={}) #:nodoc:
|
15
15
|
::MultiJson::OkJson.valenc(stringify_keys(object))
|
16
16
|
end
|
17
17
|
|
@@ -1,16 +1,16 @@
|
|
1
1
|
require 'yajl' unless defined?(::Yajl)
|
2
2
|
|
3
3
|
module MultiJson
|
4
|
-
module
|
5
|
-
# Use the Yajl-Ruby library to
|
4
|
+
module Adapters
|
5
|
+
# Use the Yajl-Ruby library to dump/load.
|
6
6
|
class Yajl
|
7
7
|
ParseError = ::Yajl::ParseError
|
8
8
|
|
9
|
-
def self.
|
9
|
+
def self.load(string, options={}) #:nodoc:
|
10
10
|
::Yajl::Parser.new(:symbolize_keys => options[:symbolize_keys]).parse(string)
|
11
11
|
end
|
12
12
|
|
13
|
-
def self.
|
13
|
+
def self.dump(object, options={}) #:nodoc:
|
14
14
|
::Yajl::Encoder.encode(object, options)
|
15
15
|
end
|
16
16
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Copyright 2011, 2012 Keith Rarick
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
6
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -166,7 +168,7 @@ module MultiJson
|
|
166
168
|
end
|
167
169
|
|
168
170
|
|
169
|
-
#
|
171
|
+
# Scans s and returns a list of json tokens,
|
170
172
|
# excluding white space (as defined in RFC 4627).
|
171
173
|
def lex(s)
|
172
174
|
ts = []
|
@@ -186,7 +188,7 @@ module MultiJson
|
|
186
188
|
|
187
189
|
# Scans the first token in s and
|
188
190
|
# returns a 3-element list, or nil
|
189
|
-
# if
|
191
|
+
# if s does not begin with a valid token.
|
190
192
|
#
|
191
193
|
# The first list element is one of
|
192
194
|
# '{', '}', ':', ',', '[', ']',
|
@@ -218,9 +220,9 @@ module MultiJson
|
|
218
220
|
end
|
219
221
|
|
220
222
|
|
221
|
-
def nulltok(s); s[0,4] == 'null'
|
222
|
-
def truetok(s); s[0,4] == 'true'
|
223
|
-
def falsetok(s); s[0,5] == 'false'
|
223
|
+
def nulltok(s); s[0,4] == 'null' ? [:val, 'null', nil] : [] end
|
224
|
+
def truetok(s); s[0,4] == 'true' ? [:val, 'true', true] : [] end
|
225
|
+
def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end
|
224
226
|
|
225
227
|
|
226
228
|
def numtok(s)
|
@@ -233,6 +235,8 @@ module MultiJson
|
|
233
235
|
else
|
234
236
|
[:val, m[0], Integer(m[0])]
|
235
237
|
end
|
238
|
+
else
|
239
|
+
[]
|
236
240
|
end
|
237
241
|
end
|
238
242
|
|
@@ -261,6 +265,12 @@ module MultiJson
|
|
261
265
|
def unquote(q)
|
262
266
|
q = q[1...-1]
|
263
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
|
264
274
|
r, w = 0, 0
|
265
275
|
while r < q.length
|
266
276
|
c = q[r]
|
@@ -298,7 +308,12 @@ module MultiJson
|
|
298
308
|
end
|
299
309
|
end
|
300
310
|
end
|
301
|
-
|
311
|
+
if rubydoesenc
|
312
|
+
a[w] = '' << uchar
|
313
|
+
w += 1
|
314
|
+
else
|
315
|
+
w += ucharenc(a, w, uchar)
|
316
|
+
end
|
302
317
|
else
|
303
318
|
raise Error, "invalid escape char #{q[r]} in \"#{q}\""
|
304
319
|
end
|
@@ -308,6 +323,8 @@ module MultiJson
|
|
308
323
|
# Copy anything else byte-for-byte.
|
309
324
|
# Valid UTF-8 will remain valid UTF-8.
|
310
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.
|
311
328
|
a[w] = c
|
312
329
|
r += 1
|
313
330
|
w += 1
|
@@ -360,15 +377,6 @@ module MultiJson
|
|
360
377
|
end
|
361
378
|
|
362
379
|
|
363
|
-
def unsubst(u)
|
364
|
-
if u < Usurrself || u > Umax || surrogate?(u)
|
365
|
-
return Ucharerr, Ucharerr
|
366
|
-
end
|
367
|
-
u -= Usurrself
|
368
|
-
[Usurr1 + ((u>>10)&0x3ff), Usurr2 + (u&0x3ff)]
|
369
|
-
end
|
370
|
-
|
371
|
-
|
372
380
|
def surrogate?(u)
|
373
381
|
Usurr1 <= u && u < Usurr3
|
374
382
|
end
|
@@ -446,6 +454,10 @@ module MultiJson
|
|
446
454
|
t = StringIO.new
|
447
455
|
t.putc(?")
|
448
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
|
+
|
449
461
|
while r < s.length
|
450
462
|
case s[r]
|
451
463
|
when ?" then t.print('\\"')
|
@@ -458,23 +470,18 @@ module MultiJson
|
|
458
470
|
else
|
459
471
|
c = s[r]
|
460
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
|
461
480
|
when Spc <= c && c <= ?~
|
462
481
|
t.putc(c)
|
463
|
-
when true
|
464
|
-
u, size = uchardec(s, r)
|
465
|
-
r += size - 1 # we add one more at the bottom of the loop
|
466
|
-
if u < 0x10000
|
467
|
-
t.print('\\u')
|
468
|
-
hexenc4(t, u)
|
469
|
-
else
|
470
|
-
u1, u2 = unsubst(u)
|
471
|
-
t.print('\\u')
|
472
|
-
hexenc4(t, u1)
|
473
|
-
t.print('\\u')
|
474
|
-
hexenc4(t, u2)
|
475
|
-
end
|
476
482
|
else
|
477
|
-
#
|
483
|
+
n = ucharcopy(t, s, r) # ensure valid UTF-8 output
|
484
|
+
r += n - 1 # r is incremented below
|
478
485
|
end
|
479
486
|
end
|
480
487
|
r += 1
|
@@ -484,76 +491,85 @@ module MultiJson
|
|
484
491
|
end
|
485
492
|
|
486
493
|
|
487
|
-
def hexenc4(t, u)
|
488
|
-
t.putc(Hex[(u>>12)&0xf])
|
489
|
-
t.putc(Hex[(u>>8)&0xf])
|
490
|
-
t.putc(Hex[(u>>4)&0xf])
|
491
|
-
t.putc(Hex[u&0xf])
|
492
|
-
end
|
493
|
-
|
494
|
-
|
495
494
|
def numenc(x)
|
496
|
-
if x.nan? || x.infinite?
|
497
|
-
|
498
|
-
end
|
495
|
+
if ((x.nan? || x.infinite?) rescue false)
|
496
|
+
raise Error, "Numeric cannot be represented: #{x}"
|
497
|
+
end
|
499
498
|
"#{x}"
|
500
499
|
end
|
501
500
|
|
502
501
|
|
503
|
-
#
|
504
|
-
#
|
505
|
-
#
|
506
|
-
|
502
|
+
# Copies the valid UTF-8 bytes of a single character
|
503
|
+
# from string s at position i to I/O object t, and
|
504
|
+
# returns the number of bytes copied.
|
505
|
+
# If no valid UTF-8 char exists at position i,
|
506
|
+
# ucharcopy writes Ustrerr and returns 1.
|
507
|
+
def ucharcopy(t, s, i)
|
507
508
|
n = s.length - i
|
508
|
-
|
509
|
+
raise Utf8Error if n < 1
|
509
510
|
|
510
511
|
c0 = s[i].ord
|
511
512
|
|
512
513
|
# 1-byte, 7-bit sequence?
|
513
514
|
if c0 < Utagx
|
514
|
-
|
515
|
+
t.putc(c0)
|
516
|
+
return 1
|
515
517
|
end
|
516
518
|
|
517
|
-
# unexpected continuation byte?
|
518
|
-
return [Ucharerr, 1] if c0 < Utag2
|
519
|
+
raise Utf8Error if c0 < Utag2 # unexpected continuation byte?
|
519
520
|
|
520
|
-
# need continuation byte
|
521
|
-
return [Ucharerr, 1] if n < 2
|
521
|
+
raise Utf8Error if n < 2 # need continuation byte
|
522
522
|
c1 = s[i+1].ord
|
523
|
-
|
523
|
+
raise Utf8Error if c1 < Utagx || Utag2 <= c1
|
524
524
|
|
525
525
|
# 2-byte, 11-bit sequence?
|
526
526
|
if c0 < Utag3
|
527
|
-
|
528
|
-
|
529
|
-
|
527
|
+
raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max
|
528
|
+
t.putc(c0)
|
529
|
+
t.putc(c1)
|
530
|
+
return 2
|
530
531
|
end
|
531
532
|
|
532
533
|
# need second continuation byte
|
533
|
-
|
534
|
+
raise Utf8Error if n < 3
|
535
|
+
|
534
536
|
c2 = s[i+2].ord
|
535
|
-
|
537
|
+
raise Utf8Error if c2 < Utagx || Utag2 <= c2
|
536
538
|
|
537
539
|
# 3-byte, 16-bit sequence?
|
538
540
|
if c0 < Utag4
|
539
541
|
u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx)
|
540
|
-
|
541
|
-
|
542
|
+
raise Utf8Error if u <= Uchar2max
|
543
|
+
t.putc(c0)
|
544
|
+
t.putc(c1)
|
545
|
+
t.putc(c2)
|
546
|
+
return 3
|
542
547
|
end
|
543
548
|
|
544
549
|
# need third continuation byte
|
545
|
-
|
550
|
+
raise Utf8Error if n < 4
|
546
551
|
c3 = s[i+3].ord
|
547
|
-
|
552
|
+
raise Utf8Error if c3 < Utagx || Utag2 <= c3
|
548
553
|
|
549
554
|
# 4-byte, 21-bit sequence?
|
550
555
|
if c0 < Utag5
|
551
556
|
u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx)
|
552
|
-
|
553
|
-
|
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
|
554
563
|
end
|
555
564
|
|
556
|
-
|
565
|
+
raise Utf8Error
|
566
|
+
rescue Utf8Error
|
567
|
+
t.write(Ustrerr)
|
568
|
+
return 1
|
569
|
+
end
|
570
|
+
|
571
|
+
|
572
|
+
class Utf8Error < ::StandardError
|
557
573
|
end
|
558
574
|
|
559
575
|
|
@@ -574,14 +590,13 @@ module MultiJson
|
|
574
590
|
Uchar2max = (1<<11) - 1
|
575
591
|
Uchar3max = (1<<16) - 1
|
576
592
|
Ucharerr = 0xFFFD # unicode "replacement char"
|
593
|
+
Ustrerr = "\xef\xbf\xbd" # unicode "replacement char"
|
577
594
|
Usurrself = 0x10000
|
578
595
|
Usurr1 = 0xd800
|
579
596
|
Usurr2 = 0xdc00
|
580
597
|
Usurr3 = 0xe000
|
581
|
-
Umax = 0x10ffff
|
582
598
|
|
583
599
|
Spc = ' '[0]
|
584
600
|
Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t}
|
585
|
-
Hex = '0123456789abcdef'
|
586
601
|
end
|
587
602
|
end
|
data/lib/multi_json/version.rb
CHANGED
data/multi_json.gemspec
CHANGED
@@ -13,6 +13,23 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.files = Dir['LICENSE.md', 'README.md', 'Rakefile', 'multi_json.gemspec', 'Gemfile', '.document', '.rspec', '.travis.yml' ,'spec/**/*', 'lib/**/*']
|
14
14
|
gem.homepage = 'http://github.com/intridea/multi_json'
|
15
15
|
gem.name = 'multi_json'
|
16
|
+
gem.post_install_message =<<eos
|
17
|
+
********************************************************************************
|
18
|
+
|
19
|
+
MultiJson.encode is deprecated and will be removed in the next major version.
|
20
|
+
Use MultiJson.dump instead.
|
21
|
+
|
22
|
+
MultiJson.decode is deprecated and will be removed in the next major version.
|
23
|
+
Use MultiJson.load instead.
|
24
|
+
|
25
|
+
MultiJson.engine is deprecated and will be removed in the next major version.
|
26
|
+
Use MultiJson.adapter instead.
|
27
|
+
|
28
|
+
MultiJson.engine= is deprecated and will be removed in the next major version.
|
29
|
+
Use MultiJson.use instead.
|
30
|
+
|
31
|
+
********************************************************************************
|
32
|
+
eos
|
16
33
|
gem.rdoc_options = ["--charset=UTF-8"]
|
17
34
|
gem.require_paths = ['lib']
|
18
35
|
gem.required_rubygems_version = Gem::Requirement.new(">= 1.3.6")
|
@@ -1,24 +1,24 @@
|
|
1
|
-
shared_examples_for "an
|
1
|
+
shared_examples_for "an adapter" do |adapter|
|
2
2
|
|
3
3
|
before do
|
4
4
|
begin
|
5
|
-
MultiJson.
|
5
|
+
MultiJson.use adapter
|
6
6
|
rescue LoadError
|
7
|
-
pending "
|
7
|
+
pending "Adapter #{adapter} couldn't be loaded (not installed?)"
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
describe '.
|
11
|
+
describe '.dump' do
|
12
12
|
it 'writes decodable JSON' do
|
13
13
|
[
|
14
14
|
{'abc' => 'def'},
|
15
15
|
[1, 2, 3, "4"],
|
16
16
|
].each do |example|
|
17
|
-
MultiJson.
|
17
|
+
MultiJson.load(MultiJson.dump(example)).should == example
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
it '
|
21
|
+
it 'dumps symbol keys as strings' do
|
22
22
|
[
|
23
23
|
[
|
24
24
|
{:foo => {:bar => 'baz'}},
|
@@ -33,64 +33,64 @@ shared_examples_for "an engine" do |engine|
|
|
33
33
|
{'foo' => [{'bar' => 'baz'}]},
|
34
34
|
]
|
35
35
|
].each do |example, expected|
|
36
|
-
|
37
|
-
MultiJson.
|
36
|
+
dumped_json = MultiJson.dump(example)
|
37
|
+
MultiJson.load(dumped_json).should == expected
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
it '
|
42
|
-
MultiJson.
|
43
|
-
MultiJson.
|
41
|
+
it 'dumps rootless JSON' do
|
42
|
+
MultiJson.dump("random rootless string").should == "\"random rootless string\""
|
43
|
+
MultiJson.dump(123).should == "123"
|
44
44
|
end
|
45
45
|
|
46
|
-
it 'passes options to the
|
47
|
-
MultiJson.
|
48
|
-
MultiJson.
|
46
|
+
it 'passes options to the adapter' do
|
47
|
+
MultiJson.adapter.should_receive(:dump).with('foo', {:bar => :baz})
|
48
|
+
MultiJson.dump('foo', :bar => :baz)
|
49
49
|
end
|
50
50
|
|
51
|
-
if
|
51
|
+
if adapter == 'json_gem' || adapter == 'json_pure'
|
52
52
|
describe 'with :pretty option set to true' do
|
53
53
|
it 'passes default pretty options' do
|
54
54
|
object = 'foo'
|
55
55
|
object.should_receive(:to_json).with(JSON::PRETTY_STATE_PROTOTYPE.to_h)
|
56
|
-
MultiJson.
|
56
|
+
MultiJson.dump(object,:pretty => true)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
it
|
62
|
-
MultiJson.
|
61
|
+
it 'dumps custom objects which implement as_json' do
|
62
|
+
MultiJson.dump(TimeWithZone.new).should == "\"2005-02-01T15:15:10Z\""
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
describe '.
|
67
|
-
it 'properly
|
68
|
-
MultiJson.
|
66
|
+
describe '.load' do
|
67
|
+
it 'properly loads valid JSON' do
|
68
|
+
MultiJson.load('{"abc":"def"}').should == {'abc' => 'def'}
|
69
69
|
end
|
70
70
|
|
71
71
|
it 'raises MultiJson::DecodeError on invalid JSON' do
|
72
72
|
lambda do
|
73
|
-
MultiJson.
|
73
|
+
MultiJson.load('{"abc"}')
|
74
74
|
end.should raise_error(MultiJson::DecodeError)
|
75
75
|
end
|
76
76
|
|
77
77
|
it 'raises MultiJson::DecodeError with data on invalid JSON' do
|
78
78
|
data = '{invalid}'
|
79
79
|
begin
|
80
|
-
MultiJson.
|
80
|
+
MultiJson.load(data)
|
81
81
|
rescue MultiJson::DecodeError => de
|
82
82
|
de.data.should == data
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
86
|
it 'stringifys symbol keys when encoding' do
|
87
|
-
|
88
|
-
MultiJson.
|
87
|
+
dumped_json = MultiJson.dump(:a => 1, :b => {:c => 2})
|
88
|
+
MultiJson.load(dumped_json).should == {"a" => 1, "b" => {"c" => 2}}
|
89
89
|
end
|
90
90
|
|
91
|
-
it
|
91
|
+
it 'properly loads valid JSON in StringIOs' do
|
92
92
|
json = StringIO.new('{"abc":"def"}')
|
93
|
-
MultiJson.
|
93
|
+
MultiJson.load(json).should == {'abc' => 'def'}
|
94
94
|
end
|
95
95
|
|
96
96
|
it 'allows for symbolization of keys' do
|
@@ -108,7 +108,7 @@ shared_examples_for "an engine" do |engine|
|
|
108
108
|
{:abc => [{:def => 'hgi'}]},
|
109
109
|
],
|
110
110
|
].each do |example, expected|
|
111
|
-
MultiJson.
|
111
|
+
MultiJson.load(example, :symbolize_keys => true).should == expected
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
data/spec/helper.rb
CHANGED
@@ -14,17 +14,17 @@ require 'multi_json'
|
|
14
14
|
require 'rspec'
|
15
15
|
|
16
16
|
class MockDecoder
|
17
|
-
def self.
|
17
|
+
def self.load(string, options={})
|
18
18
|
{'abc' => 'def'}
|
19
19
|
end
|
20
20
|
|
21
|
-
def self.
|
21
|
+
def self.dump(string)
|
22
22
|
'{"abc":"def"}'
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
class TimeWithZone
|
27
|
-
def to_json(options
|
27
|
+
def to_json(options={})
|
28
28
|
"\"2005-02-01T15:15:10Z\""
|
29
29
|
end
|
30
30
|
end
|
data/spec/multi_json_spec.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'helper'
|
2
|
-
require '
|
2
|
+
require 'adapter_shared_example'
|
3
3
|
require 'stringio'
|
4
4
|
|
5
5
|
describe 'MultiJson' do
|
6
|
-
context '
|
6
|
+
context 'adapters' do
|
7
7
|
before do
|
8
|
-
MultiJson.
|
8
|
+
MultiJson.use nil
|
9
9
|
end
|
10
10
|
context 'when no other json implementations are available' do
|
11
11
|
before do
|
@@ -13,8 +13,8 @@ describe 'MultiJson' do
|
|
13
13
|
@old_json = Object.const_get :JSON if Object.const_defined?(:JSON)
|
14
14
|
@old_oj = Object.const_get :Oj if Object.const_defined?(:Oj)
|
15
15
|
@old_yajl = Object.const_get :Yajl if Object.const_defined?(:Yajl)
|
16
|
-
MultiJson::REQUIREMENT_MAP.each_with_index do |(library,
|
17
|
-
MultiJson::REQUIREMENT_MAP[index] = ["foo/#{library}",
|
16
|
+
MultiJson::REQUIREMENT_MAP.each_with_index do |(library, adapter), index|
|
17
|
+
MultiJson::REQUIREMENT_MAP[index] = ["foo/#{library}", adapter]
|
18
18
|
end
|
19
19
|
Object.send :remove_const, :JSON if @old_json
|
20
20
|
Object.send :remove_const, :Oj if @old_oj
|
@@ -22,8 +22,8 @@ describe 'MultiJson' do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
after do
|
25
|
-
@old_map.each_with_index do |(library,
|
26
|
-
MultiJson::REQUIREMENT_MAP[index] = [library,
|
25
|
+
@old_map.each_with_index do |(library, adapter), index|
|
26
|
+
MultiJson::REQUIREMENT_MAP[index] = [library, adapter]
|
27
27
|
end
|
28
28
|
Object.const_set :JSON, @old_json if @old_json
|
29
29
|
Object.const_set :Oj, @old_oj if @old_oj
|
@@ -31,42 +31,42 @@ describe 'MultiJson' do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'defaults to ok_json if no other json implementions are available' do
|
34
|
-
MultiJson.
|
34
|
+
MultiJson.default_adapter.should == :ok_json
|
35
35
|
end
|
36
36
|
|
37
37
|
it 'prints a warning' do
|
38
38
|
Kernel.should_receive(:warn).with(/warning/i)
|
39
|
-
MultiJson.
|
39
|
+
MultiJson.default_adapter
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'defaults to the best available gem' do
|
44
44
|
unless jruby?
|
45
45
|
require 'oj'
|
46
|
-
MultiJson.
|
46
|
+
MultiJson.adapter.name.should == 'MultiJson::Adapters::Oj'
|
47
47
|
else
|
48
48
|
require 'json'
|
49
|
-
MultiJson.
|
49
|
+
MultiJson.adapter.name.should == 'MultiJson::Adapters::JsonGem'
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'is settable via a symbol' do
|
54
|
-
MultiJson.
|
55
|
-
MultiJson.
|
54
|
+
MultiJson.use :json_gem
|
55
|
+
MultiJson.adapter.name.should == 'MultiJson::Adapters::JsonGem'
|
56
56
|
end
|
57
57
|
|
58
58
|
it 'is settable via a class' do
|
59
|
-
MultiJson.
|
60
|
-
MultiJson.
|
59
|
+
MultiJson.use MockDecoder
|
60
|
+
MultiJson.adapter.name.should == 'MockDecoder'
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
%w(json_gem json_pure nsjsonserialization oj ok_json yajl).each do |
|
65
|
-
next if !macruby? &&
|
66
|
-
next if jruby? && (
|
64
|
+
%w(json_gem json_pure nsjsonserialization oj ok_json yajl).each do |adapter|
|
65
|
+
next if !macruby? && adapter == 'nsjsonserialization'
|
66
|
+
next if jruby? && (adapter == 'oj' || adapter == 'yajl')
|
67
67
|
|
68
|
-
context
|
69
|
-
it_should_behave_like "an
|
68
|
+
context adapter do
|
69
|
+
it_should_behave_like "an adapter", adapter
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: multi_json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-
|
14
|
+
date: 2012-04-16 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rake
|
@@ -97,22 +97,28 @@ files:
|
|
97
97
|
- .document
|
98
98
|
- .rspec
|
99
99
|
- .travis.yml
|
100
|
-
- spec/
|
100
|
+
- spec/adapter_shared_example.rb
|
101
101
|
- spec/helper.rb
|
102
102
|
- spec/multi_json_spec.rb
|
103
|
-
- lib/multi_json/
|
104
|
-
- lib/multi_json/
|
105
|
-
- lib/multi_json/
|
106
|
-
- lib/multi_json/
|
107
|
-
- lib/multi_json/
|
108
|
-
- lib/multi_json/
|
109
|
-
- lib/multi_json/
|
110
|
-
- lib/multi_json/vendor/
|
103
|
+
- lib/multi_json/adapters/json_common.rb
|
104
|
+
- lib/multi_json/adapters/json_gem.rb
|
105
|
+
- lib/multi_json/adapters/json_pure.rb
|
106
|
+
- lib/multi_json/adapters/nsjsonserialization.rb
|
107
|
+
- lib/multi_json/adapters/oj.rb
|
108
|
+
- lib/multi_json/adapters/ok_json.rb
|
109
|
+
- lib/multi_json/adapters/yajl.rb
|
110
|
+
- lib/multi_json/vendor/okjson.rb
|
111
111
|
- lib/multi_json/version.rb
|
112
112
|
- lib/multi_json.rb
|
113
113
|
homepage: http://github.com/intridea/multi_json
|
114
114
|
licenses: []
|
115
|
-
post_install_message:
|
115
|
+
post_install_message: ! "********************************************************************************\n\n
|
116
|
+
\ MultiJson.encode is deprecated and will be removed in the next major version.\n
|
117
|
+
\ Use MultiJson.dump instead.\n\n MultiJson.decode is deprecated and will be removed
|
118
|
+
in the next major version.\n Use MultiJson.load instead.\n\n MultiJson.engine
|
119
|
+
is deprecated and will be removed in the next major version.\n Use MultiJson.adapter
|
120
|
+
instead.\n\n MultiJson.engine= is deprecated and will be removed in the next major
|
121
|
+
version.\n Use MultiJson.use instead.\n\n********************************************************************************\n"
|
116
122
|
rdoc_options:
|
117
123
|
- --charset=UTF-8
|
118
124
|
require_paths:
|
@@ -131,12 +137,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
137
|
version: 1.3.6
|
132
138
|
requirements: []
|
133
139
|
rubyforge_project:
|
134
|
-
rubygems_version: 1.8.
|
140
|
+
rubygems_version: 1.8.22
|
135
141
|
signing_key:
|
136
142
|
specification_version: 3
|
137
143
|
summary: A gem to provide swappable JSON backends.
|
138
144
|
test_files:
|
139
|
-
- spec/
|
145
|
+
- spec/adapter_shared_example.rb
|
140
146
|
- spec/helper.rb
|
141
147
|
- spec/multi_json_spec.rb
|
142
148
|
has_rdoc:
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'oj' unless defined?(::Oj)
|
2
|
-
|
3
|
-
::Oj.default_options = {:mode => :compat}
|
4
|
-
|
5
|
-
module MultiJson
|
6
|
-
module Engines
|
7
|
-
# Use the Oj library to encode/decode.
|
8
|
-
class Oj
|
9
|
-
ParseError = SyntaxError
|
10
|
-
|
11
|
-
def self.decode(string, options = {}) #:nodoc:
|
12
|
-
opts = {}
|
13
|
-
opts[:symbol_keys] = options[:symbolize_keys]
|
14
|
-
::Oj.load(string, opts)
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.encode(object, options = {}) #:nodoc:
|
18
|
-
::Oj.dump(object, options)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|