oj 3.10.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +104 -0
- data/ext/oj/buf.h +103 -0
- data/ext/oj/cache8.c +107 -0
- data/ext/oj/cache8.h +48 -0
- data/ext/oj/circarray.c +68 -0
- data/ext/oj/circarray.h +23 -0
- data/ext/oj/code.c +235 -0
- data/ext/oj/code.h +42 -0
- data/ext/oj/compat.c +299 -0
- data/ext/oj/custom.c +1218 -0
- data/ext/oj/dump.c +1249 -0
- data/ext/oj/dump.h +96 -0
- data/ext/oj/dump_compat.c +975 -0
- data/ext/oj/dump_leaf.c +252 -0
- data/ext/oj/dump_object.c +844 -0
- data/ext/oj/dump_strict.c +434 -0
- data/ext/oj/encode.h +45 -0
- data/ext/oj/err.c +57 -0
- data/ext/oj/err.h +70 -0
- data/ext/oj/extconf.rb +53 -0
- data/ext/oj/fast.c +1771 -0
- data/ext/oj/hash.c +163 -0
- data/ext/oj/hash.h +46 -0
- data/ext/oj/hash_test.c +512 -0
- data/ext/oj/mimic_json.c +890 -0
- data/ext/oj/object.c +775 -0
- data/ext/oj/odd.c +231 -0
- data/ext/oj/odd.h +44 -0
- data/ext/oj/oj.c +1723 -0
- data/ext/oj/oj.h +387 -0
- data/ext/oj/parse.c +1134 -0
- data/ext/oj/parse.h +112 -0
- data/ext/oj/rails.c +1528 -0
- data/ext/oj/rails.h +21 -0
- data/ext/oj/reader.c +231 -0
- data/ext/oj/reader.h +151 -0
- data/ext/oj/resolve.c +102 -0
- data/ext/oj/resolve.h +14 -0
- data/ext/oj/rxclass.c +147 -0
- data/ext/oj/rxclass.h +27 -0
- data/ext/oj/saj.c +714 -0
- data/ext/oj/scp.c +224 -0
- data/ext/oj/sparse.c +924 -0
- data/ext/oj/stream_writer.c +363 -0
- data/ext/oj/strict.c +212 -0
- data/ext/oj/string_writer.c +534 -0
- data/ext/oj/trace.c +79 -0
- data/ext/oj/trace.h +28 -0
- data/ext/oj/util.c +136 -0
- data/ext/oj/util.h +19 -0
- data/ext/oj/val_stack.c +118 -0
- data/ext/oj/val_stack.h +185 -0
- data/ext/oj/wab.c +631 -0
- data/lib/oj.rb +21 -0
- data/lib/oj/active_support_helper.rb +41 -0
- data/lib/oj/bag.rb +88 -0
- data/lib/oj/easy_hash.rb +52 -0
- data/lib/oj/error.rb +22 -0
- data/lib/oj/json.rb +176 -0
- data/lib/oj/mimic.rb +267 -0
- data/lib/oj/saj.rb +66 -0
- data/lib/oj/schandler.rb +142 -0
- data/lib/oj/state.rb +131 -0
- data/lib/oj/version.rb +5 -0
- data/pages/Advanced.md +22 -0
- data/pages/Compatibility.md +25 -0
- data/pages/Custom.md +23 -0
- data/pages/Encoding.md +65 -0
- data/pages/JsonGem.md +79 -0
- data/pages/Modes.md +155 -0
- data/pages/Options.md +287 -0
- data/pages/Rails.md +155 -0
- data/pages/Security.md +20 -0
- data/pages/WAB.md +13 -0
- data/test/_test_active.rb +76 -0
- data/test/_test_active_mimic.rb +96 -0
- data/test/_test_mimic_rails.rb +126 -0
- data/test/activerecord/result_test.rb +27 -0
- data/test/activesupport4/decoding_test.rb +108 -0
- data/test/activesupport4/encoding_test.rb +531 -0
- data/test/activesupport4/test_helper.rb +41 -0
- data/test/activesupport5/abstract_unit.rb +45 -0
- data/test/activesupport5/decoding_test.rb +133 -0
- data/test/activesupport5/encoding_test.rb +500 -0
- data/test/activesupport5/encoding_test_cases.rb +98 -0
- data/test/activesupport5/test_helper.rb +72 -0
- data/test/activesupport5/time_zone_test_helpers.rb +39 -0
- data/test/activesupport6/abstract_unit.rb +44 -0
- data/test/activesupport6/decoding_test.rb +133 -0
- data/test/activesupport6/encoding_test.rb +507 -0
- data/test/activesupport6/encoding_test_cases.rb +98 -0
- data/test/activesupport6/test_common.rb +17 -0
- data/test/activesupport6/test_helper.rb +163 -0
- data/test/activesupport6/time_zone_test_helpers.rb +39 -0
- data/test/bar.rb +35 -0
- data/test/baz.rb +16 -0
- data/test/files.rb +29 -0
- data/test/foo.rb +52 -0
- data/test/helper.rb +26 -0
- data/test/isolated/shared.rb +308 -0
- data/test/isolated/test_mimic_after.rb +13 -0
- data/test/isolated/test_mimic_alone.rb +12 -0
- data/test/isolated/test_mimic_as_json.rb +45 -0
- data/test/isolated/test_mimic_before.rb +13 -0
- data/test/isolated/test_mimic_define.rb +28 -0
- data/test/isolated/test_mimic_rails_after.rb +22 -0
- data/test/isolated/test_mimic_rails_before.rb +21 -0
- data/test/isolated/test_mimic_redefine.rb +15 -0
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +148 -0
- data/test/json_gem/json_encoding_test.rb +107 -0
- data/test/json_gem/json_ext_parser_test.rb +20 -0
- data/test/json_gem/json_fixtures_test.rb +35 -0
- data/test/json_gem/json_generator_test.rb +383 -0
- data/test/json_gem/json_generic_object_test.rb +90 -0
- data/test/json_gem/json_parser_test.rb +470 -0
- data/test/json_gem/json_string_matching_test.rb +42 -0
- data/test/json_gem/test_helper.rb +18 -0
- data/test/perf.rb +107 -0
- data/test/perf_compat.rb +130 -0
- data/test/perf_fast.rb +164 -0
- data/test/perf_file.rb +64 -0
- data/test/perf_object.rb +138 -0
- data/test/perf_saj.rb +109 -0
- data/test/perf_scp.rb +151 -0
- data/test/perf_simple.rb +287 -0
- data/test/perf_strict.rb +145 -0
- data/test/perf_wab.rb +131 -0
- data/test/prec.rb +23 -0
- data/test/sample.rb +54 -0
- data/test/sample/change.rb +14 -0
- data/test/sample/dir.rb +19 -0
- data/test/sample/doc.rb +36 -0
- data/test/sample/file.rb +48 -0
- data/test/sample/group.rb +16 -0
- data/test/sample/hasprops.rb +16 -0
- data/test/sample/layer.rb +12 -0
- data/test/sample/line.rb +20 -0
- data/test/sample/oval.rb +10 -0
- data/test/sample/rect.rb +10 -0
- data/test/sample/shape.rb +35 -0
- data/test/sample/text.rb +20 -0
- data/test/sample_json.rb +37 -0
- data/test/test_compat.rb +502 -0
- data/test/test_custom.rb +527 -0
- data/test/test_debian.rb +53 -0
- data/test/test_fast.rb +470 -0
- data/test/test_file.rb +239 -0
- data/test/test_gc.rb +49 -0
- data/test/test_hash.rb +29 -0
- data/test/test_integer_range.rb +72 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +1027 -0
- data/test/test_rails.rb +26 -0
- data/test/test_saj.rb +186 -0
- data/test/test_scp.rb +433 -0
- data/test/test_strict.rb +433 -0
- data/test/test_various.rb +719 -0
- data/test/test_wab.rb +307 -0
- data/test/test_writer.rb +380 -0
- data/test/tests.rb +25 -0
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- data/test/zoo.rb +13 -0
- metadata +381 -0
data/lib/oj.rb
ADDED
@@ -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
|
data/lib/oj/bag.rb
ADDED
@@ -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
|
data/lib/oj/easy_hash.rb
ADDED
@@ -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
|
data/lib/oj/error.rb
ADDED
@@ -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
|
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
ADDED
@@ -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
|