oj 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +17 -23
  3. data/README.md +74 -425
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +4 -0
  6. data/ext/oj/circarray.c +68 -0
  7. data/ext/oj/circarray.h +23 -0
  8. data/ext/oj/code.c +227 -0
  9. data/ext/oj/code.h +40 -0
  10. data/ext/oj/compat.c +243 -0
  11. data/ext/oj/custom.c +1097 -0
  12. data/ext/oj/dump.c +766 -1534
  13. data/ext/oj/dump.h +92 -0
  14. data/ext/oj/dump_compat.c +937 -0
  15. data/ext/oj/dump_leaf.c +254 -0
  16. data/ext/oj/dump_object.c +810 -0
  17. data/ext/oj/dump_rails.c +329 -0
  18. data/ext/oj/dump_strict.c +416 -0
  19. data/ext/oj/encode.h +51 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +17 -7
  23. data/ext/oj/fast.c +213 -180
  24. data/ext/oj/hash.c +163 -0
  25. data/ext/oj/hash.h +46 -0
  26. data/ext/oj/hash_test.c +512 -0
  27. data/ext/oj/mimic_json.c +817 -0
  28. data/ext/oj/mimic_rails.c +806 -0
  29. data/ext/oj/mimic_rails.h +17 -0
  30. data/ext/oj/object.c +752 -0
  31. data/ext/oj/odd.c +230 -0
  32. data/ext/oj/odd.h +44 -0
  33. data/ext/oj/oj.c +1288 -929
  34. data/ext/oj/oj.h +240 -69
  35. data/ext/oj/parse.c +1014 -0
  36. data/ext/oj/parse.h +92 -0
  37. data/ext/oj/reader.c +223 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +127 -0
  40. data/ext/oj/{cache.h → resolve.h} +6 -13
  41. data/ext/oj/rxclass.c +133 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +77 -175
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +911 -0
  46. data/ext/oj/stream_writer.c +301 -0
  47. data/ext/oj/strict.c +162 -0
  48. data/ext/oj/string_writer.c +480 -0
  49. data/ext/oj/val_stack.c +98 -0
  50. data/ext/oj/val_stack.h +188 -0
  51. data/lib/oj/active_support_helper.rb +41 -0
  52. data/lib/oj/bag.rb +6 -10
  53. data/lib/oj/easy_hash.rb +52 -0
  54. data/lib/oj/json.rb +172 -0
  55. data/lib/oj/mimic.rb +260 -5
  56. data/lib/oj/saj.rb +13 -10
  57. data/lib/oj/schandler.rb +142 -0
  58. data/lib/oj/state.rb +131 -0
  59. data/lib/oj/version.rb +1 -1
  60. data/lib/oj.rb +11 -23
  61. data/pages/Advanced.md +22 -0
  62. data/pages/Compatibility.md +25 -0
  63. data/pages/Custom.md +23 -0
  64. data/pages/Encoding.md +65 -0
  65. data/pages/JsonGem.md +79 -0
  66. data/pages/Modes.md +140 -0
  67. data/pages/Options.md +250 -0
  68. data/pages/Rails.md +60 -0
  69. data/pages/Security.md +20 -0
  70. data/test/_test_active.rb +76 -0
  71. data/test/_test_active_mimic.rb +96 -0
  72. data/test/_test_mimic_rails.rb +126 -0
  73. data/test/activesupport4/decoding_test.rb +105 -0
  74. data/test/activesupport4/encoding_test.rb +531 -0
  75. data/test/activesupport4/test_helper.rb +41 -0
  76. data/test/activesupport5/decoding_test.rb +125 -0
  77. data/test/activesupport5/encoding_test.rb +483 -0
  78. data/test/activesupport5/encoding_test_cases.rb +90 -0
  79. data/test/activesupport5/test_helper.rb +50 -0
  80. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  81. data/test/helper.rb +27 -0
  82. data/test/isolated/shared.rb +310 -0
  83. data/test/isolated/test_mimic_after.rb +13 -0
  84. data/test/isolated/test_mimic_alone.rb +12 -0
  85. data/test/isolated/test_mimic_as_json.rb +45 -0
  86. data/test/isolated/test_mimic_before.rb +13 -0
  87. data/test/isolated/test_mimic_define.rb +28 -0
  88. data/test/isolated/test_mimic_rails_after.rb +22 -0
  89. data/test/isolated/test_mimic_rails_before.rb +21 -0
  90. data/test/isolated/test_mimic_redefine.rb +15 -0
  91. data/test/json_gem/json_addition_test.rb +216 -0
  92. data/test/json_gem/json_common_interface_test.rb +143 -0
  93. data/test/json_gem/json_encoding_test.rb +109 -0
  94. data/test/json_gem/json_ext_parser_test.rb +20 -0
  95. data/test/json_gem/json_fixtures_test.rb +35 -0
  96. data/test/json_gem/json_generator_test.rb +383 -0
  97. data/test/json_gem/json_generic_object_test.rb +90 -0
  98. data/test/json_gem/json_parser_test.rb +470 -0
  99. data/test/json_gem/json_string_matching_test.rb +42 -0
  100. data/test/json_gem/test_helper.rb +18 -0
  101. data/test/perf_compat.rb +130 -0
  102. data/test/perf_fast.rb +9 -9
  103. data/test/perf_file.rb +64 -0
  104. data/test/{perf_obj.rb → perf_object.rb} +24 -10
  105. data/test/perf_scp.rb +151 -0
  106. data/test/perf_strict.rb +32 -113
  107. data/test/sample.rb +2 -3
  108. data/test/test_compat.rb +474 -0
  109. data/test/test_custom.rb +355 -0
  110. data/test/test_debian.rb +53 -0
  111. data/test/test_fast.rb +66 -16
  112. data/test/test_file.rb +237 -0
  113. data/test/test_gc.rb +49 -0
  114. data/test/test_hash.rb +29 -0
  115. data/test/test_null.rb +376 -0
  116. data/test/test_object.rb +1010 -0
  117. data/test/test_saj.rb +16 -16
  118. data/test/test_scp.rb +417 -0
  119. data/test/test_strict.rb +410 -0
  120. data/test/test_various.rb +815 -0
  121. data/test/test_writer.rb +308 -0
  122. data/test/tests.rb +9 -902
  123. data/test/tests_mimic.rb +14 -0
  124. data/test/tests_mimic_addition.rb +7 -0
  125. metadata +253 -38
  126. data/ext/oj/cache.c +0 -148
  127. data/ext/oj/foo.rb +0 -6
  128. data/ext/oj/load.c +0 -1049
  129. data/test/a.rb +0 -38
  130. data/test/perf1.rb +0 -64
  131. data/test/perf2.rb +0 -76
  132. data/test/perf_obj_old.rb +0 -213
  133. data/test/test_mimic.rb +0 -208
data/lib/oj/mimic.rb CHANGED
@@ -1,12 +1,267 @@
1
1
 
2
+ require 'bigdecimal'
3
+ begin
4
+ require 'ostruct'
5
+ rescue Exception
6
+ # ignore
7
+ end
8
+
2
9
  module Oj
3
-
10
+
11
+ # A bit hack-ish but does the trick. The JSON.dump_default_options is a Hash
12
+ # but in mimic we use a C struct to store defaults. This class creates a view
13
+ # onto that struct.
14
+ class MimicDumpOption < Hash
15
+ def initialize()
16
+ oo = Oj.default_options
17
+ self.store(:max_nesting, false)
18
+ self.store(:allow_nan, true)
19
+ self.store(:quirks_mode, oo[:quirks_mode])
20
+ self.store(:ascii_only, (:ascii == oo[:escape_mode]))
21
+ end
22
+
23
+ def []=(key, value)
24
+ case key
25
+ when :quirks_mode
26
+ Oj.default_options = {:quirks_mode => value}
27
+ when :ascii_only
28
+ Oj.default_options = {:ascii_only => value}
29
+ end
30
+ end
31
+ end
32
+
33
+ # Loads mimic-ed JSON paths. Used by Oj.mimic_JSON().
34
+ # @param mimic_path [Array] additional paths to add to the Ruby loaded features.
4
35
  def self.mimic_loaded(mimic_paths=[])
5
- gems_dir = File.dirname(File.dirname(File.dirname(File.dirname(__FILE__))))
6
- Dir.foreach(gems_dir) do |gem|
7
- next unless (gem.start_with?('json-') || gem.start_with?('json_pure'))
8
- $LOADED_FEATURES << File.join(gems_dir, gem, 'lib', 'json.rb')
36
+ $LOAD_PATH.each do |d|
37
+ next unless File.exist?(d)
38
+
39
+ jfile = File.join(d, 'json.rb')
40
+ $LOADED_FEATURES << jfile unless $LOADED_FEATURES.include?(jfile) if File.exist?(jfile)
41
+
42
+ Dir.glob(File.join(d, 'json', '**', '*.rb')).each do |file|
43
+ # allow json/add/xxx to be loaded. User can override with Oj.add_to_json(xxx).
44
+ $LOADED_FEATURES << file unless $LOADED_FEATURES.include?(file) unless file.include?('add')
45
+ end
9
46
  end
10
47
  mimic_paths.each { |p| $LOADED_FEATURES << p }
48
+ $LOADED_FEATURES << 'json' unless $LOADED_FEATURES.include?('json')
49
+
50
+ require 'oj/json'
51
+
52
+ if Object.const_defined?('OpenStruct')
53
+ OpenStruct.class_eval do
54
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
55
+ unless defined?(self.as_json)
56
+ def as_json(*)
57
+ name = self.class.name.to_s
58
+ raise JSON::JSONError, "Only named structs are supported!" if 0 == name.length
59
+ { JSON.create_id => name, 't' => table }
60
+ end
61
+ end
62
+ def self.json_create(h)
63
+ new(h['t'] || h[:t])
64
+ end
65
+ end
66
+ end
67
+
68
+ BigDecimal.class_eval do
69
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
70
+ unless defined?(self.as_json)
71
+ def as_json(*)
72
+ {JSON.create_id => 'BigDecimal', 'b' => _dump }
73
+ end
74
+ end
75
+ def self.json_create(h)
76
+ BigDecimal._load(h['b'])
77
+ end
78
+ end
79
+
80
+ Complex.class_eval do
81
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
82
+ unless defined?(self.as_json)
83
+ def as_json(*)
84
+ {JSON.create_id => 'Complex', 'r' => real, 'i' => imag }
85
+ end
86
+ end
87
+ def self.json_create(h)
88
+ Complex(h['r'], h['i'])
89
+ end
90
+ end
91
+
92
+ Date.class_eval do
93
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
94
+ unless defined?(self.as_json)
95
+ def as_json(*)
96
+ { JSON.create_id => 'Date', 'y' => year, 'm' => month, 'd' => day, 'sg' => start }
97
+ end
98
+ end
99
+ def self.json_create(h)
100
+ civil(h['y'], h['m'], h['d'], h['sg'])
101
+ end
102
+ end
103
+
104
+ DateTime.class_eval do
105
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
106
+ unless defined?(self.as_json)
107
+ def as_json(*)
108
+ { JSON.create_id => 'DateTime',
109
+ 'y' => year,
110
+ 'm' => month,
111
+ 'd' => day,
112
+ 'H' => hour,
113
+ 'M' => min,
114
+ 'S' => sec,
115
+ 'of' => offset.to_s,
116
+ 'sg' => start }
117
+ end
118
+ end
119
+ def self.json_create(h)
120
+ # offset is a rational as a string
121
+ as, bs = h['of'].split('/')
122
+ a = as.to_i
123
+ b = bs.to_i
124
+ if 0 == b
125
+ off = a
126
+ else
127
+ off = Rational(a, b)
128
+ end
129
+ civil(h['y'], h['m'], h['d'], h['H'], h['M'], h['S'], off, h['sg'])
130
+ end
131
+ end
132
+
133
+ Date.class_eval do
134
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
135
+ unless defined?(self.as_json)
136
+ def as_json(*)
137
+ { JSON.create_id => 'Date', 'y' => year, 'm' => month, 'd' => day, 'sg' => start }
138
+ end
139
+ end
140
+ def self.json_create(h)
141
+ civil(h['y'], h['m'], h['d'], h['sg'])
142
+ end
143
+ end
144
+
145
+ Exception.class_eval do
146
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
147
+ unless defined?(self.as_json)
148
+ def as_json(*)
149
+ {JSON.create_id => self.class.name, 'm' => message, 'b' => backtrace }
150
+ end
151
+ end
152
+ def self.json_create(h)
153
+ e = new(h['m'])
154
+ e.set_backtrace(h['b'])
155
+ e
156
+ end
157
+ end
158
+
159
+ Range.class_eval do
160
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
161
+ unless defined?(self.as_json)
162
+ def as_json(*)
163
+ {JSON.create_id => 'Range', 'a' => [first, last, exclude_end?]}
164
+ end
165
+ end
166
+ def self.json_create(h)
167
+ new(*h['a'])
168
+ end
169
+ end
170
+
171
+ Rational.class_eval do
172
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
173
+ unless defined?(self.as_json)
174
+ def as_json(*)
175
+ {JSON.create_id => 'Rational', 'n' => numerator, 'd' => denominator }
176
+ end
177
+ end
178
+ def self.json_create(h)
179
+ Rational(h['n'], h['d'])
180
+ end
181
+ end
182
+
183
+ Regexp.class_eval do
184
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
185
+ unless defined?(self.as_json)
186
+ def as_json(*)
187
+ {JSON.create_id => 'Regexp', 'o' => options, 's' => source }
188
+ end
189
+ end
190
+ def self.json_create(h)
191
+ new(h['s'], h['o'])
192
+ end
193
+ end
194
+
195
+ Struct.class_eval do
196
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
197
+ unless defined?(self.as_json)
198
+ def as_json(*)
199
+ name = self.class.name.to_s
200
+ raise JSON::JSONError, "Only named structs are supported!" if 0 == name.length
201
+ { JSON.create_id => name, 'v' => values }
202
+ end
203
+ end
204
+ def self.json_create(h)
205
+ new(*h['v'])
206
+ end
207
+ end
208
+
209
+ Symbol.class_eval do
210
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
211
+ unless defined?(self.as_json)
212
+ def as_json(*)
213
+ {JSON.create_id => 'Symbol', 's' => to_s }
214
+ end
215
+ end
216
+ def self.json_create(h)
217
+ h['s'].to_sym
218
+ end
219
+ end
220
+
221
+ Time.class_eval do
222
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
223
+ unless defined?(self.as_json)
224
+ def as_json(*)
225
+ nsecs = [ tv_usec * 1000 ]
226
+ nsecs << tv_nsec if respond_to?(:tv_nsec)
227
+ nsecs = nsecs.max
228
+ { JSON.create_id => 'Time', 's' => tv_sec, 'n' => nsecs }
229
+ end
230
+ end
231
+ def self.json_create(h)
232
+ if usec = h.delete('u')
233
+ h['n'] = usec * 1000
234
+ end
235
+ if instance_methods.include?(:tv_nsec)
236
+ at(h['s'], Rational(h['n'], 1000))
237
+ else
238
+ at(h['s'], h['n'] / 1000)
239
+ end
240
+ end
241
+ end
242
+
243
+ end # self.mimic_loaded
244
+
245
+ end # Oj
246
+
247
+ # More monkey patches.
248
+ class String
249
+ def to_json_raw_object
250
+ {
251
+ JSON.create_id => self.class.name,
252
+ 'raw' => self.bytes
253
+ }
254
+ end
255
+ def to_json_raw(*)
256
+ to_json_raw_object().to_json()
257
+ end
258
+ def self.json_create(obj)
259
+ s = ''
260
+ s.encode!(Encoding::ASCII_8BIT) if s.respond_to?(:encode!)
261
+ raw = obj['raw']
262
+ if raw.is_a? Array
263
+ raw.each { |v| s << v }
264
+ end
265
+ s
11
266
  end
12
267
  end
data/lib/oj/saj.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  module Oj
2
- # A SAX style parse handler for JSON hence the acronym SAJ for Simple API for JSON. The Oj::Saj handler class should be subclassed
3
- # and then used with the Oj.saj_parse() method. The Saj methods will then be
4
- # called as the file is parsed.
2
+ # A SAX style parse handler for JSON hence the acronym SAJ for Simple API for
3
+ # JSON. The Oj::Saj handler class should be subclassed and then used with the
4
+ # Oj::Saj key_parse() method. The Saj methods will then be called as the file
5
+ # is parsed.
6
+ #
5
7
  # @example
6
8
  #
7
9
  # require 'oj'
@@ -11,18 +13,19 @@ module Oj
11
13
  # @hash_cnt = 0
12
14
  # end
13
15
  #
14
- # def start_hash(key)
16
+ # def hash_start(key)
15
17
  # @hash_cnt += 1
16
18
  # end
17
19
  # end
18
20
  #
19
21
  # cnt = MySaj.new()
20
- # File.open('any.xml', 'r') do |f|
22
+ # File.open('any.json', 'r') do |f|
21
23
  # Oj.saj_parse(cnt, f)
22
24
  # end
23
25
  #
24
- # To make the desired methods active while parsing the desired method should be made public in the subclasses. If the
25
- # methods remain private they will not be called during parsing.
26
+ # To make the desired methods active while parsing the desired method should
27
+ # be made public in the subclasses. If the methods remain private they will
28
+ # not be called during parsing.
26
29
  #
27
30
  # def hash_start(key); end
28
31
  # def hash_end(key); end
@@ -36,9 +39,9 @@ module Oj
36
39
  def initialize()
37
40
  end
38
41
 
39
- # To make the desired methods active while parsing the desired method
40
- # should be made public in the subclasses. If the methods remain private
41
- # they will not be called during parsing.
42
+ # To make the desired methods active while parsing the desired method should
43
+ # be made public in the subclasses. If the methods remain private they will
44
+ # not be called during parsing.
42
45
  private
43
46
 
44
47
  def hash_start(key)
@@ -0,0 +1,142 @@
1
+ module Oj
2
+ # A Simple Callback Parser (SCP) for JSON. The Oj::ScHandler class should be
3
+ # subclassed and then used with the Oj.sc_parse() method. The Scp methods will
4
+ # then be called as the file is parsed. The handler does not have to be a
5
+ # subclass of the ScHandler class as long as it responds to the desired
6
+ # methods.
7
+ #
8
+ # @example
9
+ #
10
+ # require 'oj'
11
+ #
12
+ # class MyHandler < ::Oj::ScHandler
13
+ # def hash_start
14
+ # {}
15
+ # end
16
+ #
17
+ # def hash_set(h,k,v)
18
+ # h[k] = v
19
+ # end
20
+ #
21
+ # def array_start
22
+ # []
23
+ # end
24
+ #
25
+ # def array_append(a,v)
26
+ # a << v
27
+ # end
28
+ #
29
+ # def add_value(v)
30
+ # p v
31
+ # end
32
+ #
33
+ # def error(message, line, column)
34
+ # p "ERROR: #{message}"
35
+ # end
36
+ # end
37
+ #
38
+ # File.open('any.json', 'r') do |f|
39
+ # Oj.sc_parse(MyHandler.new, f)
40
+ # end
41
+ #
42
+ # To make the desired methods active while parsing the desired method should
43
+ # be made public in the subclasses. If the methods remain private they will
44
+ # not be called during parsing.
45
+ #
46
+ # def hash_start(); end
47
+ # def hash_end(); end
48
+ # def hash_key(key); end
49
+ # def hash_set(h, key, value); end
50
+ # def array_start(); end
51
+ # def array_end(); end
52
+ # def array_append(a, value); end
53
+ # def add_value(value); end
54
+ #
55
+ # As certain elements of a JSON document are reached during parsing the
56
+ # callbacks are called. The parser helps by keeping track of objects created
57
+ # by the callbacks but does not create those objects itself.
58
+ #
59
+ # hash_start
60
+ #
61
+ # When a JSON object element starts the hash_start() callback is called if
62
+ # public. It should return what ever Ruby Object is to be used as the element
63
+ # that will later be included in the hash_set() callback.
64
+ #
65
+ # hash_end
66
+ #
67
+ # When a hash key is encountered the hash_key method is called with the parsed
68
+ # hash value key. The return value from the call is then used as the key in
69
+ # the key-value pair that follows.
70
+ #
71
+ # hash_key
72
+ #
73
+ # At the end of a JSON object element the hash_end() callback is called if public.
74
+ #
75
+ # hash_set
76
+ #
77
+ # When a key value pair is encountered during parsing the hash_set() callback
78
+ # is called if public. The first element will be the object returned from the
79
+ # enclosing hash_start() callback. The second argument is the key and the last
80
+ # is the value.
81
+ #
82
+ # array_start
83
+ #
84
+ # When a JSON array element is started the array_start() callback is called if
85
+ # public. It should return what ever Ruby Object is to be used as the element
86
+ # that will later be included in the array_append() callback.
87
+ #
88
+ # array_end
89
+ #
90
+ # At the end of a JSON array element the array_end() callback is called if public.
91
+ #
92
+ # array_append
93
+ #
94
+ # When a element is encountered that is an element of an array the
95
+ # array_append() callback is called if public. The first argument to the
96
+ # callback is the Ruby object returned from the enclosing array_start()
97
+ # callback.
98
+ #
99
+ # add_value
100
+ #
101
+ # The handler is expected to handle multiple JSON elements in one stream,
102
+ # file, or string. When a top level JSON has been read completely the
103
+ # add_value() callback is called. Even if only one element was ready this
104
+ # callback returns the Ruby object that was constructed during the parsing.
105
+ #
106
+ class ScHandler
107
+ # Create a new instance of the ScHandler class.
108
+ def initialize()
109
+ end
110
+
111
+ # To make the desired methods active while parsing the desired method should
112
+ # be made public in the subclasses. If the methods remain private they will
113
+ # not be called during parsing.
114
+ private
115
+
116
+ def hash_start()
117
+ end
118
+
119
+ def hash_end()
120
+ end
121
+
122
+ def hash_key(key)
123
+ key
124
+ end
125
+
126
+ def hash_set(h, key, value)
127
+ end
128
+
129
+ def array_start()
130
+ end
131
+
132
+ def array_end()
133
+ end
134
+
135
+ def add_value(value)
136
+ end
137
+
138
+ def array_append(a, value)
139
+ end
140
+
141
+ end # ScHandler
142
+ end # Oj
data/lib/oj/state.rb ADDED
@@ -0,0 +1,131 @@
1
+
2
+ module JSON
3
+ module Ext
4
+ module Generator
5
+ unless defined?(::JSON::Ext::Generator::State)
6
+ # This class exists for json gem compatibility only. While it can be
7
+ # used as the options for other than compatibility a simple Hash is
8
+ # recommended as it is simpler and performs better. The only bit
9
+ # missing by not using a state object is the depth availability which
10
+ # may be the depth during dumping or maybe not since it can be set and
11
+ # the docs for depth= is the same as max_nesting. Note: Had to make
12
+ # this a subclass of Object instead of Hash like EashyHash due to
13
+ # conflicts with the json gem.
14
+ class State
15
+
16
+ def self.from_state(opts)
17
+ s = self.new()
18
+ s.clear()
19
+ s.merge(opts)
20
+ s
21
+ end
22
+
23
+ def initialize(opts = {})
24
+ @attrs = {}
25
+
26
+ # Populate with all vars then merge in opts. This class deviates from
27
+ # the json gem in that any of the options can be set with the opts
28
+ # argument. The json gem limits the opts use to 7 of the options.
29
+ @attrs[:indent] = ''
30
+ @attrs[:space] = ''
31
+ @attrs[:space_before] = ''
32
+ @attrs[:array_nl] = ''
33
+ @attrs[:object_nl] = ''
34
+ @attrs[:allow_nan] = false
35
+ @attrs[:buffer_initial_length] = 1024 # completely ignored by Oj
36
+ @attrs[:depth] = 0
37
+ @attrs[:max_nesting] = 100
38
+ @attrs[:check_circular?] = true
39
+ @attrs[:ascii_only] = false
40
+
41
+ @attrs.merge!(opts)
42
+ end
43
+
44
+ def to_h()
45
+ return @attrs.dup
46
+ end
47
+
48
+ def to_hash()
49
+ return @attrs.dup
50
+ end
51
+
52
+ def allow_nan?()
53
+ @attrs[:allow_nan]
54
+ end
55
+
56
+ def ascii_only?()
57
+ @attrs[:ascii_only]
58
+ end
59
+
60
+ def configure(opts)
61
+ raise TypeError.new('expected a Hash') unless opts.respond_to?(:to_h)
62
+ @attrs.merge!(opts.to_h)
63
+ end
64
+
65
+ def generate(obj)
66
+ JSON.generate(obj)
67
+ end
68
+
69
+ def merge(opts)
70
+ @attrs.merge!(opts)
71
+ end
72
+
73
+ # special rule for this.
74
+ def buffer_initial_length=(len)
75
+ len = 1024 if 0 >= len
76
+ @attrs[:buffer_initial_length] = len
77
+ end
78
+
79
+ # Replaces the Object.respond_to?() method.
80
+ # @param [Symbol] m method symbol
81
+ # @return [Boolean] true for any method that matches an instance
82
+ # variable reader, otherwise false.
83
+ def respond_to?(m)
84
+ return true if super
85
+ return true if has_key?(key)
86
+ return true if has_key?(key.to_s)
87
+ has_key?(key.to_sym)
88
+ end
89
+
90
+ def [](key)
91
+ key = key.to_sym
92
+ @attrs.fetch(key, nil)
93
+ end
94
+
95
+ def []=(key, value)
96
+ key = key.to_sym
97
+ @attrs[key] = value
98
+ end
99
+
100
+ def clear()
101
+ @attrs.clear()
102
+ end
103
+
104
+ def has_key?(k)
105
+ @attrs.has_key?(key.to_sym)
106
+ end
107
+
108
+ # Handles requests for Hash values. Others cause an Exception to be raised.
109
+ # @param [Symbol|String] m method symbol
110
+ # @return [Boolean] the value of the specified instance variable.
111
+ # @raise [ArgumentError] if an argument is given. Zero arguments expected.
112
+ # @raise [NoMethodError] if the instance variable is not defined.
113
+ def method_missing(m, *args, &block)
114
+ if m.to_s.end_with?('=')
115
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 1 with #{m}) to method #{m}") if args.nil? or 1 != args.length
116
+ m = m.to_s[0..-2]
117
+ m = m.to_sym
118
+ return @attrs.store(m, args[0])
119
+ else
120
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 0 with #{m}) to method #{m}") unless args.nil? or args.empty?
121
+ return @attrs[m.to_sym]
122
+ end
123
+ raise NoMethodError.new("undefined method #{m}", m)
124
+ end
125
+
126
+ end # State
127
+ end # defined check
128
+ end # Generator
129
+ end # Ext
130
+
131
+ end # JSON
data/lib/oj/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '2.0.0'
4
+ VERSION = '3.0.0'
5
5
  end
data/lib/oj.rb CHANGED
@@ -1,33 +1,21 @@
1
- # Optimized JSON (Oj), as the name implies was written to provide speed
2
- # optimized JSON handling.
3
- #
4
- # Oj has several dump or serialization modes which control how Objects are
5
- # converted to JSON. These modes are set with the :mode option in either the
6
- # default options or as one of the options to the dump() method.
7
- #
8
- # - :strict mode will only allow the 7 basic JSON types to be serialized. Any other Object
9
- # will raise and Exception.
10
- #
11
- # - :null mode replaces any Object that is not one of the JSON types is replaced by a JSON null.
12
- #
13
- # - :object mode will dump any Object as a JSON Object with keys that match
14
- # the Ruby Object's variable names without the '@' character. This is the
15
- # highest performance mode.
16
- #
17
- # - :compat mode is is the compatible with other systems. It will serialize
18
- # any Object but will check to see if the Object implements a to_hash() or
19
- # to_json() method. If either exists that method is used for serializing the
20
- # Object. The to_hash() is more flexible and produces more consistent output
21
- # so it has a preference over the to_json() method. If neither the to_json()
22
- # or to_hash() methods exist then the Oj internal Object variable encoding
23
- # is used.
1
+
24
2
  module Oj
25
3
  end
26
4
 
5
+ begin
6
+ # This require exists to get around Rubinius failing to load bigdecimal from
7
+ # the C extension.
8
+ require 'bigdecimal'
9
+ rescue Exception
10
+ # ignore
11
+ end
12
+
27
13
  require 'oj/version'
28
14
  require 'oj/bag'
15
+ require 'oj/easy_hash'
29
16
  require 'oj/error'
30
17
  require 'oj/mimic'
31
18
  require 'oj/saj'
19
+ require 'oj/schandler'
32
20
 
33
21
  require 'oj/oj' # C extension
data/pages/Advanced.md ADDED
@@ -0,0 +1,22 @@
1
+ # Advanced Features
2
+
3
+ Optimized JSON (Oj), as the name implies, was written to provide speed optimized
4
+ JSON handling. It was designed as a faster alternative to Yajl and other
5
+ common Ruby JSON parsers. So far it has achieved that, and is about 2 times faster
6
+ than any other Ruby JSON parser, and 3 or more times faster at serializing JSON.
7
+
8
+ Oj has several `dump` or serialization modes which control how Ruby `Object`s are
9
+ converted to JSON. These modes are set with the `:mode` option in either the
10
+ default options or as one of the options to the `dump` method. In addition to
11
+ the various options there are also alternative APIs for parsing JSON.
12
+
13
+ The fastest alternative parser API is the `Oj::Doc` API. The `Oj::Doc` API takes
14
+ a completely different approach by opening a JSON document and providing calls
15
+ to navigate around the JSON while it is open. With this approach, JSON access
16
+ can be well over 20 times faster than conventional JSON parsing.
17
+
18
+ The `Oj::Saj` and `Oj::ScHandler` APIs are callback parsers that
19
+ walk the JSON document depth first and makes callbacks for each element.
20
+ Both callback parser are useful when only portions of the JSON are of
21
+ interest. Performance up to 20 times faster than conventional JSON is
22
+ possible if only a few elements of the JSON are of interest.
@@ -0,0 +1,25 @@
1
+ # Compatibility
2
+
3
+ **Ruby**
4
+
5
+ Oj is compatible with Ruby 1.9.3, 2.0.0, 2.1, 2.2, 2.3, 2.4 and RBX.
6
+ Support for JRuby has been removed as JRuby no longer supports C extensions and
7
+ there are bugs in the older versions that are not being fixed.
8
+
9
+ **Rails**
10
+
11
+ Although up until 4.1 Rails uses [multi_json](https://github.com/intridea/multi_json), an [issue in Rails](https://github.com/rails/rails/issues/9212) causes ActiveSupport to fail to make use Oj for JSON handling.
12
+ There is a
13
+ [gem to patch this](https://github.com/GoodLife/rails-patch-json-encode) for
14
+ Rails 3.2 and 4.0. As of the Oj 2.6.0 release the default behavior is to not use
15
+ the `to_json()` method unless the `:use_to_json` option is set. This provides
16
+ another work around to the rails older and newer behavior.
17
+
18
+ The latest ActiveRecord is able to work with Oj by simply using the line:
19
+
20
+ ```
21
+ serialize :metadata, Oj
22
+ ```
23
+
24
+ In version Rails 4.1, multi_json has been removed, and this patch is unnecessary and will no longer work.
25
+ See {file:Rails.md}.