oj 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +17 -23
  3. data/README.md +74 -425
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +4 -0
  6. data/ext/oj/circarray.c +68 -0
  7. data/ext/oj/circarray.h +23 -0
  8. data/ext/oj/code.c +227 -0
  9. data/ext/oj/code.h +40 -0
  10. data/ext/oj/compat.c +243 -0
  11. data/ext/oj/custom.c +1097 -0
  12. data/ext/oj/dump.c +766 -1534
  13. data/ext/oj/dump.h +92 -0
  14. data/ext/oj/dump_compat.c +937 -0
  15. data/ext/oj/dump_leaf.c +254 -0
  16. data/ext/oj/dump_object.c +810 -0
  17. data/ext/oj/dump_rails.c +329 -0
  18. data/ext/oj/dump_strict.c +416 -0
  19. data/ext/oj/encode.h +51 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +17 -7
  23. data/ext/oj/fast.c +213 -180
  24. data/ext/oj/hash.c +163 -0
  25. data/ext/oj/hash.h +46 -0
  26. data/ext/oj/hash_test.c +512 -0
  27. data/ext/oj/mimic_json.c +817 -0
  28. data/ext/oj/mimic_rails.c +806 -0
  29. data/ext/oj/mimic_rails.h +17 -0
  30. data/ext/oj/object.c +752 -0
  31. data/ext/oj/odd.c +230 -0
  32. data/ext/oj/odd.h +44 -0
  33. data/ext/oj/oj.c +1288 -929
  34. data/ext/oj/oj.h +240 -69
  35. data/ext/oj/parse.c +1014 -0
  36. data/ext/oj/parse.h +92 -0
  37. data/ext/oj/reader.c +223 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +127 -0
  40. data/ext/oj/{cache.h → resolve.h} +6 -13
  41. data/ext/oj/rxclass.c +133 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +77 -175
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +911 -0
  46. data/ext/oj/stream_writer.c +301 -0
  47. data/ext/oj/strict.c +162 -0
  48. data/ext/oj/string_writer.c +480 -0
  49. data/ext/oj/val_stack.c +98 -0
  50. data/ext/oj/val_stack.h +188 -0
  51. data/lib/oj/active_support_helper.rb +41 -0
  52. data/lib/oj/bag.rb +6 -10
  53. data/lib/oj/easy_hash.rb +52 -0
  54. data/lib/oj/json.rb +172 -0
  55. data/lib/oj/mimic.rb +260 -5
  56. data/lib/oj/saj.rb +13 -10
  57. data/lib/oj/schandler.rb +142 -0
  58. data/lib/oj/state.rb +131 -0
  59. data/lib/oj/version.rb +1 -1
  60. data/lib/oj.rb +11 -23
  61. data/pages/Advanced.md +22 -0
  62. data/pages/Compatibility.md +25 -0
  63. data/pages/Custom.md +23 -0
  64. data/pages/Encoding.md +65 -0
  65. data/pages/JsonGem.md +79 -0
  66. data/pages/Modes.md +140 -0
  67. data/pages/Options.md +250 -0
  68. data/pages/Rails.md +60 -0
  69. data/pages/Security.md +20 -0
  70. data/test/_test_active.rb +76 -0
  71. data/test/_test_active_mimic.rb +96 -0
  72. data/test/_test_mimic_rails.rb +126 -0
  73. data/test/activesupport4/decoding_test.rb +105 -0
  74. data/test/activesupport4/encoding_test.rb +531 -0
  75. data/test/activesupport4/test_helper.rb +41 -0
  76. data/test/activesupport5/decoding_test.rb +125 -0
  77. data/test/activesupport5/encoding_test.rb +483 -0
  78. data/test/activesupport5/encoding_test_cases.rb +90 -0
  79. data/test/activesupport5/test_helper.rb +50 -0
  80. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  81. data/test/helper.rb +27 -0
  82. data/test/isolated/shared.rb +310 -0
  83. data/test/isolated/test_mimic_after.rb +13 -0
  84. data/test/isolated/test_mimic_alone.rb +12 -0
  85. data/test/isolated/test_mimic_as_json.rb +45 -0
  86. data/test/isolated/test_mimic_before.rb +13 -0
  87. data/test/isolated/test_mimic_define.rb +28 -0
  88. data/test/isolated/test_mimic_rails_after.rb +22 -0
  89. data/test/isolated/test_mimic_rails_before.rb +21 -0
  90. data/test/isolated/test_mimic_redefine.rb +15 -0
  91. data/test/json_gem/json_addition_test.rb +216 -0
  92. data/test/json_gem/json_common_interface_test.rb +143 -0
  93. data/test/json_gem/json_encoding_test.rb +109 -0
  94. data/test/json_gem/json_ext_parser_test.rb +20 -0
  95. data/test/json_gem/json_fixtures_test.rb +35 -0
  96. data/test/json_gem/json_generator_test.rb +383 -0
  97. data/test/json_gem/json_generic_object_test.rb +90 -0
  98. data/test/json_gem/json_parser_test.rb +470 -0
  99. data/test/json_gem/json_string_matching_test.rb +42 -0
  100. data/test/json_gem/test_helper.rb +18 -0
  101. data/test/perf_compat.rb +130 -0
  102. data/test/perf_fast.rb +9 -9
  103. data/test/perf_file.rb +64 -0
  104. data/test/{perf_obj.rb → perf_object.rb} +24 -10
  105. data/test/perf_scp.rb +151 -0
  106. data/test/perf_strict.rb +32 -113
  107. data/test/sample.rb +2 -3
  108. data/test/test_compat.rb +474 -0
  109. data/test/test_custom.rb +355 -0
  110. data/test/test_debian.rb +53 -0
  111. data/test/test_fast.rb +66 -16
  112. data/test/test_file.rb +237 -0
  113. data/test/test_gc.rb +49 -0
  114. data/test/test_hash.rb +29 -0
  115. data/test/test_null.rb +376 -0
  116. data/test/test_object.rb +1010 -0
  117. data/test/test_saj.rb +16 -16
  118. data/test/test_scp.rb +417 -0
  119. data/test/test_strict.rb +410 -0
  120. data/test/test_various.rb +815 -0
  121. data/test/test_writer.rb +308 -0
  122. data/test/tests.rb +9 -902
  123. data/test/tests_mimic.rb +14 -0
  124. data/test/tests_mimic_addition.rb +7 -0
  125. metadata +253 -38
  126. data/ext/oj/cache.c +0 -148
  127. data/ext/oj/foo.rb +0 -6
  128. data/ext/oj/load.c +0 -1049
  129. data/test/a.rb +0 -38
  130. data/test/perf1.rb +0 -64
  131. data/test/perf2.rb +0 -76
  132. data/test/perf_obj_old.rb +0 -213
  133. data/test/test_mimic.rb +0 -208
@@ -0,0 +1,188 @@
1
+ /* val_stack.h
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * - Redistributions of source code must retain the above copyright notice, this
9
+ * list of conditions and the following disclaimer.
10
+ *
11
+ * - Redistributions in binary form must reproduce the above copyright notice,
12
+ * this list of conditions and the following disclaimer in the documentation
13
+ * and/or other materials provided with the distribution.
14
+ *
15
+ * - Neither the name of Peter Ohler nor the names of its contributors may be
16
+ * used to endorse or promote products derived from this software without
17
+ * specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ #ifndef __OJ_VAL_STACK_H__
32
+ #define __OJ_VAL_STACK_H__
33
+
34
+ #include "ruby.h"
35
+ #include "odd.h"
36
+ #include <stdint.h>
37
+ #if USE_PTHREAD_MUTEX
38
+ #include <pthread.h>
39
+ #endif
40
+
41
+ #define STACK_INC 64
42
+
43
+ typedef enum {
44
+ NEXT_NONE = 0,
45
+ NEXT_ARRAY_NEW = 'a',
46
+ NEXT_ARRAY_ELEMENT = 'e',
47
+ NEXT_ARRAY_COMMA = ',',
48
+ NEXT_HASH_NEW = 'h',
49
+ NEXT_HASH_KEY = 'k',
50
+ NEXT_HASH_COLON = ':',
51
+ NEXT_HASH_VALUE = 'v',
52
+ NEXT_HASH_COMMA = 'n',
53
+ } ValNext;
54
+
55
+ typedef struct _Val {
56
+ volatile VALUE val;
57
+ const char *key;
58
+ char karray[32];
59
+ volatile VALUE key_val;
60
+ union {
61
+ struct {
62
+ const char *classname;
63
+ VALUE clas;
64
+ };
65
+ OddArgs odd_args;
66
+ };
67
+ uint16_t klen;
68
+ uint16_t clen;
69
+ char next; // ValNext
70
+ char k1; // first original character in the key
71
+ char kalloc;
72
+ } *Val;
73
+
74
+ typedef struct _ValStack {
75
+ struct _Val base[STACK_INC];
76
+ Val head; // current stack
77
+ Val end; // stack end
78
+ Val tail; // pointer to one past last element name on stack
79
+ #if USE_PTHREAD_MUTEX
80
+ pthread_mutex_t mutex;
81
+ #elif USE_RB_MUTEX
82
+ VALUE mutex;
83
+ #endif
84
+
85
+ } *ValStack;
86
+
87
+ extern VALUE oj_stack_init(ValStack stack);
88
+
89
+ inline static int
90
+ stack_empty(ValStack stack) {
91
+ return (stack->head == stack->tail);
92
+ }
93
+
94
+ inline static void
95
+ stack_cleanup(ValStack stack) {
96
+ if (stack->base != stack->head) {
97
+ xfree(stack->head);
98
+ stack->head = NULL;
99
+ }
100
+ }
101
+
102
+ inline static void
103
+ stack_push(ValStack stack, VALUE val, ValNext next) {
104
+ if (stack->end <= stack->tail) {
105
+ size_t len = stack->end - stack->head;
106
+ size_t toff = stack->tail - stack->head;
107
+ Val head = stack->head;
108
+
109
+ // A realloc can trigger a GC so make sure it happens outside the lock
110
+ // but lock before changing pointers.
111
+ if (stack->base == stack->head) {
112
+ head = ALLOC_N(struct _Val, len + STACK_INC);
113
+ memcpy(head, stack->base, sizeof(struct _Val) * len);
114
+ } else {
115
+ REALLOC_N(head, struct _Val, len + STACK_INC);
116
+ }
117
+ #if USE_PTHREAD_MUTEX
118
+ pthread_mutex_lock(&stack->mutex);
119
+ #elif USE_RB_MUTEX
120
+ rb_mutex_lock(stack->mutex);
121
+ #endif
122
+ stack->head = head;
123
+ stack->tail = stack->head + toff;
124
+ stack->end = stack->head + len + STACK_INC;
125
+ #if USE_PTHREAD_MUTEX
126
+ pthread_mutex_unlock(&stack->mutex);
127
+ #elif USE_RB_MUTEX
128
+ rb_mutex_unlock(stack->mutex);
129
+ #endif
130
+ }
131
+ stack->tail->val = val;
132
+ stack->tail->next = next;
133
+ stack->tail->classname = NULL;
134
+ stack->tail->clas = Qundef;
135
+ stack->tail->key = 0;
136
+ stack->tail->key_val = Qundef;
137
+ stack->tail->clen = 0;
138
+ stack->tail->klen = 0;
139
+ stack->tail->kalloc = 0;
140
+ stack->tail++;
141
+ }
142
+
143
+ inline static size_t
144
+ stack_size(ValStack stack) {
145
+ return stack->tail - stack->head;
146
+ }
147
+
148
+ inline static Val
149
+ stack_peek(ValStack stack) {
150
+ if (stack->head < stack->tail) {
151
+ return stack->tail - 1;
152
+ }
153
+ return 0;
154
+ }
155
+
156
+ inline static Val
157
+ stack_peek_up(ValStack stack) {
158
+ if (stack->head < stack->tail - 1) {
159
+ return stack->tail - 2;
160
+ }
161
+ return 0;
162
+ }
163
+
164
+ inline static Val
165
+ stack_prev(ValStack stack) {
166
+ return stack->tail;
167
+ }
168
+
169
+ inline static VALUE
170
+ stack_head_val(ValStack stack) {
171
+ if (Qundef != stack->head->val) {
172
+ return stack->head->val;
173
+ }
174
+ return Qnil;
175
+ }
176
+
177
+ inline static Val
178
+ stack_pop(ValStack stack) {
179
+ if (stack->head < stack->tail) {
180
+ stack->tail--;
181
+ return stack->tail;
182
+ }
183
+ return 0;
184
+ }
185
+
186
+ extern const char* oj_stack_next_string(ValNext n);
187
+
188
+ #endif /* __OJ_VAL_STACK_H__ */
@@ -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 CHANGED
@@ -13,7 +13,7 @@ module Oj
13
13
  # value. This is intended for testing purposes only.
14
14
  # @example Oj::Bag.new(:@x => 42, :@y => 57)
15
15
  # @param [Hash] args instance variable symbols and their values
16
- def initialize(args={ })
16
+ def initialize(args = {})
17
17
  args.each do |k,v|
18
18
  self.instance_variable_set(k, v)
19
19
  end
@@ -25,8 +25,7 @@ module Oj
25
25
  # variable reader, otherwise false.
26
26
  def respond_to?(m)
27
27
  return true if super
28
- at_m = ('@' + m.to_s).to_sym
29
- instance_variables.include?(at_m)
28
+ instance_variables.include?(:"@#{m}")
30
29
  end
31
30
 
32
31
  # Handles requests for variable values. Others cause an Exception to be
@@ -37,7 +36,7 @@ module Oj
37
36
  # @raise [NoMethodError] if the instance variable is not defined.
38
37
  def method_missing(m, *args, &block)
39
38
  raise ArgumentError.new("wrong number of arguments (#{args.size} for 0) to method #{m}") unless args.nil? or args.empty?
40
- at_m = ('@' + m.to_s).to_sym
39
+ at_m = :"@#{m}"
41
40
  raise NoMethodError.new("undefined method #{m}", m) unless instance_variable_defined?(at_m)
42
41
  instance_variable_get(at_m)
43
42
  end
@@ -50,13 +49,10 @@ module Oj
50
49
  ova = other.instance_variables
51
50
  iv = instance_variables
52
51
  return false if ova.size != iv.size
53
- iv.each do |vid|
54
- return false if instance_variable_get(vid) != other.instance_variable_get(vid)
55
- end
56
- true
52
+ iv.all? { |vid| instance_variable_get(vid) != other.instance_variable_get(vid) }
57
53
  end
58
54
  alias == eql?
59
-
55
+
60
56
  # Define a new class based on the Oj::Bag class. This is used internally in
61
57
  # the Oj module and is available to service wrappers that receive XML
62
58
  # requests that include Objects of Classes not defined in the storage
@@ -66,7 +62,7 @@ module Oj
66
62
  # @raise [NameError] if the classname is invalid.
67
63
  def self.define_class(classname)
68
64
  classname = classname.to_s unless classname.is_a?(String)
69
- tokens = classname.split('::').map { |n| n.to_sym }
65
+ tokens = classname.split('::').map(&:to_sym)
70
66
  raise NameError.new("Invalid classname '#{classname}") if tokens.empty?
71
67
  m = Object
72
68
  tokens[0..-2].each do |sym|
@@ -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/json.rb ADDED
@@ -0,0 +1,172 @@
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
96
+
97
+ Parser = ::JSON::Ext::Parser
98
+ self.parser = ::JSON::Ext::Parser
99
+ self.generator = ::JSON::Ext::Generator
100
+
101
+ # Taken directly from the json gem. Shamelessly copied. It is similar in
102
+ # some ways to the Oj::Bag class or the Oj::EasyHash class.
103
+ class GenericObject < OpenStruct
104
+ class << self
105
+ alias [] new
106
+
107
+ def json_creatable?
108
+ @json_creatable
109
+ end
110
+
111
+ attr_writer :json_creatable
112
+
113
+ def json_create(data)
114
+ data = data.dup
115
+ data.delete JSON.create_id
116
+ self[data]
117
+ end
118
+
119
+ def from_hash(object)
120
+ case
121
+ when object.respond_to?(:to_hash)
122
+ result = new
123
+ object.to_hash.each do |key, value|
124
+ result[key] = from_hash(value)
125
+ end
126
+ result
127
+ when object.respond_to?(:to_ary)
128
+ object.to_ary.map { |a| from_hash(a) }
129
+ else
130
+ object
131
+ end
132
+ end
133
+
134
+ def load(source, proc = nil, opts = {})
135
+ result = ::JSON.load(source, proc, opts.merge(:object_class => self))
136
+ result.nil? ? new : result
137
+ end
138
+
139
+ def dump(obj, *args)
140
+ ::JSON.dump(obj, *args)
141
+ end
142
+
143
+ end # self
144
+
145
+ self.json_creatable = false
146
+
147
+ def to_hash
148
+ table
149
+ end
150
+
151
+ def [](name)
152
+ __send__(name)
153
+ end unless method_defined?(:[])
154
+
155
+ def []=(name, value)
156
+ __send__("#{name}=", value)
157
+ end unless method_defined?(:[]=)
158
+
159
+ def |(other)
160
+ self.class[other.to_hash.merge(to_hash)]
161
+ end
162
+
163
+ def as_json(*)
164
+ { JSON.create_id => self.class.name }.merge to_hash
165
+ end
166
+
167
+ def to_json(*a)
168
+ as_json.to_json(*a)
169
+ end
170
+ end
171
+
172
+ end # JSON