oj 2.1.3 → 2.1.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of oj might be problematic. Click here for more details.

Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -4
  3. data/ext/oj/compat.c +3 -4
  4. data/ext/oj/encode.h +51 -0
  5. data/ext/oj/fast.c +4 -9
  6. data/ext/oj/object.c +7 -19
  7. data/ext/oj/oj.c +32 -12
  8. data/ext/oj/oj.h +3 -0
  9. data/ext/oj/parse.c +2 -3
  10. data/ext/oj/saj.c +4 -9
  11. data/ext/oj/scp.c +5 -12
  12. data/ext/oj/strict.c +5 -12
  13. data/lib/oj/version.rb +1 -1
  14. data/test/a.rb +38 -0
  15. data/test/bug.rb +15 -0
  16. data/test/e.rb +12 -0
  17. data/test/files.rb +29 -0
  18. data/test/foo.rb +24 -0
  19. data/test/mj.rb +48 -0
  20. data/test/perf.rb +107 -0
  21. data/test/perf_compat.rb +128 -0
  22. data/test/perf_fast.rb +164 -0
  23. data/test/perf_object.rb +136 -0
  24. data/test/perf_saj.rb +109 -0
  25. data/test/perf_scp.rb +151 -0
  26. data/test/perf_simple.rb +287 -0
  27. data/test/perf_strict.rb +127 -0
  28. data/test/sample.rb +55 -0
  29. data/test/sample/change.rb +14 -0
  30. data/test/sample/dir.rb +19 -0
  31. data/test/sample/doc.rb +36 -0
  32. data/test/sample/file.rb +48 -0
  33. data/test/sample/group.rb +16 -0
  34. data/test/sample/hasprops.rb +16 -0
  35. data/test/sample/layer.rb +12 -0
  36. data/test/sample/line.rb +20 -0
  37. data/test/sample/oval.rb +10 -0
  38. data/test/sample/rect.rb +10 -0
  39. data/test/sample/shape.rb +35 -0
  40. data/test/sample/text.rb +20 -0
  41. data/test/sample_json.rb +37 -0
  42. data/test/test_compat.rb +342 -0
  43. data/test/test_fast.rb +416 -0
  44. data/test/test_mimic.rb +208 -0
  45. data/test/test_mimic_after.rb +35 -0
  46. data/test/test_object.rb +390 -0
  47. data/test/test_saj.rb +184 -0
  48. data/test/test_scp.rb +224 -0
  49. data/test/test_strict.rb +259 -0
  50. data/test/tests.rb +1017 -0
  51. data/test/x.rb +59 -0
  52. metadata +41 -2
@@ -0,0 +1,14 @@
1
+
2
+ module Sample
3
+ class Change
4
+ attr_accessor :time
5
+ attr_accessor :user
6
+ attr_accessor :comment
7
+
8
+ def initialize(comment=nil, time=nil, user=nil)
9
+ @user = user || ENV['USER']
10
+ @time = time || Time.now
11
+ @comment = comment
12
+ end
13
+ end # Change
14
+ end # Sample
@@ -0,0 +1,19 @@
1
+
2
+ require 'etc'
3
+
4
+ module Sample
5
+
6
+ class Dir < File
7
+ attr_accessor :files
8
+
9
+ def initialize(filename)
10
+ super
11
+ @files = []
12
+ end
13
+
14
+ def <<(f)
15
+ @files << f
16
+ end
17
+
18
+ end # Dir
19
+ end # Sample
@@ -0,0 +1,36 @@
1
+
2
+ require 'sample/hasprops'
3
+ require 'sample/group'
4
+ require 'sample/layer'
5
+ require 'sample/line'
6
+ require 'sample/shape'
7
+ require 'sample/oval'
8
+ require 'sample/rect'
9
+ require 'sample/text'
10
+ require 'sample/change'
11
+
12
+ module Sample
13
+ class Doc
14
+ include HasProps
15
+
16
+ attr_accessor :title
17
+ attr_accessor :create_time
18
+ attr_accessor :user
19
+ # Hash of layers in the document indexed by layer name.
20
+ attr_reader :layers
21
+ attr_reader :change_history
22
+
23
+ def initialize(title)
24
+ @title = title
25
+ @user = ENV['USER']
26
+ @create_time = Time.now
27
+ @layers = { }
28
+ @change_history = []
29
+ end
30
+
31
+ def add_change(comment, time=nil, user=nil)
32
+ @change_history << Change.new(comment, time, user)
33
+ end
34
+
35
+ end # Doc
36
+ end # Sample
@@ -0,0 +1,48 @@
1
+
2
+ require 'etc'
3
+
4
+ module Sample
5
+
6
+ class File
7
+ attr_accessor :name, :ctime, :mtime, :size, :owner, :group, :permissions
8
+
9
+ def initialize(filename)
10
+ @name = ::File.basename(filename)
11
+ stat = ::File.stat(filename)
12
+ @ctime = stat.ctime
13
+ @mtime = stat.mtime
14
+ @size = stat.size
15
+ @owner = Etc.getpwuid(stat.uid).name
16
+ @group = Etc.getgrgid(stat.gid).name
17
+ if false
18
+ @permissions = {
19
+ 'user' => {
20
+ 'read' => (0 != (stat.mode & 0x0100)),
21
+ 'write' => (0 != (stat.mode & 0x0080)),
22
+ 'execute' => (0 != (stat.mode & 0x0040))},
23
+ 'group' => {
24
+ 'read' => (0 != (stat.mode & 0x0020)),
25
+ 'write' => (0 != (stat.mode & 0x0010)),
26
+ 'execute' => (0 != (stat.mode & 0x0008))},
27
+ 'other' => {
28
+ 'read' => (0 != (stat.mode & 0x0004)),
29
+ 'write' => (0 != (stat.mode & 0x0002)),
30
+ 'execute' => (0 != (stat.mode & 0x0001))}
31
+ }
32
+ else
33
+ @permissions = {
34
+ 'user' => [(0 != (stat.mode & 0x0100)) ? 'r' : '-',
35
+ (0 != (stat.mode & 0x0080)) ? 'w' : '-',
36
+ (0 != (stat.mode & 0x0040)) ? 'x' : '-'].join(''),
37
+ 'group' => [(0 != (stat.mode & 0x0020)) ? 'r' : '-',
38
+ (0 != (stat.mode & 0x0010)) ? 'w' : '-',
39
+ (0 != (stat.mode & 0x0008)) ? 'x' : '-'].join(''),
40
+ 'other' => [(0 != (stat.mode & 0x0004)) ? 'r' : '-',
41
+ (0 != (stat.mode & 0x0002)) ? 'w' : '-',
42
+ (0 != (stat.mode & 0x0001)) ? 'x' : '-'].join('')
43
+ }
44
+ end
45
+ end
46
+
47
+ end # File
48
+ end # Sample
@@ -0,0 +1,16 @@
1
+
2
+ module Sample
3
+ class Group
4
+ attr_reader :members
5
+
6
+ def initialize()
7
+ @members = []
8
+ end
9
+
10
+ def <<(member)
11
+ @members << member
12
+ end
13
+
14
+ end # Group
15
+ end # Sample
16
+
@@ -0,0 +1,16 @@
1
+
2
+ module Sample
3
+ module HasProps
4
+
5
+ def add_prop(key, value)
6
+ @props = { } unless self.instance_variable_defined?(:@props)
7
+ @props[key] = value
8
+ end
9
+
10
+ def props
11
+ @props = { } unless self.instance_variable_defined?(:@props)
12
+ @props
13
+ end
14
+
15
+ end # HasProps
16
+ end # Sample
@@ -0,0 +1,12 @@
1
+
2
+ module Sample
3
+ class Layer < Group
4
+ attr_accessor :name
5
+
6
+ def initialize(name)
7
+ super()
8
+ @name = name
9
+ end
10
+
11
+ end # Layer
12
+ end # Sample
@@ -0,0 +1,20 @@
1
+ module Sample
2
+
3
+ class Line
4
+ include HasProps
5
+
6
+ attr_accessor :x, :y, :dx, :dy
7
+ attr_accessor :color
8
+ attr_accessor :thick
9
+
10
+ def initialize(x, y, dx, dy, thick, color)
11
+ @x = x
12
+ @y = y
13
+ @dx = dx
14
+ @dy = dy
15
+ @thick = thick
16
+ @color = color
17
+ end
18
+
19
+ end # Line
20
+ end # Sample
@@ -0,0 +1,10 @@
1
+ module Sample
2
+
3
+ class Oval < Shape
4
+
5
+ def initialize(left, top, wide, high, color=nil)
6
+ super
7
+ end
8
+
9
+ end # Oval
10
+ end # Sample
@@ -0,0 +1,10 @@
1
+
2
+ module Sample
3
+ class Rect < Shape
4
+
5
+ def initialize(left, top, wide, high, color=nil)
6
+ super
7
+ end
8
+
9
+ end # Rect
10
+ end # Sample
@@ -0,0 +1,35 @@
1
+
2
+ module Sample
3
+ class Shape
4
+ include HasProps
5
+
6
+ attr_accessor :bounds
7
+ attr_accessor :color
8
+ attr_accessor :border, :border_color
9
+
10
+ def initialize(left, top, wide, high, color=nil)
11
+ @bounds = [[left, top], [left + wide, top + high]]
12
+ @color = color
13
+ @border = 1
14
+ @border_color = :black
15
+ end
16
+
17
+ def left
18
+ @bounds[0][0]
19
+ end
20
+
21
+ def top
22
+ @bounds[0][1]
23
+ end
24
+
25
+ def width
26
+ @bounds[1][0] - @bounds[0][0]
27
+ end
28
+
29
+ def height
30
+ @bounds[1][1] - @bounds[0][1]
31
+ end
32
+
33
+ end # Shape
34
+ end # Sample
35
+
@@ -0,0 +1,20 @@
1
+
2
+ module Sample
3
+ class Text < Shape
4
+ attr_accessor :text
5
+ attr_accessor :font
6
+ attr_accessor :font_size
7
+ attr_accessor :just
8
+ attr_accessor :text_color
9
+
10
+ def initialize(text, left, top, wide, high, color=nil)
11
+ super(left, top, wide, high, color)
12
+ @text = text
13
+ @font = 'helvetica'
14
+ @font_size = 14
15
+ @just = 'left'
16
+ @text_color = 'black'
17
+ end
18
+
19
+ end # Text
20
+ end # Sample
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby -wW2
2
+
3
+ if $0 == __FILE__
4
+ $: << '.'
5
+ $: << '..'
6
+ $: << '../lib'
7
+ $: << '../ext'
8
+ end
9
+
10
+ require 'pp'
11
+ require 'oj'
12
+
13
+ def sample_json(size=3)
14
+ colors = [ :black, :gray, :white, :red, :blue, :yellow, :green, :purple, :orange ]
15
+ container = []
16
+ size.times do |i|
17
+ box = {
18
+ 'color' => colors[i % colors.size],
19
+ 'fragile' => (0 == (i % 2)),
20
+ 'width' => i,
21
+ 'height' => i,
22
+ 'depth' => i,
23
+ 'weight' => i * 1.3,
24
+ 'address' => {
25
+ 'street' => "#{i} Main Street",
26
+ 'city' => 'Sity',
27
+ 'state' => nil
28
+ }
29
+ }
30
+ container << box
31
+ end
32
+ container
33
+ end
34
+
35
+ if $0 == __FILE__
36
+ File.open('sample.json', "w") { |f| f.write(Oj.dump(sample_json(3), :indent => 2)) }
37
+ end
@@ -0,0 +1,342 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ # Ubuntu does not accept arguments to ruby when called using env. To get warnings to show up the -w options is
5
+ # required. That can be set in the RUBYOPT environment variable.
6
+ # export RUBYOPT=-w
7
+
8
+ $VERBOSE = true
9
+
10
+ $: << File.join(File.dirname(__FILE__), "../lib")
11
+ $: << File.join(File.dirname(__FILE__), "../ext")
12
+
13
+ require 'test/unit'
14
+ require 'stringio'
15
+ require 'date'
16
+ require 'bigdecimal'
17
+ require 'oj'
18
+
19
+ $ruby = RUBY_DESCRIPTION.split(' ')[0]
20
+ $ruby = 'ree' if 'ruby' == $ruby && RUBY_DESCRIPTION.include?('Ruby Enterprise Edition')
21
+
22
+ class Jeez
23
+ attr_accessor :x, :y
24
+
25
+ def initialize(x, y)
26
+ @x = x
27
+ @y = y
28
+ end
29
+
30
+ def eql?(o)
31
+ self.class == o.class && @x == o.x && @y == o.y
32
+ end
33
+ alias == eql?
34
+
35
+ def to_json(*a)
36
+ %{{"json_class":"#{self.class}","x":#{@x},"y":#{@y}}}
37
+ end
38
+
39
+ def self.json_create(h)
40
+ self.new(h['x'], h['y'])
41
+ end
42
+ end # Jeez
43
+
44
+ module One
45
+ module Two
46
+ module Three
47
+ class Deep
48
+
49
+ def initialize()
50
+ end
51
+
52
+ def eql?(o)
53
+ self.class == o.class
54
+ end
55
+ alias == eql?
56
+
57
+ def to_hash()
58
+ {'json_class' => "#{self.class.name}"}
59
+ end
60
+
61
+ def to_json(*a)
62
+ %{{"json_class":"#{self.class.name}"}}
63
+ end
64
+
65
+ def self.json_create(h)
66
+ self.new()
67
+ end
68
+ end # Deep
69
+ end # Three
70
+ end # Two
71
+ end # One
72
+
73
+ def hash_eql(h1, h2)
74
+ return false if h1.size != h2.size
75
+ h1.keys.each do |k|
76
+ return false unless h1[k] == h2[k]
77
+ end
78
+ true
79
+ end
80
+
81
+ class CompatJuice < ::Test::Unit::TestCase
82
+
83
+ def test_nil
84
+ dump_and_load(nil, false)
85
+ end
86
+
87
+ def test_true
88
+ dump_and_load(true, false)
89
+ end
90
+
91
+ def test_false
92
+ dump_and_load(false, false)
93
+ end
94
+
95
+ def test_fixnum
96
+ dump_and_load(0, false)
97
+ dump_and_load(12345, false)
98
+ dump_and_load(-54321, false)
99
+ dump_and_load(1, false)
100
+ end
101
+
102
+ def test_float
103
+ dump_and_load(0.0, false)
104
+ dump_and_load(12345.6789, false)
105
+ dump_and_load(70.35, false)
106
+ dump_and_load(-54321.012, false)
107
+ dump_and_load(2.48e16, false)
108
+ dump_and_load(2.48e100 * 1.0e10, false)
109
+ dump_and_load(-2.48e100 * 1.0e10, false)
110
+ end
111
+
112
+ def test_string
113
+ dump_and_load('', false)
114
+ dump_and_load('abc', false)
115
+ dump_and_load("abc\ndef", false)
116
+ dump_and_load("a\u0041", false)
117
+ end
118
+
119
+ def test_encode
120
+ opts = Oj.default_options
121
+ Oj.default_options = { :ascii_only => false }
122
+ unless 'jruby' == $ruby
123
+ dump_and_load("ぴーたー", false)
124
+ end
125
+ Oj.default_options = { :ascii_only => true }
126
+ json = Oj.dump("ぴーたー")
127
+ assert_equal(%{"\\u3074\\u30fc\\u305f\\u30fc"}, json)
128
+ unless 'jruby' == $ruby
129
+ dump_and_load("ぴーたー", false)
130
+ end
131
+ Oj.default_options = opts
132
+ end
133
+
134
+ def test_unicode
135
+ # hits the 3 normal ranges and one extended surrogate pair
136
+ json = %{"\\u019f\\u05e9\\u3074\\ud834\\udd1e"}
137
+ obj = Oj.load(json)
138
+ json2 = Oj.dump(obj, :ascii_only => true)
139
+ assert_equal(json, json2)
140
+ end
141
+
142
+ def test_array
143
+ dump_and_load([], false)
144
+ dump_and_load([true, false], false)
145
+ dump_and_load(['a', 1, nil], false)
146
+ dump_and_load([[nil]], false)
147
+ dump_and_load([[nil], 58], false)
148
+ end
149
+
150
+ def test_array_deep
151
+ dump_and_load([1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,[15,[16,[17,[18,[19,[20]]]]]]]]]]]]]]]]]]]], false)
152
+ end
153
+
154
+ # Hash
155
+ def test_hash
156
+ dump_and_load({}, false)
157
+ dump_and_load({ 'true' => true, 'false' => false}, false)
158
+ dump_and_load({ 'true' => true, 'array' => [], 'hash' => { }}, false)
159
+ end
160
+
161
+ def test_hash_deep
162
+ dump_and_load({'1' => {
163
+ '2' => {
164
+ '3' => {
165
+ '4' => {
166
+ '5' => {
167
+ '6' => {
168
+ '7' => {
169
+ '8' => {
170
+ '9' => {
171
+ '10' => {
172
+ '11' => {
173
+ '12' => {
174
+ '13' => {
175
+ '14' => {
176
+ '15' => {
177
+ '16' => {
178
+ '17' => {
179
+ '18' => {
180
+ '19' => {
181
+ '20' => {}}}}}}}}}}}}}}}}}}}}}, false)
182
+ end
183
+
184
+ def test_hash_escaped_key
185
+ json = %{{"a\nb":true,"c\td":false}}
186
+ obj = Oj.compat_load(json)
187
+ assert_equal({"a\nb" => true, "c\td" => false}, obj)
188
+ end
189
+
190
+ def test_bignum_object
191
+ dump_and_load(7 ** 55, false)
192
+ end
193
+
194
+ # BigDecimal
195
+ def test_bigdecimal_compat
196
+ dump_and_load(BigDecimal.new('3.14159265358979323846'), false)
197
+ end
198
+
199
+ def test_bigdecimal_load
200
+ orig = BigDecimal.new('80.51')
201
+ json = Oj.dump(orig, :mode => :compat, :bigdecimal_as_decimal => true)
202
+ bg = Oj.load(json, :mode => :compat, :bigdecimal_load => true)
203
+ assert_equal(BigDecimal, bg.class)
204
+ assert_equal(orig, bg)
205
+ end
206
+
207
+ # Stream IO
208
+ def test_io_string
209
+ json = %{{
210
+ "x":true,
211
+ "y":58,
212
+ "z": [1,2,3]
213
+ }
214
+ }
215
+ input = StringIO.new(json)
216
+ obj = Oj.compat_load(input)
217
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
218
+ end
219
+
220
+ def test_io_file
221
+ filename = 'open_file_test.json'
222
+ File.open(filename, 'w') { |f| f.write(%{{
223
+ "x":true,
224
+ "y":58,
225
+ "z": [1,2,3]
226
+ }
227
+ }) }
228
+ f = File.new(filename)
229
+ obj = Oj.compat_load(f)
230
+ f.close()
231
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
232
+ end
233
+
234
+ # symbol_keys option
235
+ def test_symbol_keys
236
+ json = %{{
237
+ "x":true,
238
+ "y":58,
239
+ "z": [1,2,3]
240
+ }
241
+ }
242
+ obj = Oj.compat_load(json, :symbol_keys => true)
243
+ assert_equal({ :x => true, :y => 58, :z => [1, 2, 3]}, obj)
244
+ end
245
+
246
+ # comments
247
+ def test_comment_slash
248
+ json = %{{
249
+ "x":true,//three
250
+ "y":58,
251
+ "z": [1,2,
252
+ 3 // six
253
+ ]}
254
+ }
255
+ obj = Oj.compat_load(json)
256
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
257
+ end
258
+
259
+ def test_comment_c
260
+ json = %{{
261
+ "x"/*one*/:/*two*/true,
262
+ "y":58,
263
+ "z": [1,2,3]}
264
+ }
265
+ obj = Oj.compat_load(json)
266
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
267
+ end
268
+
269
+ def test_comment
270
+ json = %{{
271
+ "x"/*one*/:/*two*/true,//three
272
+ "y":58/*four*/,
273
+ "z": [1,2/*five*/,
274
+ 3 // six
275
+ ]
276
+ }
277
+ }
278
+ obj = Oj.compat_load(json)
279
+ assert_equal({ 'x' => true, 'y' => 58, 'z' => [1, 2, 3]}, obj)
280
+ end
281
+
282
+ def test_json_object_compat
283
+ obj = Jeez.new(true, 58)
284
+ dump_and_load(obj, false)
285
+ end
286
+
287
+ def test_json_module_object
288
+ obj = One::Two::Three::Deep.new()
289
+ dump_and_load(obj, false)
290
+ end
291
+
292
+ def test_json_object_create_id
293
+ expected = Jeez.new(true, 58)
294
+ json = Oj.dump(expected, :indent => 2, :mode => :compat)
295
+ obj = Oj.compat_load(json)
296
+ assert_equal(expected, obj)
297
+ end
298
+
299
+ def test_json_object_bad
300
+ json = %{{"json_class":"Junk","x":true}}
301
+ begin
302
+ Oj.compat_load(json)
303
+ rescue Exception => e
304
+ assert_equal("Oj::ParseError", e.class().name)
305
+ return
306
+ end
307
+ assert(false, "*** expected an exception")
308
+ end
309
+
310
+ def test_json_object_create_cache
311
+ expected = Jeez.new(true, 58)
312
+ json = Oj.dump(expected, :indent => 2, :mode => :compat)
313
+ obj = Oj.compat_load(json, :class_cache => true)
314
+ assert_equal(expected, obj)
315
+ obj = Oj.compat_load(json, :class_cache => false)
316
+ assert_equal(expected, obj)
317
+ end
318
+
319
+ def test_json_object_create_id_other
320
+ expected = Jeez.new(true, 58)
321
+ json = Oj.dump(expected, :indent => 2, :mode => :compat)
322
+ json.gsub!('json_class', '_class_')
323
+ obj = Oj.compat_load(json, :create_id => "_class_")
324
+ assert_equal(expected, obj)
325
+ end
326
+
327
+ def test_json_object_create_deep
328
+ expected = One::Two::Three::Deep.new()
329
+ json = Oj.dump(expected, :indent => 2, :mode => :compat)
330
+ obj = Oj.compat_load(json)
331
+ assert_equal(expected, obj)
332
+ end
333
+
334
+ def dump_and_load(obj, trace=false)
335
+ json = Oj.dump(obj, :indent => 2, :mode => :compat)
336
+ puts json if trace
337
+ loaded = Oj.compat_load(json);
338
+ assert_equal(obj, loaded)
339
+ loaded
340
+ end
341
+
342
+ end