oj 2.0.0 → 3.0.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.
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}.