oj 2.18.3 → 3.13.14

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 (182) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1324 -0
  3. data/README.md +51 -204
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +49 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -68
  11. data/ext/oj/circarray.h +16 -42
  12. data/ext/oj/code.c +221 -0
  13. data/ext/oj/code.h +40 -0
  14. data/ext/oj/compat.c +231 -107
  15. data/ext/oj/custom.c +1125 -0
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +935 -2513
  18. data/ext/oj/dump.h +108 -0
  19. data/ext/oj/dump_compat.c +936 -0
  20. data/ext/oj/dump_leaf.c +164 -0
  21. data/ext/oj/dump_object.c +761 -0
  22. data/ext/oj/dump_strict.c +410 -0
  23. data/ext/oj/encode.h +7 -42
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -54
  26. data/ext/oj/err.h +52 -46
  27. data/ext/oj/extconf.rb +21 -30
  28. data/ext/oj/fast.c +1097 -1080
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +893 -0
  32. data/ext/oj/object.c +549 -620
  33. data/ext/oj/odd.c +155 -167
  34. data/ext/oj/odd.h +37 -63
  35. data/ext/oj/oj.c +1661 -2063
  36. data/ext/oj/oj.h +341 -270
  37. data/ext/oj/parse.c +974 -737
  38. data/ext/oj/parse.h +105 -97
  39. data/ext/oj/parser.c +1526 -0
  40. data/ext/oj/parser.h +90 -0
  41. data/ext/oj/rails.c +1504 -0
  42. data/ext/oj/rails.h +18 -0
  43. data/ext/oj/reader.c +141 -163
  44. data/ext/oj/reader.h +75 -113
  45. data/ext/oj/resolve.c +45 -93
  46. data/ext/oj/resolve.h +7 -34
  47. data/ext/oj/rxclass.c +143 -0
  48. data/ext/oj/rxclass.h +26 -0
  49. data/ext/oj/saj.c +447 -511
  50. data/ext/oj/saj2.c +348 -0
  51. data/ext/oj/scp.c +91 -138
  52. data/ext/oj/sparse.c +793 -644
  53. data/ext/oj/stream_writer.c +331 -0
  54. data/ext/oj/strict.c +145 -109
  55. data/ext/oj/string_writer.c +493 -0
  56. data/ext/oj/trace.c +72 -0
  57. data/ext/oj/trace.h +28 -0
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +62 -70
  62. data/ext/oj/val_stack.h +95 -129
  63. data/ext/oj/validate.c +51 -0
  64. data/ext/oj/wab.c +622 -0
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +17 -8
  67. data/lib/oj/error.rb +10 -11
  68. data/lib/oj/json.rb +176 -0
  69. data/lib/oj/mimic.rb +158 -19
  70. data/lib/oj/state.rb +132 -0
  71. data/lib/oj/version.rb +2 -2
  72. data/lib/oj.rb +1 -31
  73. data/pages/Advanced.md +22 -0
  74. data/pages/Compatibility.md +25 -0
  75. data/pages/Custom.md +23 -0
  76. data/pages/Encoding.md +65 -0
  77. data/pages/JsonGem.md +94 -0
  78. data/pages/Modes.md +161 -0
  79. data/pages/Options.md +327 -0
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +167 -0
  82. data/pages/Security.md +20 -0
  83. data/pages/WAB.md +13 -0
  84. data/test/activerecord/result_test.rb +32 -0
  85. data/test/activesupport4/decoding_test.rb +108 -0
  86. data/test/activesupport4/encoding_test.rb +531 -0
  87. data/test/activesupport4/test_helper.rb +41 -0
  88. data/test/activesupport5/abstract_unit.rb +45 -0
  89. data/test/activesupport5/decoding_test.rb +133 -0
  90. data/test/activesupport5/encoding_test.rb +500 -0
  91. data/test/activesupport5/encoding_test_cases.rb +98 -0
  92. data/test/activesupport5/test_helper.rb +72 -0
  93. data/test/activesupport5/time_zone_test_helpers.rb +39 -0
  94. data/test/activesupport6/abstract_unit.rb +44 -0
  95. data/test/activesupport6/decoding_test.rb +133 -0
  96. data/test/activesupport6/encoding_test.rb +507 -0
  97. data/test/activesupport6/encoding_test_cases.rb +98 -0
  98. data/test/activesupport6/test_common.rb +17 -0
  99. data/test/activesupport6/test_helper.rb +163 -0
  100. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  101. data/test/activesupport7/abstract_unit.rb +49 -0
  102. data/test/activesupport7/decoding_test.rb +125 -0
  103. data/test/activesupport7/encoding_test.rb +486 -0
  104. data/test/activesupport7/encoding_test_cases.rb +104 -0
  105. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  106. data/test/bar.rb +9 -0
  107. data/test/baz.rb +16 -0
  108. data/test/bug.rb +11 -46
  109. data/test/foo.rb +69 -16
  110. data/test/helper.rb +10 -1
  111. data/test/isolated/shared.rb +12 -8
  112. data/test/isolated/test_mimic_rails_after.rb +3 -3
  113. data/test/isolated/test_mimic_rails_before.rb +3 -3
  114. data/test/json_gem/json_addition_test.rb +216 -0
  115. data/test/json_gem/json_common_interface_test.rb +153 -0
  116. data/test/json_gem/json_encoding_test.rb +107 -0
  117. data/test/json_gem/json_ext_parser_test.rb +20 -0
  118. data/test/json_gem/json_fixtures_test.rb +35 -0
  119. data/test/json_gem/json_generator_test.rb +397 -0
  120. data/test/json_gem/json_generic_object_test.rb +90 -0
  121. data/test/json_gem/json_parser_test.rb +470 -0
  122. data/test/json_gem/json_string_matching_test.rb +42 -0
  123. data/test/json_gem/test_helper.rb +26 -0
  124. data/test/mem.rb +33 -0
  125. data/test/perf.rb +1 -1
  126. data/test/perf_compat.rb +30 -28
  127. data/test/perf_dump.rb +50 -0
  128. data/test/perf_object.rb +1 -1
  129. data/test/perf_once.rb +58 -0
  130. data/test/perf_parser.rb +189 -0
  131. data/test/perf_scp.rb +11 -10
  132. data/test/perf_strict.rb +30 -19
  133. data/test/perf_wab.rb +131 -0
  134. data/test/prec.rb +23 -0
  135. data/test/sample.rb +0 -1
  136. data/test/sample_json.rb +1 -1
  137. data/test/test_compat.rb +219 -102
  138. data/test/test_custom.rb +533 -0
  139. data/test/test_fast.rb +107 -35
  140. data/test/test_file.rb +19 -25
  141. data/test/test_generate.rb +21 -0
  142. data/test/test_hash.rb +11 -1
  143. data/test/test_integer_range.rb +72 -0
  144. data/test/test_null.rb +376 -0
  145. data/test/test_object.rb +357 -70
  146. data/test/test_parser.rb +27 -0
  147. data/test/test_parser_saj.rb +245 -0
  148. data/test/test_parser_usual.rb +217 -0
  149. data/test/test_rails.rb +35 -0
  150. data/test/test_saj.rb +1 -1
  151. data/test/test_scp.rb +39 -2
  152. data/test/test_strict.rb +186 -7
  153. data/test/test_various.rb +160 -774
  154. data/test/test_wab.rb +307 -0
  155. data/test/test_writer.rb +90 -2
  156. data/test/tests.rb +24 -0
  157. data/test/tests_mimic.rb +14 -0
  158. data/test/tests_mimic_addition.rb +7 -0
  159. data/test/zoo.rb +13 -0
  160. metadata +194 -56
  161. data/ext/oj/hash.c +0 -163
  162. data/ext/oj/hash.h +0 -46
  163. data/ext/oj/hash_test.c +0 -512
  164. data/test/activesupport_datetime_test.rb +0 -23
  165. data/test/bug2.rb +0 -10
  166. data/test/bug3.rb +0 -46
  167. data/test/bug_fast.rb +0 -32
  168. data/test/bug_load.rb +0 -24
  169. data/test/crash.rb +0 -111
  170. data/test/curl/curl_oj.rb +0 -46
  171. data/test/curl/get_oj.rb +0 -24
  172. data/test/curl/just_curl.rb +0 -31
  173. data/test/curl/just_oj.rb +0 -51
  174. data/test/example.rb +0 -11
  175. data/test/io.rb +0 -48
  176. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  177. data/test/mod.rb +0 -16
  178. data/test/rails.rb +0 -50
  179. data/test/russian.rb +0 -18
  180. data/test/struct.rb +0 -29
  181. data/test/test_serializer.rb +0 -59
  182. data/test/write_timebars.rb +0 -31
data/lib/oj/json.rb ADDED
@@ -0,0 +1,176 @@
1
+
2
+ require 'ostruct'
3
+ require 'oj/state'
4
+
5
+ module JSON
6
+ NaN = 0.0/0.0 unless defined?(::JSON::NaN)
7
+ Infinity = 1.0/0.0 unless defined?(::JSON::Infinity)
8
+ MinusInfinity = -1.0/0.0 unless defined?(::JSON::MinusInfinity)
9
+ # Taken from the unit test. Note that items like check_circular? are not
10
+ # present.
11
+ PRETTY_STATE_PROTOTYPE = Ext::Generator::State.from_state({
12
+ :allow_nan => false,
13
+ :array_nl => "\n",
14
+ :ascii_only => false,
15
+ :buffer_initial_length => 1024,
16
+ :depth => 0,
17
+ :indent => " ",
18
+ :max_nesting => 100,
19
+ :object_nl => "\n",
20
+ :space => " ",
21
+ :space_before => "",
22
+ }) unless defined?(::JSON::PRETTY_STATE_PROTOTYPE)
23
+ SAFE_STATE_PROTOTYPE = Ext::Generator::State.from_state({
24
+ :allow_nan => false,
25
+ :array_nl => "",
26
+ :ascii_only => false,
27
+ :buffer_initial_length => 1024,
28
+ :depth => 0,
29
+ :indent => "",
30
+ :max_nesting => 100,
31
+ :object_nl => "",
32
+ :space => "",
33
+ :space_before => "",
34
+ }) unless defined?(::JSON::SAFE_STATE_PROTOTYPE)
35
+ FAST_STATE_PROTOTYPE = Ext::Generator::State.from_state({
36
+ :allow_nan => false,
37
+ :array_nl => "",
38
+ :ascii_only => false,
39
+ :buffer_initial_length => 1024,
40
+ :depth => 0,
41
+ :indent => "",
42
+ :max_nesting => 0,
43
+ :object_nl => "",
44
+ :space => "",
45
+ :space_before => "",
46
+ }) unless defined?(::JSON::FAST_STATE_PROTOTYPE)
47
+
48
+ def self.dump_default_options
49
+ Oj::MimicDumpOption.new
50
+ end
51
+
52
+ def self.dump_default_options=(h)
53
+ m = Oj::MimicDumpOption.new
54
+ h.each do |k,v|
55
+ m[k] = v
56
+ end
57
+ end
58
+
59
+ def self.parser=(p)
60
+ @@parser = p
61
+ end
62
+
63
+ def self.parser()
64
+ @@parser
65
+ end
66
+
67
+ def self.generator=(g)
68
+ @@generator = g
69
+ end
70
+
71
+ def self.generator()
72
+ @@generator
73
+ end
74
+
75
+ module Ext
76
+ class Parser
77
+ def initialize(src)
78
+ raise TypeError.new("already initialized") unless @source.nil?
79
+ @source = src
80
+ end
81
+
82
+ def source()
83
+ raise TypeError.new("already initialized") if @source.nil?
84
+ @source
85
+ end
86
+
87
+ def parse()
88
+ raise TypeError.new("already initialized") if @source.nil?
89
+ JSON.parse(@source)
90
+ end
91
+
92
+ end # Parser
93
+ end # Ext
94
+
95
+ State = ::JSON::Ext::Generator::State unless defined?(::JSON::State)
96
+
97
+ begin
98
+ send(:remove_const, :Parser)
99
+ rescue
100
+ end
101
+ Parser = ::JSON::Ext::Parser unless defined?(::JSON::Parser)
102
+ self.parser = ::JSON::Ext::Parser
103
+ self.generator = ::JSON::Ext::Generator
104
+
105
+ # Taken directly from the json gem. Shamelessly copied. It is similar in
106
+ # some ways to the Oj::Bag class or the Oj::EasyHash class.
107
+ class GenericObject < OpenStruct
108
+ class << self
109
+ alias [] new
110
+
111
+ def json_creatable?
112
+ @json_creatable
113
+ end
114
+
115
+ attr_writer :json_creatable
116
+
117
+ def json_create(data)
118
+ data = data.dup
119
+ data.delete JSON.create_id
120
+ self[data]
121
+ end
122
+
123
+ def from_hash(object)
124
+ case
125
+ when object.respond_to?(:to_hash)
126
+ result = new
127
+ object.to_hash.each do |key, value|
128
+ result[key] = from_hash(value)
129
+ end
130
+ result
131
+ when object.respond_to?(:to_ary)
132
+ object.to_ary.map { |a| from_hash(a) }
133
+ else
134
+ object
135
+ end
136
+ end
137
+
138
+ def load(source, proc = nil, opts = {})
139
+ result = ::JSON.load(source, proc, opts.merge(:object_class => self))
140
+ result.nil? ? new : result
141
+ end
142
+
143
+ def dump(obj, *args)
144
+ ::JSON.dump(obj, *args)
145
+ end
146
+
147
+ end # self
148
+
149
+ self.json_creatable = false
150
+
151
+ def to_hash
152
+ table
153
+ end
154
+
155
+ def [](name)
156
+ __send__(name)
157
+ end unless method_defined?(:[])
158
+
159
+ def []=(name, value)
160
+ __send__("#{name}=", value)
161
+ end unless method_defined?(:[]=)
162
+
163
+ def |(other)
164
+ self.class[other.to_hash.merge(to_hash)]
165
+ end
166
+
167
+ def as_json(*)
168
+ { JSON.create_id => self.class.name }.merge to_hash
169
+ end
170
+
171
+ def to_json(*a)
172
+ as_json.to_json(*a)
173
+ end
174
+ end
175
+
176
+ end # JSON
data/lib/oj/mimic.rb CHANGED
@@ -1,4 +1,5 @@
1
1
 
2
+ require 'bigdecimal'
2
3
  begin
3
4
  require 'ostruct'
4
5
  rescue Exception
@@ -7,6 +8,52 @@ end
7
8
 
8
9
  module Oj
9
10
 
11
+ ##
12
+ # Custom mode can be used to emulate the compat mode with some minor
13
+ # differences. These are the options that setup the custom mode to be like
14
+ # the compat mode.
15
+ CUSTOM_MIMIC_JSON_OPTIONS = {
16
+ allow_gc: true,
17
+ allow_invalid_unicode: false,
18
+ allow_nan: false,
19
+ array_class: nil,
20
+ array_nl: nil,
21
+ auto_define: false,
22
+ bigdecimal_as_decimal: false,
23
+ bigdecimal_load: :auto,
24
+ circular: false,
25
+ class_cache: false,
26
+ cache_keys: true,
27
+ cache_str: 5,
28
+ create_additions: false,
29
+ create_id: "json_class",
30
+ empty_string: false,
31
+ escape_mode: :unicode_xss,
32
+ float_precision: 0,
33
+ hash_class: nil,
34
+ ignore: nil,
35
+ ignore_under: false,
36
+ indent: 0,
37
+ integer_range: nil,
38
+ mode: :custom,
39
+ nan: :raise,
40
+ nilnil: false,
41
+ object_nl: nil,
42
+ omit_nil: false,
43
+ quirks_mode: true,
44
+ safe: false,
45
+ second_precision: 3,
46
+ space: nil,
47
+ space_before: nil,
48
+ symbol_keys: false,
49
+ time_format: :ruby,
50
+ trace: false,
51
+ use_as_json: false,
52
+ use_raw_json: false,
53
+ use_to_hash: false,
54
+ use_to_json: true,
55
+ }
56
+
10
57
  # A bit hack-ish but does the trick. The JSON.dump_default_options is a Hash
11
58
  # but in mimic we use a C struct to store defaults. This class creates a view
12
59
  # onto that struct.
@@ -29,20 +76,25 @@ module Oj
29
76
  end
30
77
  end
31
78
 
79
+ # Loads mimic-ed JSON paths. Used by Oj.mimic_JSON().
80
+ # @param mimic_paths [Array] additional paths to add to the Ruby loaded features.
32
81
  def self.mimic_loaded(mimic_paths=[])
33
82
  $LOAD_PATH.each do |d|
34
83
  next unless File.exist?(d)
35
84
 
36
85
  jfile = File.join(d, 'json.rb')
37
86
  $LOADED_FEATURES << jfile unless $LOADED_FEATURES.include?(jfile) if File.exist?(jfile)
38
-
87
+
39
88
  Dir.glob(File.join(d, 'json', '**', '*.rb')).each do |file|
40
- $LOADED_FEATURES << file unless $LOADED_FEATURES.include?(file)
89
+ # allow json/add/xxx to be loaded. User can override with Oj.add_to_json(xxx).
90
+ $LOADED_FEATURES << file unless $LOADED_FEATURES.include?(file) unless file.include?('add')
41
91
  end
42
92
  end
43
93
  mimic_paths.each { |p| $LOADED_FEATURES << p }
44
94
  $LOADED_FEATURES << 'json' unless $LOADED_FEATURES.include?('json')
45
95
 
96
+ require 'oj/json'
97
+
46
98
  if Object.const_defined?('OpenStruct')
47
99
  OpenStruct.class_eval do
48
100
  # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
@@ -54,8 +106,87 @@ module Oj
54
106
  end
55
107
  end
56
108
  def self.json_create(h)
57
- new(h['t'])
109
+ new(h['t'] || h[:t])
110
+ end
111
+ end
112
+ end
113
+
114
+ BigDecimal.class_eval do
115
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
116
+ unless defined?(self.as_json)
117
+ def as_json(*)
118
+ {JSON.create_id => 'BigDecimal', 'b' => _dump }
119
+ end
120
+ end
121
+ def self.json_create(h)
122
+ BigDecimal._load(h['b'])
123
+ end
124
+ end
125
+
126
+ Complex.class_eval do
127
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
128
+ unless defined?(self.as_json)
129
+ def as_json(*)
130
+ {JSON.create_id => 'Complex', 'r' => real, 'i' => imag }
131
+ end
132
+ end
133
+ def self.json_create(h)
134
+ Complex(h['r'], h['i'])
135
+ end
136
+ end
137
+
138
+ DateTime.class_eval do
139
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
140
+ unless defined?(self.as_json)
141
+ def as_json(*)
142
+ { JSON.create_id => 'DateTime',
143
+ 'y' => year,
144
+ 'm' => month,
145
+ 'd' => day,
146
+ 'H' => hour,
147
+ 'M' => min,
148
+ 'S' => sec,
149
+ 'of' => offset.to_s,
150
+ 'sg' => start }
151
+ end
152
+ end
153
+ def self.json_create(h)
154
+ # offset is a rational as a string
155
+ as, bs = h['of'].split('/')
156
+ a = as.to_i
157
+ b = bs.to_i
158
+ if 0 == b
159
+ off = a
160
+ else
161
+ off = Rational(a, b)
58
162
  end
163
+ civil(h['y'], h['m'], h['d'], h['H'], h['M'], h['S'], off, h['sg'])
164
+ end
165
+ end
166
+
167
+ Date.class_eval do
168
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
169
+ unless defined?(self.as_json)
170
+ def as_json(*)
171
+ { JSON.create_id => 'Date', 'y' => year, 'm' => month, 'd' => day, 'sg' => start }
172
+ end
173
+ end
174
+ def self.json_create(h)
175
+ civil(h['y'], h['m'], h['d'], h['sg'])
176
+ end
177
+ end
178
+
179
+ Exception.class_eval do
180
+ # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
181
+ unless defined?(self.as_json)
182
+ def as_json(*)
183
+ {JSON.create_id => self.class.name, 'm' => message, 'b' => backtrace }
184
+ end
185
+ end
186
+ def self.json_create(h)
187
+ e = new(h['m'])
188
+ e.set_backtrace(h['b'])
189
+ e
59
190
  end
60
191
  end
61
192
 
@@ -67,7 +198,7 @@ module Oj
67
198
  end
68
199
  end
69
200
  def self.json_create(h)
70
- new(h['a'])
201
+ new(*h['a'])
71
202
  end
72
203
  end
73
204
 
@@ -105,7 +236,7 @@ module Oj
105
236
  end
106
237
  end
107
238
  def self.json_create(h)
108
- new(h['v'])
239
+ new(*h['v'])
109
240
  end
110
241
  end
111
242
 
@@ -125,7 +256,6 @@ module Oj
125
256
  # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
126
257
  unless defined?(self.as_json)
127
258
  def as_json(*)
128
- {JSON.create_id => 'Symbol', 's' => to_s }
129
259
  nsecs = [ tv_usec * 1000 ]
130
260
  nsecs << tv_nsec if respond_to?(:tv_nsec)
131
261
  nsecs = nsecs.max
@@ -144,19 +274,28 @@ module Oj
144
274
  end
145
275
  end
146
276
 
147
- JSON.module_eval do
148
- def self.dump_default_options
149
- Oj::MimicDumpOption.new
150
- end
151
-
152
- def self.dump_default_options=(h)
153
- m = Oj::MimicDumpOption.new
154
- h.each do |k,v|
155
- m[k] = v
156
- end
157
- end
158
- end
159
-
160
277
  end # self.mimic_loaded
161
278
 
162
279
  end # Oj
280
+
281
+ # More monkey patches.
282
+ class String
283
+ def to_json_raw_object
284
+ {
285
+ JSON.create_id => self.class.name,
286
+ 'raw' => self.bytes
287
+ }
288
+ end
289
+ def to_json_raw(*)
290
+ to_json_raw_object().to_json()
291
+ end
292
+ def self.json_create(obj)
293
+ s = ''
294
+ s.encode!(Encoding::ASCII_8BIT) if s.respond_to?(:encode!)
295
+ raw = obj['raw']
296
+ if raw.is_a? Array
297
+ raw.each { |v| s << v }
298
+ end
299
+ s
300
+ end
301
+ end
data/lib/oj/state.rb ADDED
@@ -0,0 +1,132 @@
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
+ end
120
+ if @attrs.has_key?(m.to_sym)
121
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 0 with #{m}) to method #{m}") unless args.nil? or args.empty?
122
+ return @attrs[m.to_sym]
123
+ end
124
+ return @attrs.send(m, *args, &block)
125
+ end
126
+
127
+ end # State
128
+ end # defined check
129
+ end # Generator
130
+ end # Ext
131
+
132
+ end # JSON
data/lib/oj/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
- # Current version of the module.
4
- VERSION = '2.18.3'
3
+ # Current version of the module.
4
+ VERSION = '3.13.14'
5
5
  end
data/lib/oj.rb CHANGED
@@ -1,35 +1,5 @@
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.
24
- module Oj
25
- end
26
1
 
27
- begin
28
- # This require exists to get around Rubinius failing to load bigdecimal from
29
- # the C extension.
30
- require 'bigdecimal'
31
- rescue Exception
32
- # ignore
2
+ module Oj
33
3
  end
34
4
 
35
5
  require 'oj/version'
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 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}.
data/pages/Custom.md ADDED
@@ -0,0 +1,23 @@
1
+ # Custom mode
2
+
3
+ The `:custom` mode is the most configurable mode and honors almost all
4
+ options. It provides the most flexibility although it can not be configured to
5
+ be exactly like any of the other modes. Each mode has some special aspect that
6
+ makes it unique. For example, the `:object` mode has it's own unique format
7
+ for object dumping and loading. The `:compat` mode mimic the json gem
8
+ including methods called for encoding and inconsistencies between
9
+ `JSON.dump()`, `JSON.generate()`, and `JSON()`.
10
+
11
+ The `:custom` mode is the default mode. It can be configured either by passing
12
+ options to the `Oj.dump()` and `Oj.load()` methods or by modifying the default
13
+ options.
14
+
15
+ The ability to create objects from JSON object elements is supported and
16
+ considers the `:create_additions` option. Special treatment is given to the
17
+ `:create_id` though. If the `:create_id` is set to `"^o"` then the Oj internal
18
+ encoding and decoding is used. These are more efficient than calling out to a
19
+ `to_json` method or `create_json` method on the classes. Those method do not
20
+ have to exist for the `"^o"` behavior to be utilized. Any other `:create_id`
21
+ value behaves similar to the json gem by calling `to_json` and `create_json`
22
+ as appropriate.
23
+