oj 3.7.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +96 -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 +1188 -0
  13. data/ext/oj/dump.c +1232 -0
  14. data/ext/oj/dump.h +94 -0
  15. data/ext/oj/dump_compat.c +973 -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 +873 -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 +1694 -0
  32. data/ext/oj/oj.h +381 -0
  33. data/ext/oj/parse.c +1085 -0
  34. data/ext/oj/parse.h +111 -0
  35. data/ext/oj/rails.c +1485 -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 +512 -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 +154 -0
  73. data/pages/Options.md +266 -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/big.rb +15 -0
  90. data/test/files.rb +29 -0
  91. data/test/foo.rb +33 -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/mem.rb +35 -0
  113. data/test/perf.rb +107 -0
  114. data/test/perf_compat.rb +130 -0
  115. data/test/perf_fast.rb +164 -0
  116. data/test/perf_file.rb +64 -0
  117. data/test/perf_object.rb +138 -0
  118. data/test/perf_saj.rb +109 -0
  119. data/test/perf_scp.rb +151 -0
  120. data/test/perf_simple.rb +287 -0
  121. data/test/perf_strict.rb +145 -0
  122. data/test/perf_wab.rb +131 -0
  123. data/test/sample.rb +54 -0
  124. data/test/sample/change.rb +14 -0
  125. data/test/sample/dir.rb +19 -0
  126. data/test/sample/doc.rb +36 -0
  127. data/test/sample/file.rb +48 -0
  128. data/test/sample/group.rb +16 -0
  129. data/test/sample/hasprops.rb +16 -0
  130. data/test/sample/layer.rb +12 -0
  131. data/test/sample/line.rb +20 -0
  132. data/test/sample/oval.rb +10 -0
  133. data/test/sample/rect.rb +10 -0
  134. data/test/sample/shape.rb +35 -0
  135. data/test/sample/text.rb +20 -0
  136. data/test/sample_json.rb +37 -0
  137. data/test/test_compat.rb +509 -0
  138. data/test/test_custom.rb +406 -0
  139. data/test/test_debian.rb +53 -0
  140. data/test/test_fast.rb +470 -0
  141. data/test/test_file.rb +239 -0
  142. data/test/test_gc.rb +49 -0
  143. data/test/test_hash.rb +29 -0
  144. data/test/test_integer_range.rb +73 -0
  145. data/test/test_null.rb +376 -0
  146. data/test/test_object.rb +1018 -0
  147. data/test/test_saj.rb +186 -0
  148. data/test/test_scp.rb +433 -0
  149. data/test/test_strict.rb +410 -0
  150. data/test/test_various.rb +739 -0
  151. data/test/test_wab.rb +307 -0
  152. data/test/test_writer.rb +380 -0
  153. data/test/tests.rb +24 -0
  154. data/test/tests_mimic.rb +14 -0
  155. data/test/tests_mimic_addition.rb +7 -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
+ Object.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