multi_json 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|