oj 3.8.1

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 (156) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +104 -0
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +107 -0
  6. data/ext/oj/cache8.h +48 -0
  7. data/ext/oj/circarray.c +68 -0
  8. data/ext/oj/circarray.h +23 -0
  9. data/ext/oj/code.c +235 -0
  10. data/ext/oj/code.h +42 -0
  11. data/ext/oj/compat.c +299 -0
  12. data/ext/oj/custom.c +1191 -0
  13. data/ext/oj/dump.c +1252 -0
  14. data/ext/oj/dump.h +96 -0
  15. data/ext/oj/dump_compat.c +977 -0
  16. data/ext/oj/dump_leaf.c +252 -0
  17. data/ext/oj/dump_object.c +837 -0
  18. data/ext/oj/dump_strict.c +433 -0
  19. data/ext/oj/encode.h +45 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +47 -0
  23. data/ext/oj/fast.c +1771 -0
  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 +878 -0
  28. data/ext/oj/object.c +771 -0
  29. data/ext/oj/odd.c +231 -0
  30. data/ext/oj/odd.h +44 -0
  31. data/ext/oj/oj.c +1704 -0
  32. data/ext/oj/oj.h +385 -0
  33. data/ext/oj/parse.c +1086 -0
  34. data/ext/oj/parse.h +111 -0
  35. data/ext/oj/rails.c +1493 -0
  36. data/ext/oj/rails.h +21 -0
  37. data/ext/oj/reader.c +231 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +102 -0
  40. data/ext/oj/resolve.h +14 -0
  41. data/ext/oj/rxclass.c +147 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +714 -0
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +910 -0
  46. data/ext/oj/stream_writer.c +363 -0
  47. data/ext/oj/strict.c +212 -0
  48. data/ext/oj/string_writer.c +534 -0
  49. data/ext/oj/trace.c +79 -0
  50. data/ext/oj/trace.h +28 -0
  51. data/ext/oj/util.c +136 -0
  52. data/ext/oj/util.h +19 -0
  53. data/ext/oj/val_stack.c +118 -0
  54. data/ext/oj/val_stack.h +185 -0
  55. data/ext/oj/wab.c +631 -0
  56. data/lib/oj.rb +21 -0
  57. data/lib/oj/active_support_helper.rb +41 -0
  58. data/lib/oj/bag.rb +88 -0
  59. data/lib/oj/easy_hash.rb +52 -0
  60. data/lib/oj/error.rb +22 -0
  61. data/lib/oj/json.rb +176 -0
  62. data/lib/oj/mimic.rb +267 -0
  63. data/lib/oj/saj.rb +66 -0
  64. data/lib/oj/schandler.rb +142 -0
  65. data/lib/oj/state.rb +131 -0
  66. data/lib/oj/version.rb +5 -0
  67. data/pages/Advanced.md +22 -0
  68. data/pages/Compatibility.md +25 -0
  69. data/pages/Custom.md +23 -0
  70. data/pages/Encoding.md +65 -0
  71. data/pages/JsonGem.md +79 -0
  72. data/pages/Modes.md +155 -0
  73. data/pages/Options.md +283 -0
  74. data/pages/Rails.md +116 -0
  75. data/pages/Security.md +20 -0
  76. data/pages/WAB.md +13 -0
  77. data/test/_test_active.rb +76 -0
  78. data/test/_test_active_mimic.rb +96 -0
  79. data/test/_test_mimic_rails.rb +126 -0
  80. data/test/activerecord/result_test.rb +27 -0
  81. data/test/activesupport4/decoding_test.rb +108 -0
  82. data/test/activesupport4/encoding_test.rb +531 -0
  83. data/test/activesupport4/test_helper.rb +41 -0
  84. data/test/activesupport5/decoding_test.rb +125 -0
  85. data/test/activesupport5/encoding_test.rb +485 -0
  86. data/test/activesupport5/encoding_test_cases.rb +90 -0
  87. data/test/activesupport5/test_helper.rb +50 -0
  88. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  89. data/test/bar.rb +25 -0
  90. data/test/files.rb +29 -0
  91. data/test/foo.rb +167 -0
  92. data/test/helper.rb +26 -0
  93. data/test/isolated/shared.rb +308 -0
  94. data/test/isolated/test_mimic_after.rb +13 -0
  95. data/test/isolated/test_mimic_alone.rb +12 -0
  96. data/test/isolated/test_mimic_as_json.rb +45 -0
  97. data/test/isolated/test_mimic_before.rb +13 -0
  98. data/test/isolated/test_mimic_define.rb +28 -0
  99. data/test/isolated/test_mimic_rails_after.rb +22 -0
  100. data/test/isolated/test_mimic_rails_before.rb +21 -0
  101. data/test/isolated/test_mimic_redefine.rb +15 -0
  102. data/test/json_gem/json_addition_test.rb +216 -0
  103. data/test/json_gem/json_common_interface_test.rb +148 -0
  104. data/test/json_gem/json_encoding_test.rb +107 -0
  105. data/test/json_gem/json_ext_parser_test.rb +20 -0
  106. data/test/json_gem/json_fixtures_test.rb +35 -0
  107. data/test/json_gem/json_generator_test.rb +383 -0
  108. data/test/json_gem/json_generic_object_test.rb +90 -0
  109. data/test/json_gem/json_parser_test.rb +470 -0
  110. data/test/json_gem/json_string_matching_test.rb +42 -0
  111. data/test/json_gem/test_helper.rb +18 -0
  112. data/test/perf.rb +107 -0
  113. data/test/perf_compat.rb +130 -0
  114. data/test/perf_fast.rb +164 -0
  115. data/test/perf_file.rb +64 -0
  116. data/test/perf_object.rb +138 -0
  117. data/test/perf_saj.rb +109 -0
  118. data/test/perf_scp.rb +151 -0
  119. data/test/perf_simple.rb +287 -0
  120. data/test/perf_strict.rb +145 -0
  121. data/test/perf_wab.rb +131 -0
  122. data/test/sample.rb +54 -0
  123. data/test/sample/change.rb +14 -0
  124. data/test/sample/dir.rb +19 -0
  125. data/test/sample/doc.rb +36 -0
  126. data/test/sample/file.rb +48 -0
  127. data/test/sample/group.rb +16 -0
  128. data/test/sample/hasprops.rb +16 -0
  129. data/test/sample/layer.rb +12 -0
  130. data/test/sample/line.rb +20 -0
  131. data/test/sample/oval.rb +10 -0
  132. data/test/sample/rect.rb +10 -0
  133. data/test/sample/shape.rb +35 -0
  134. data/test/sample/text.rb +20 -0
  135. data/test/sample_json.rb +37 -0
  136. data/test/test_compat.rb +509 -0
  137. data/test/test_custom.rb +503 -0
  138. data/test/test_debian.rb +53 -0
  139. data/test/test_fast.rb +470 -0
  140. data/test/test_file.rb +239 -0
  141. data/test/test_gc.rb +49 -0
  142. data/test/test_hash.rb +29 -0
  143. data/test/test_integer_range.rb +73 -0
  144. data/test/test_null.rb +376 -0
  145. data/test/test_object.rb +1018 -0
  146. data/test/test_saj.rb +186 -0
  147. data/test/test_scp.rb +433 -0
  148. data/test/test_strict.rb +410 -0
  149. data/test/test_various.rb +741 -0
  150. data/test/test_wab.rb +307 -0
  151. data/test/test_writer.rb +380 -0
  152. data/test/tests.rb +24 -0
  153. data/test/tests_mimic.rb +14 -0
  154. data/test/tests_mimic_addition.rb +7 -0
  155. data/test/zoo.rb +13 -0
  156. metadata +359 -0
@@ -0,0 +1,21 @@
1
+
2
+ module Oj
3
+ end
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
+
13
+ require 'oj/version'
14
+ require 'oj/bag'
15
+ require 'oj/easy_hash'
16
+ require 'oj/error'
17
+ require 'oj/mimic'
18
+ require 'oj/saj'
19
+ require 'oj/schandler'
20
+
21
+ require 'oj/oj' # C extension
@@ -0,0 +1,41 @@
1
+
2
+ require 'active_support/time'
3
+
4
+ module Oj
5
+
6
+ # Exists only to handle the ActiveSupport::TimeWithZone.
7
+ class ActiveSupportHelper
8
+
9
+ def self.createTimeWithZone(utc, zone)
10
+ ActiveSupport::TimeWithZone.new(utc - utc.gmt_offset, ActiveSupport::TimeZone[zone])
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ Oj.register_odd(ActiveSupport::TimeWithZone, Oj::ActiveSupportHelper, :createTimeWithZone, :utc, 'time_zone.name')
17
+
18
+ # This is a hack to work around an oddness with DateTime and the ActiveSupport
19
+ # that causes a hang when some methods are called from C. Hour, min(ute),
20
+ # sec(ond) and other methods are special but they can be called from C until
21
+ # activesupport/time is required. After that they can not be even though
22
+ # resond_to? returns true. By defining methods to call super the problem goes
23
+ # away. There is obviously some magic going on under the covers that I don't
24
+ # understand.
25
+ class DateTime
26
+ def hour()
27
+ super
28
+ end
29
+ def min()
30
+ super
31
+ end
32
+ def sec()
33
+ super
34
+ end
35
+ def sec_fraction()
36
+ super
37
+ end
38
+ def offset()
39
+ super
40
+ end
41
+ end
@@ -0,0 +1,88 @@
1
+
2
+ module Oj
3
+
4
+ # A generic class that is used only for storing attributes. It is the base
5
+ # Class for auto-generated classes in the storage system. Instance variables
6
+ # are added using the instance_variable_set() method. All instance variables
7
+ # can be accessed using the variable name (without the @ prefix). No setters
8
+ # are provided as the Class is intended for reading only.
9
+ class Bag
10
+
11
+ # The initializer can take multiple arguments in the form of key values
12
+ # where the key is the variable name and the value is the variable
13
+ # value. This is intended for testing purposes only.
14
+ # @example Oj::Bag.new(:@x => 42, :@y => 57)
15
+ # @param [Hash] args instance variable symbols and their values
16
+ def initialize(args = {})
17
+ args.each do |k,v|
18
+ self.instance_variable_set(k, v)
19
+ end
20
+ end
21
+
22
+ # Replaces the Object.respond_to?() method.
23
+ # @param [Symbol] m method symbol
24
+ # @return [Boolean] true for any method that matches an instance
25
+ # variable reader, otherwise false.
26
+ def respond_to?(m)
27
+ return true if super
28
+ instance_variables.include?(:"@#{m}")
29
+ end
30
+
31
+ # Handles requests for variable values. Others cause an Exception to be
32
+ # raised.
33
+ # @param [Symbol] m method symbol
34
+ # @return [Boolean] the value of the specified instance variable.
35
+ # @raise [ArgumentError] if an argument is given. Zero arguments expected.
36
+ # @raise [NoMethodError] if the instance variable is not defined.
37
+ def method_missing(m, *args, &block)
38
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 0) to method #{m}") unless args.nil? or args.empty?
39
+ at_m = :"@#{m}"
40
+ raise NoMethodError.new("undefined method #{m}", m) unless instance_variable_defined?(at_m)
41
+ instance_variable_get(at_m)
42
+ end
43
+
44
+ # Replaces eql?() with something more reasonable for this Class.
45
+ # @param [Object] other Object to compare self to
46
+ # @return [Boolean] true if each variable and value are the same, otherwise false.
47
+ def eql?(other)
48
+ return false if (other.nil? or self.class != other.class)
49
+ ova = other.instance_variables
50
+ iv = instance_variables
51
+ return false if ova.size != iv.size
52
+ iv.all? { |vid| instance_variable_get(vid) != other.instance_variable_get(vid) }
53
+ end
54
+ alias == eql?
55
+
56
+ # Define a new class based on the Oj::Bag class. This is used internally in
57
+ # the Oj module and is available to service wrappers that receive XML
58
+ # requests that include Objects of Classes not defined in the storage
59
+ # process.
60
+ # @param [String] classname Class name or symbol that includes Module names.
61
+ # @return [Object] an instance of the specified Class.
62
+ # @raise [NameError] if the classname is invalid.
63
+ def self.define_class(classname)
64
+ classname = classname.to_s unless classname.is_a?(String)
65
+ tokens = classname.split('::').map(&:to_sym)
66
+ raise NameError.new("Invalid classname '#{classname}") if tokens.empty?
67
+ m = Object
68
+ tokens[0..-2].each do |sym|
69
+ if m.const_defined?(sym)
70
+ m = m.const_get(sym)
71
+ else
72
+ c = Module.new
73
+ m.const_set(sym, c)
74
+ m = c
75
+ end
76
+ end
77
+ sym = tokens[-1]
78
+ if m.const_defined?(sym)
79
+ c = m.const_get(sym)
80
+ else
81
+ c = Class.new(Oj::Bag)
82
+ m.const_set(sym, c)
83
+ end
84
+ c
85
+ end
86
+
87
+ end # Bag
88
+ end # Oj
@@ -0,0 +1,52 @@
1
+
2
+ module Oj
3
+
4
+ # A Hash subclass that normalizes the hash keys to allow lookup by the
5
+ # key.to_s or key.to_sym. It also supports looking up hash values by methods
6
+ # that match the keys.
7
+ class EasyHash < Hash
8
+
9
+ # Initializes the instance to an empty Hash.
10
+ def initialize()
11
+ end
12
+
13
+ # Replaces the Object.respond_to?() method.
14
+ # @param [Symbol] m method symbol
15
+ # @return [Boolean] true for any method that matches an instance
16
+ # variable reader, otherwise false.
17
+ def respond_to?(m)
18
+ return true if super
19
+ return true if has_key?(key)
20
+ return true if has_key?(key.to_s)
21
+ has_key?(key.to_sym)
22
+ end
23
+
24
+ def [](key)
25
+ return fetch(key, nil) if has_key?(key)
26
+ return fetch(key.to_s, nil) if has_key?(key.to_s)
27
+ fetch(key.to_sym, nil)
28
+ end
29
+
30
+ # Handles requests for Hash values. Others cause an Exception to be raised.
31
+ # @param [Symbol|String] m method symbol
32
+ # @return [Boolean] the value of the specified instance variable.
33
+ # @raise [ArgumentError] if an argument is given. Zero arguments expected.
34
+ # @raise [NoMethodError] if the instance variable is not defined.
35
+ def method_missing(m, *args, &block)
36
+ if m.to_s.end_with?('=')
37
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 1 with #{m}) to method #{m}") if args.nil? or 1 != args.length
38
+ m = m[0..-2]
39
+ return store(m.to_s, args[0]) if has_key?(m.to_s)
40
+ return store(m.to_sym, args[0]) if has_key?(m.to_sym)
41
+ return store(m, args[0])
42
+ else
43
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 0 with #{m}) to method #{m}") unless args.nil? or args.empty?
44
+ return fetch(m, nil) if has_key?(m)
45
+ return fetch(m.to_s, nil) if has_key?(m.to_s)
46
+ return fetch(m.to_sym, nil) if has_key?(m.to_sym)
47
+ end
48
+ raise NoMethodError.new("undefined method #{m}", m)
49
+ end
50
+
51
+ end # EasyHash
52
+ end # Oj
@@ -0,0 +1,22 @@
1
+
2
+ module Oj
3
+
4
+ # Inherit Error class from StandardError.
5
+ Error = Class.new(StandardError)
6
+
7
+ # Following classes inherit from the Error class.
8
+ # -----------------------------------------------
9
+
10
+ # An Exception that is raised as a result of a parse error while parsing a JSON document.
11
+ ParseError = Class.new(Error)
12
+
13
+ # An Exception that is raised as a result of a path being too deep.
14
+ DepthError = Class.new(Error)
15
+
16
+ # An Exception that is raised if a file fails to load.
17
+ LoadError = Class.new(Error)
18
+
19
+ # An Exception that is raised if there is a conflict with mimicing JSON
20
+ MimicError = Class.new(Error)
21
+
22
+ end # Oj
@@ -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
@@ -0,0 +1,267 @@
1
+
2
+ require 'bigdecimal'
3
+ begin
4
+ require 'ostruct'
5
+ rescue Exception
6
+ # ignore
7
+ end
8
+
9
+ module Oj
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_paths [Array] additional paths to add to the Ruby loaded features.
35
+ def self.mimic_loaded(mimic_paths=[])
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
46
+ end
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
266
+ end
267
+ end