oj 2.18.5 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -226
  3. data/ext/oj/circarray.c +0 -25
  4. data/ext/oj/circarray.h +0 -25
  5. data/ext/oj/code.c +227 -0
  6. data/ext/oj/code.h +40 -0
  7. data/ext/oj/compat.c +126 -38
  8. data/ext/oj/custom.c +1097 -0
  9. data/ext/oj/dump.c +658 -2376
  10. data/ext/oj/dump.h +92 -0
  11. data/ext/oj/dump_compat.c +937 -0
  12. data/ext/oj/dump_leaf.c +254 -0
  13. data/ext/oj/dump_object.c +810 -0
  14. data/ext/oj/dump_rails.c +329 -0
  15. data/ext/oj/dump_strict.c +416 -0
  16. data/ext/oj/err.c +0 -25
  17. data/ext/oj/err.h +8 -2
  18. data/ext/oj/fast.c +24 -24
  19. data/ext/oj/mimic_json.c +817 -0
  20. data/ext/oj/mimic_rails.c +806 -0
  21. data/ext/oj/mimic_rails.h +17 -0
  22. data/ext/oj/object.c +18 -72
  23. data/ext/oj/odd.c +0 -25
  24. data/ext/oj/odd.h +2 -27
  25. data/ext/oj/oj.c +655 -1503
  26. data/ext/oj/oj.h +93 -40
  27. data/ext/oj/parse.c +99 -46
  28. data/ext/oj/parse.h +12 -26
  29. data/ext/oj/reader.c +1 -25
  30. data/ext/oj/reader.h +3 -25
  31. data/ext/oj/resolve.c +9 -11
  32. data/ext/oj/resolve.h +2 -2
  33. data/ext/oj/rxclass.c +133 -0
  34. data/ext/oj/rxclass.h +27 -0
  35. data/ext/oj/saj.c +4 -25
  36. data/ext/oj/scp.c +3 -25
  37. data/ext/oj/sparse.c +89 -13
  38. data/ext/oj/stream_writer.c +301 -0
  39. data/ext/oj/strict.c +4 -27
  40. data/ext/oj/string_writer.c +480 -0
  41. data/ext/oj/val_stack.h +6 -2
  42. data/lib/oj.rb +1 -23
  43. data/lib/oj/easy_hash.rb +12 -4
  44. data/lib/oj/json.rb +172 -0
  45. data/lib/oj/mimic.rb +123 -18
  46. data/lib/oj/state.rb +131 -0
  47. data/lib/oj/version.rb +1 -1
  48. data/pages/Advanced.md +22 -0
  49. data/pages/Compatibility.md +25 -0
  50. data/pages/Custom.md +23 -0
  51. data/pages/Encoding.md +65 -0
  52. data/pages/JsonGem.md +79 -0
  53. data/pages/Modes.md +140 -0
  54. data/pages/Options.md +250 -0
  55. data/pages/Rails.md +60 -0
  56. data/pages/Security.md +20 -0
  57. data/test/activesupport4/decoding_test.rb +105 -0
  58. data/test/activesupport4/encoding_test.rb +531 -0
  59. data/test/activesupport4/test_helper.rb +41 -0
  60. data/test/activesupport5/decoding_test.rb +125 -0
  61. data/test/activesupport5/encoding_test.rb +483 -0
  62. data/test/activesupport5/encoding_test_cases.rb +90 -0
  63. data/test/activesupport5/test_helper.rb +50 -0
  64. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  65. data/test/json_gem/json_addition_test.rb +216 -0
  66. data/test/json_gem/json_common_interface_test.rb +143 -0
  67. data/test/json_gem/json_encoding_test.rb +109 -0
  68. data/test/json_gem/json_ext_parser_test.rb +20 -0
  69. data/test/json_gem/json_fixtures_test.rb +35 -0
  70. data/test/json_gem/json_generator_test.rb +383 -0
  71. data/test/json_gem/json_generic_object_test.rb +90 -0
  72. data/test/json_gem/json_parser_test.rb +470 -0
  73. data/test/json_gem/json_string_matching_test.rb +42 -0
  74. data/test/json_gem/test_helper.rb +18 -0
  75. data/test/perf_compat.rb +30 -28
  76. data/test/perf_object.rb +1 -1
  77. data/test/perf_strict.rb +18 -1
  78. data/test/sample.rb +0 -1
  79. data/test/test_compat.rb +169 -93
  80. data/test/test_custom.rb +355 -0
  81. data/test/test_file.rb +0 -8
  82. data/test/test_null.rb +376 -0
  83. data/test/test_object.rb +268 -3
  84. data/test/test_scp.rb +22 -1
  85. data/test/test_strict.rb +160 -4
  86. data/test/test_various.rb +52 -620
  87. data/test/tests.rb +14 -0
  88. data/test/tests_mimic.rb +14 -0
  89. data/test/tests_mimic_addition.rb +7 -0
  90. metadata +89 -47
  91. data/test/activesupport_datetime_test.rb +0 -23
  92. data/test/bug.rb +0 -51
  93. data/test/bug2.rb +0 -10
  94. data/test/bug3.rb +0 -46
  95. data/test/bug_fast.rb +0 -32
  96. data/test/bug_load.rb +0 -24
  97. data/test/crash.rb +0 -111
  98. data/test/curl/curl_oj.rb +0 -46
  99. data/test/curl/get_oj.rb +0 -24
  100. data/test/curl/just_curl.rb +0 -31
  101. data/test/curl/just_oj.rb +0 -51
  102. data/test/example.rb +0 -11
  103. data/test/foo.rb +0 -24
  104. data/test/io.rb +0 -48
  105. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  106. data/test/mod.rb +0 -16
  107. data/test/rails.rb +0 -50
  108. data/test/russian.rb +0 -18
  109. data/test/struct.rb +0 -29
  110. data/test/test_serializer.rb +0 -59
  111. data/test/write_timebars.rb +0 -31
@@ -58,7 +58,10 @@ typedef struct _Val {
58
58
  char karray[32];
59
59
  volatile VALUE key_val;
60
60
  union {
61
- const char *classname;
61
+ struct {
62
+ const char *classname;
63
+ VALUE clas;
64
+ };
62
65
  OddArgs odd_args;
63
66
  };
64
67
  uint16_t klen;
@@ -127,7 +130,8 @@ stack_push(ValStack stack, VALUE val, ValNext next) {
127
130
  }
128
131
  stack->tail->val = val;
129
132
  stack->tail->next = next;
130
- stack->tail->classname = 0;
133
+ stack->tail->classname = NULL;
134
+ stack->tail->clas = Qundef;
131
135
  stack->tail->key = 0;
132
136
  stack->tail->key_val = Qundef;
133
137
  stack->tail->clen = 0;
data/lib/oj.rb CHANGED
@@ -1,26 +1,4 @@
1
- # Optimized JSON (Oj), as the name implies was written to provide speed
2
- # optimized JSON handling.
3
- #
4
- # Oj has several dump or serialization modes which control how Objects are
5
- # converted to JSON. These modes are set with the :mode option in either the
6
- # default options or as one of the options to the dump() method.
7
- #
8
- # - :strict mode will only allow the 7 basic JSON types to be serialized. Any other Object
9
- # will raise and Exception.
10
- #
11
- # - :null mode replaces any Object that is not one of the JSON types is replaced by a JSON null.
12
- #
13
- # - :object mode will dump any Object as a JSON Object with keys that match
14
- # the Ruby Object's variable names without the '@' character. This is the
15
- # highest performance mode.
16
- #
17
- # - :compat mode is is the compatible with other systems. It will serialize
18
- # any Object but will check to see if the Object implements a to_hash() or
19
- # to_json() method. If either exists that method is used for serializing the
20
- # Object. The to_hash() is more flexible and produces more consistent output
21
- # so it has a preference over the to_json() method. If neither the to_json()
22
- # or to_hash() methods exist then the Oj internal Object variable encoding
23
- # is used.
1
+
24
2
  module Oj
25
3
  end
26
4
 
@@ -33,10 +33,18 @@ module Oj
33
33
  # @raise [ArgumentError] if an argument is given. Zero arguments expected.
34
34
  # @raise [NoMethodError] if the instance variable is not defined.
35
35
  def method_missing(m, *args, &block)
36
- raise ArgumentError.new("wrong number of arguments (#{args.size} for 0 with #{m}) to method #{m}") unless args.nil? or args.empty?
37
- return fetch(m, nil) if has_key?(m)
38
- return fetch(m.to_s, nil) if has_key?(m.to_s)
39
- return fetch(m.to_sym, nil) if has_key?(m.to_sym)
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
40
48
  raise NoMethodError.new("undefined method #{m}", m)
41
49
  end
42
50
 
@@ -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
@@ -1,4 +1,5 @@
1
1
 
2
+ require 'bigdecimal'
2
3
  begin
3
4
  require 'ostruct'
4
5
  rescue Exception
@@ -29,6 +30,8 @@ module Oj
29
30
  end
30
31
  end
31
32
 
33
+ # Loads mimic-ed JSON paths. Used by Oj.mimic_JSON().
34
+ # @param mimic_path [Array] additional paths to add to the Ruby loaded features.
32
35
  def self.mimic_loaded(mimic_paths=[])
33
36
  $LOAD_PATH.each do |d|
34
37
  next unless File.exist?(d)
@@ -37,12 +40,15 @@ module Oj
37
40
  $LOADED_FEATURES << jfile unless $LOADED_FEATURES.include?(jfile) if File.exist?(jfile)
38
41
 
39
42
  Dir.glob(File.join(d, 'json', '**', '*.rb')).each do |file|
40
- $LOADED_FEATURES << file unless $LOADED_FEATURES.include?(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')
41
45
  end
42
46
  end
43
47
  mimic_paths.each { |p| $LOADED_FEATURES << p }
44
48
  $LOADED_FEATURES << 'json' unless $LOADED_FEATURES.include?('json')
45
49
 
50
+ require 'oj/json'
51
+
46
52
  if Object.const_defined?('OpenStruct')
47
53
  OpenStruct.class_eval do
48
54
  # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
@@ -54,9 +60,100 @@ module Oj
54
60
  end
55
61
  end
56
62
  def self.json_create(h)
57
- new(h['t'])
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 }
58
117
  end
59
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
60
157
  end
61
158
 
62
159
  Range.class_eval do
@@ -67,7 +164,7 @@ module Oj
67
164
  end
68
165
  end
69
166
  def self.json_create(h)
70
- new(h['a'])
167
+ new(*h['a'])
71
168
  end
72
169
  end
73
170
 
@@ -105,7 +202,7 @@ module Oj
105
202
  end
106
203
  end
107
204
  def self.json_create(h)
108
- new(h['v'])
205
+ new(*h['v'])
109
206
  end
110
207
  end
111
208
 
@@ -125,7 +222,6 @@ module Oj
125
222
  # Both the JSON gem and Rails monkey patch as_json. Let them battle it out.
126
223
  unless defined?(self.as_json)
127
224
  def as_json(*)
128
- {JSON.create_id => 'Symbol', 's' => to_s }
129
225
  nsecs = [ tv_usec * 1000 ]
130
226
  nsecs << tv_nsec if respond_to?(:tv_nsec)
131
227
  nsecs = nsecs.max
@@ -144,19 +240,28 @@ module Oj
144
240
  end
145
241
  end
146
242
 
147
- JSON.module_eval do
148
- def self.dump_default_options
149
- Oj::MimicDumpOption.new
150
- end
151
-
152
- def self.dump_default_options=(h)
153
- m = Oj::MimicDumpOption.new
154
- h.each do |k,v|
155
- m[k] = v
156
- end
157
- end
158
- end
159
-
160
243
  end # self.mimic_loaded
161
244
 
162
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
@@ -0,0 +1,131 @@
1
+
2
+ module JSON
3
+ module Ext
4
+ module Generator
5
+ unless defined?(::JSON::Ext::Generator::State)
6
+ # This class exists for json gem compatibility only. While it can be
7
+ # used as the options for other than compatibility a simple Hash is
8
+ # recommended as it is simpler and performs better. The only bit
9
+ # missing by not using a state object is the depth availability which
10
+ # may be the depth during dumping or maybe not since it can be set and
11
+ # the docs for depth= is the same as max_nesting. Note: Had to make
12
+ # this a subclass of Object instead of Hash like EashyHash due to
13
+ # conflicts with the json gem.
14
+ class State
15
+
16
+ def self.from_state(opts)
17
+ s = self.new()
18
+ s.clear()
19
+ s.merge(opts)
20
+ s
21
+ end
22
+
23
+ def initialize(opts = {})
24
+ @attrs = {}
25
+
26
+ # Populate with all vars then merge in opts. This class deviates from
27
+ # the json gem in that any of the options can be set with the opts
28
+ # argument. The json gem limits the opts use to 7 of the options.
29
+ @attrs[:indent] = ''
30
+ @attrs[:space] = ''
31
+ @attrs[:space_before] = ''
32
+ @attrs[:array_nl] = ''
33
+ @attrs[:object_nl] = ''
34
+ @attrs[:allow_nan] = false
35
+ @attrs[:buffer_initial_length] = 1024 # completely ignored by Oj
36
+ @attrs[:depth] = 0
37
+ @attrs[:max_nesting] = 100
38
+ @attrs[:check_circular?] = true
39
+ @attrs[:ascii_only] = false
40
+
41
+ @attrs.merge!(opts)
42
+ end
43
+
44
+ def to_h()
45
+ return @attrs.dup
46
+ end
47
+
48
+ def to_hash()
49
+ return @attrs.dup
50
+ end
51
+
52
+ def allow_nan?()
53
+ @attrs[:allow_nan]
54
+ end
55
+
56
+ def ascii_only?()
57
+ @attrs[:ascii_only]
58
+ end
59
+
60
+ def configure(opts)
61
+ raise TypeError.new('expected a Hash') unless opts.respond_to?(:to_h)
62
+ @attrs.merge!(opts.to_h)
63
+ end
64
+
65
+ def generate(obj)
66
+ JSON.generate(obj)
67
+ end
68
+
69
+ def merge(opts)
70
+ @attrs.merge!(opts)
71
+ end
72
+
73
+ # special rule for this.
74
+ def buffer_initial_length=(len)
75
+ len = 1024 if 0 >= len
76
+ @attrs[:buffer_initial_length] = len
77
+ end
78
+
79
+ # Replaces the Object.respond_to?() method.
80
+ # @param [Symbol] m method symbol
81
+ # @return [Boolean] true for any method that matches an instance
82
+ # variable reader, otherwise false.
83
+ def respond_to?(m)
84
+ return true if super
85
+ return true if has_key?(key)
86
+ return true if has_key?(key.to_s)
87
+ has_key?(key.to_sym)
88
+ end
89
+
90
+ def [](key)
91
+ key = key.to_sym
92
+ @attrs.fetch(key, nil)
93
+ end
94
+
95
+ def []=(key, value)
96
+ key = key.to_sym
97
+ @attrs[key] = value
98
+ end
99
+
100
+ def clear()
101
+ @attrs.clear()
102
+ end
103
+
104
+ def has_key?(k)
105
+ @attrs.has_key?(key.to_sym)
106
+ end
107
+
108
+ # Handles requests for Hash values. Others cause an Exception to be raised.
109
+ # @param [Symbol|String] m method symbol
110
+ # @return [Boolean] the value of the specified instance variable.
111
+ # @raise [ArgumentError] if an argument is given. Zero arguments expected.
112
+ # @raise [NoMethodError] if the instance variable is not defined.
113
+ def method_missing(m, *args, &block)
114
+ if m.to_s.end_with?('=')
115
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 1 with #{m}) to method #{m}") if args.nil? or 1 != args.length
116
+ m = m.to_s[0..-2]
117
+ m = m.to_sym
118
+ return @attrs.store(m, args[0])
119
+ else
120
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 0 with #{m}) to method #{m}") unless args.nil? or args.empty?
121
+ return @attrs[m.to_sym]
122
+ end
123
+ raise NoMethodError.new("undefined method #{m}", m)
124
+ end
125
+
126
+ end # State
127
+ end # defined check
128
+ end # Generator
129
+ end # Ext
130
+
131
+ end # JSON