active_model_serializer_plus 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 361857f5e46f0a701cf41f9d43fa7d7f404bf928
4
- data.tar.gz: a59df64844aa6b4d4b7421263c8c98cb0104f69e
3
+ metadata.gz: 24bdcf126d5a85b91e9f44683d88da3c00f28aff
4
+ data.tar.gz: dcf9f939596e70496714ab6665e2f6b67591a41b
5
5
  SHA512:
6
- metadata.gz: 1f4f2018d56e59590fae7c2facc0160cc7971b55bff6e78069f05a8e26ac2bdabd783e60a4a6ace40d56fb542682d49566bda9ac860c2a4325926b3507aec072
7
- data.tar.gz: 13e288511f09e66054680471fa61e51bac872308ac4f46595b46b898be86706ba5cd76a90a0400f9d68618d6954384788c28aec796d24ccd6a25e36d51168edd
6
+ metadata.gz: 59b914a36ebfaa8349f7a31dda8605ff7449e43b78f9e240415d297f9a8d3161905803295947515eb5fc291166e386d3f5b0a018efefdfacf6c3574f1a8f21db
7
+ data.tar.gz: 2aefb9e4e67ed9083bf73ec03042476efd5c581aa8d6bdfefa02b2dd848e6cb3f16d398a70a234b9a7ae9dc26583bdd2af106da8a6a41c9e93b7863586313867
@@ -1,3 +1,7 @@
1
+ # 1.1.0
2
+
3
+ * Add support for Array and Hash containers in JSON representation
4
+
1
5
  # 1.0.0
2
6
 
3
7
  * Initial release
data/README.md CHANGED
@@ -41,12 +41,24 @@ after including all of the ActiveModel modules you need:
41
41
  include ActiveModelSerializerPlus::Assignment
42
42
  ```
43
43
 
44
+ The `#attributes=` method this module provides will raise an `ArgumentError` with a
45
+ descriptive message if a problem occurs.
46
+
44
47
  The class will need to implement the `#attribute_types` method which should return a hash
45
48
  consisting of attribute names and the name of the type/class of the attribute. You only need
46
49
  to include those attributes that are themselves a serializable class and that you want turned
47
50
  back into objects rather than being left as hashes, or attributes that aren't automatically
48
51
  converted from strings back into the correct type (eg. Date, Time, DateTime).
49
52
 
53
+ The value can be a string, symbol or class name to specify the type. For containers (arrays or
54
+ hashes) it is a 2-element array with the first element being the type of the container (array
55
+ or hash) and the second element specifying the type of the elements in the container. You can
56
+ also specify the type of the container as just `'Container'` or `:Container` and the code will
57
+ create a container of the same type (array or hash) as occurs in the JSON. Due to the fact that
58
+ the JSON doesn't indicate the type of elements in a container there's no straightforward way to
59
+ have containers contain elements of different types. It's also not possible to declare a container
60
+ whose elements are containers, elements have to be of a non-container class.
61
+
50
62
  This would be an example:
51
63
 
52
64
  ```ruby
@@ -61,19 +73,22 @@ class Example
61
73
  attr_accessor :time_field
62
74
  attr_accessor :string_field
63
75
  attr_accessor :object_field
76
+ attr_accessor :array_field
64
77
 
65
78
  def attributes
66
79
  {
67
80
  'integer_field' => nil,
68
81
  'time_field' => nil,
69
82
  'string_field' => nil,
70
- 'object_field' => nil
83
+ 'object_field' => nil,
84
+ 'array_field' => nil
71
85
  }
72
86
 
73
87
  def attribute_types
74
88
  {
75
89
  'time_field' => 'Time',
76
- 'object_field' => 'SomeSerializableClass'
90
+ 'object_field' => 'SomeSerializableClass',
91
+ 'array_field' => [ 'Array', 'Integer' ]
77
92
  }
78
93
 
79
94
  def initialize( i, t, s, o )
@@ -82,6 +97,7 @@ class Example
82
97
  time_field = t
83
98
  string_field = s
84
99
  object_field = o
100
+ array_field = [ 1, 2, 3, 4, 5 ]
85
101
  }
86
102
 
87
103
  end
@@ -94,8 +110,8 @@ Examples of using this class to serialize an object to a JSON string:
94
110
 
95
111
  json_string now contains:
96
112
 
97
- { 'integer_field' => 5, 'time_field' => '"2015-09-26T19:04:07-07:00', 'string_field' => 'xyzzy abc',
98
- 'object_field' => { ... } }
113
+ { "integer_field" => 5, "time_field" => "2015-09-26T19:04:07-07:00", "string_field" => "xyzzy abc",
114
+ "object_field" => { ... }, "array_field" => [ 1, 2, 3, 4, 5 ] }
99
115
 
100
116
  And deserializing that string back to an object:
101
117
 
@@ -134,6 +150,20 @@ add_xlate('FalseClass', 'Boolean')
134
150
  which would create the parsing proc entry for `Boolean` and add the translation entries so that `TrueClass`
135
151
  and `FalseClass` act as if derived from an imaginary `Boolean` class for formatting and parsing purposes.
136
152
 
153
+ ## Adding information about new containers
154
+
155
+ In `assignment.rb` there are some functions defined on the ActiveModelSerializersPlus module for adding
156
+ new containers. The basic one is `#add_container` which takes 3 arguments: the container type
157
+ name, a proc for iterating through elements from that kind of container and a proc for adding an item to
158
+ that kind of container. The procs paper over the differences in containers, without that there'd need to
159
+ be a separate bit of code for every permutation of source container in the JSON and new destination container.
160
+ The procs for Hash-like containers are the basis for the code. The iterator proc for an Array-like container
161
+ uses the array index as the key when calling the adder proc, and the adder proc for Array-like containers
162
+ ignores the key and just appends the new item to the array. I don't expect a need to add containers often,
163
+ and since most new containers will act like either Arrays or Hashes there are two convenience functions
164
+ `#add_arraylike_container` and `#add_hashlike_container` that take just the container type name and use
165
+ the matching standard iterator and adder procs.
166
+
137
167
  ## Contributing
138
168
 
139
169
  This project uses `git-flow`, where new features are developed along feature branches based off the
@@ -2,6 +2,129 @@ require 'active_model_serializer_plus/translations'
2
2
 
3
3
  module ActiveModelSerializerPlus
4
4
 
5
+ private
6
+
7
+ # Add a new value to an array-like container. `index` will be ignored.
8
+ @@add_to_arraylike_proc = Proc.new { |container, index, value|
9
+ container << value
10
+ }
11
+ # Add a new key and it's value to a hash-like container.
12
+ @@add_to_hashlike_proc = Proc.new { |container, key, value|
13
+ container[key] = value
14
+ }
15
+
16
+ # Populate a new container from an array-like value
17
+ @@build_from_arraylike_proc = Proc.new { |container, add_proc, obj_klass, value_container|
18
+ index = 0
19
+ value_container.each do |item|
20
+ obj = ActiveModelSerializerPlus.build_object(obj_klass, item)
21
+ add_proc.call(container, index, obj) unless obj.nil?
22
+ index += 1
23
+ end
24
+ }
25
+ # Populate a new container from a hash-like value
26
+ @@build_from_hashlike_proc = Proc.new { |container, add_proc, obj_klass, value_container|
27
+ value_container.each do |key, item|
28
+ obj = ActiveModelSerializerPlus.build_object(obj_klass, item)
29
+ add_proc.call(container, key, obj) unless obj.nil?
30
+ end
31
+ }
32
+
33
+ # Map container type names to the procs that iterate through that kind of container.
34
+ #
35
+ # You can probably treat the array-like and hash-like procs as standard procs to
36
+ # handle building from any container that acts like an array (iterates values, indexes are
37
+ # integers starting from 0) or hash (iterates keys and values).
38
+ # @note we need both iterator and adder procs so we can build arrays from hashes and vice-versa without
39
+ # having to manually list out every permutation.
40
+ @@container_iterators = {
41
+ 'Array' => @@build_from_arraylike_proc,
42
+ 'Hash' => @@build_from_hashlike_proc
43
+ }
44
+
45
+ # Map container type names to the procs that add a new item to that kind of container.
46
+ #
47
+ # Again you can probably treat the array-like and hash-like procs as standard procs
48
+ # to add items to any container that behaves like an array or hash.
49
+ @@container_adders = {
50
+ 'Array' => @@add_to_arraylike_proc,
51
+ 'Hash' => @@add_to_hashlike_proc
52
+ }
53
+
54
+ public
55
+
56
+ # Look up iterator proc.
57
+ def self.get_container_iterator(typename)
58
+ @@container_iterators[typename]
59
+ end
60
+
61
+ # Look up adder proc.
62
+ def self.get_container_adder(typename)
63
+ @@container_adders[typename]
64
+ end
65
+
66
+ # Break out the logic for creating a new object of a class from a hash or string value.
67
+ # It's needed for both individual attributes and for each element of a
68
+ # container.
69
+ # @param [Class] obj_klass class of the object to create
70
+ # @param [String, Hash] value value to use to initialize the object
71
+ # @return [Object] newly-created object or nil
72
+ # @raise [ArgumentError] if the object cannot be created
73
+ def self.build_object(obj_klass, value)
74
+ obj = nil
75
+ if value.is_a?(Hash)
76
+ # If we're looking at a contained object (our value is a hash), see if we have a Proc
77
+ # to build the object from a hash. If we don't, fall back to creating an object and
78
+ # using the hash #attributes= method if possible. If all else fails just leave the value
79
+ obj = ActiveModelSerializerPlus.build(obj_klass.name, value)
80
+ if obj.nil? && obj_klass.method_defined?('attributes=')
81
+ obj = obj_klass.new
82
+ if obj.nil?
83
+ raise ArgumentError, "Cannot create object of type #{obj_klass.name}."
84
+ end
85
+ obj.attributes = value
86
+ end
87
+ elsif value.is_a?(String)
88
+ obj = ActiveModelSerializerPlus.parse(obj_klass.name, value)
89
+ end
90
+ obj
91
+ end
92
+
93
+ # Add iterator and adder procs for a new kind of container.
94
+ # @param [String] typename type name of the container type to add
95
+ # @param [Proc] iterator_proc Proc to build from that type of container
96
+ # @param [Proc] adder_proc Proc to add an item to that type of container
97
+ # @return [void]
98
+ def self.add_container(typename, iterator_proc, adder_proc)
99
+ return if typename.blank? || iterator_proc.nil? || adder_proc.nil?
100
+ @@container_iterators[typename] = iterator_proc
101
+ @@container_adders[typename] = adder_proc
102
+ ActiveModelSerializerPlus.add_xlate(typename, 'Container')
103
+ return
104
+ end
105
+
106
+ # Add a new kind of Array-like container
107
+ # @param [String] typename type name of the container type to add
108
+ # @return [void]
109
+ def self.add_arraylike_container(typename)
110
+ return if typename.blank?
111
+ @@container_iterators[typename] = @@build_from_arraylike_proc
112
+ @@container_adders[typename] = @@add_to_arraylike_proc
113
+ ActiveModelSerializerPlus.add_xlate(typename, 'Container')
114
+ return
115
+ end
116
+
117
+ # Add a new kind of Hash-like container
118
+ # @param [String] typename type name of the container type to add
119
+ # @return [void]
120
+ def self.add_hashlike_container(typename)
121
+ return if typename.blank?
122
+ @@container_iterators[typename] = @@build_from_hashlike_proc
123
+ @@container_adders[typename] = @@add_to_hashlike_proc
124
+ ActiveModelSerializerPlus.add_xlate(typename, 'Container')
125
+ return
126
+ end
127
+
5
128
  # @author Todd Knarr <tknarr@silverglass.org>
6
129
  #
7
130
  # Default implementation of the <tt>#attributes=</tt> method for ActiveModel classes.
@@ -21,42 +144,99 @@ module ActiveModelSerializerPlus
21
144
  # The default <tt>#attributes=</tt> method which assigns a hash to the object's attributes.
22
145
  # @param [Hash] hash the hash of attribute names and values
23
146
  # @return [self] self
24
- # @raise [ArgumentError] if a value from the @attribute_types hash can't be converted to a Class
147
+ # @raise [ArgumentError] if any error occurs
25
148
  def attributes=(hash)
26
149
  hash.each do |key, value|
27
150
  # Check #attribute_types for what type this item should be, and if we have an entry
28
151
  # convert it to an actual Class object we can use.
29
- klass = nil
30
- v = nil
31
- v = self.attribute_types[key] if self.respond_to?(:attribute_types) && self.attribute_types.is_a?(Hash)
32
- begin
33
- klass = ActiveModelSerializerPlus.to_class(v) unless v.nil?
34
- rescue ArgumentError
35
- raise ArgumentError, "Type #{v.to_s} for attribute #{key.to_s} is not a valid type."
36
- end
152
+ attr_klass = nil
153
+ attr_typename = nil
154
+
155
+ attr_typename = self.attribute_types[key] if self.respond_to?(:attribute_types) && self.attribute_types.is_a?(Hash)
156
+ if attr_typename.is_a?(Array)
157
+ # Container
158
+
159
+ container_klass = nil
160
+ object_klass = nil
161
+
162
+ if attr_typename.length != 2
163
+ raise ArgumentError, "Container type specification for attribute #{key.to_s} is invalid."
164
+ end
37
165
 
38
- unless klass.nil?
39
- if value.is_a?(Hash)
40
- # If we're looking at a contained object (our value is a hash), see if we have a Proc
41
- # to build the object from a hash. If we don't, fall back to creating an object and
42
- # using the hash #attributes= method if possible. If all else fails just leave the value
43
- v = ActiveModelSerializerPlus.build(klass.name, value)
44
- if v.nil? && klass.method_defined?('attributes=')
45
- v = klass.new
46
- v.attributes = value
166
+ # Sort out the type of container. First make sure the container type name translates to 'Container'.
167
+ # If the type name actually is 'Container', take the type of the container from the type of the
168
+ # original value. If it's an actual type name, convert it to a Class object. Raise exceptions if
169
+ # any problems are encountered.
170
+ container_typename = attr_typename[0]
171
+ if container_typename == 'Container'
172
+ container_klass = value.class
173
+ else
174
+ xlated_container_typename = ActiveModelSerializerPlus.type_name_xlate(container_typename)
175
+ if xlated_container_typename != 'Container'
176
+ raise ArgumentError, "Container type #{container_typename} for attribute #{key.to_s} is not a container."
47
177
  end
178
+ begin
179
+ container_klass = ActiveModelSerializerPlus.to_class(container_typename)
180
+ rescue ArgumentError
181
+ raise ArgumentError, "Container type #{container_typename} for attribute #{key.to_s} is not a valid type."
182
+ end
183
+ end
184
+
185
+ # Sort out the type of objects in the container. Convert the object type name to a Class object
186
+ # and raise an exception if it can't be converted.
187
+ object_typename = attr_typename[1]
188
+ begin
189
+ object_klass = ActiveModelSerializerPlus.to_class(object_typename)
190
+ rescue ArgumentError
191
+ raise ArgumentError, "Object type #{object_typename} for attribute #{key.to_s} is not a valid type."
192
+ end
193
+
194
+ container = container_klass.new
195
+ if container.nil?
196
+ raise ArgumentError, "Cannot create container of type #{container_klass.name}."
197
+ end
198
+ adder_proc = ActiveModelSerializerPlus.get_container_adder(container_klass.name)
199
+ iterator_proc = ActiveModelSerializerPlus.get_container_iterator(value.class.name)
200
+ if adder_proc.nil? || iterator_proc.nil?
201
+ msg = ''
202
+ if iterator_proc.nil?
203
+ msg << "iterate through #{value.class.name}"
204
+ end
205
+ if adder_proc.nil?
206
+ if msg.length == 0
207
+ msg << ', '
208
+ end
209
+ msg << "add to #{container_klass.name}"
210
+ end
211
+ raise ArgumentError, "Cannot #{msg}."
212
+ end
213
+ # Build the new container by iterating through the value container and adding each item to
214
+ # the new container, using the procs we looked up.
215
+ iterator_proc.call(container, adder_proc, object_klass, value)
216
+
217
+ self.send("#{key}=", container)
218
+
219
+ else
220
+ # Object
221
+
222
+ unless attr_typename.nil?
223
+ begin
224
+ attr_klass = ActiveModelSerializerPlus.to_class(attr_typename)
225
+ rescue ArgumentError
226
+ raise ArgumentError, "Type #{attr_typename.to_s} for attribute #{key.to_s} is not a valid type."
227
+ end
228
+
229
+ v = ActiveModelSerializerPlus.build_object(attr_klass, value)
48
230
  value = v unless v.nil?
49
- elsif value.is_a?(String)
50
- v = ActiveModelSerializerPlus.parse(klass.name, value)
51
- value = v if v
52
231
  end
232
+
233
+ self.send("#{key}=", value)
234
+
53
235
  end
54
236
 
55
- self.send("#{key}=", value)
237
+ self
56
238
  end
57
239
 
58
- self
59
-
60
240
  end
61
241
 
62
242
  end
@@ -67,8 +67,6 @@ module ActiveModelSerializerPlus
67
67
 
68
68
  public
69
69
 
70
- # @!scope class
71
-
72
70
  # Translate a type/class name to it's psuedo-parent class name if it has one.
73
71
  # @param [String] class_name the name of the class to translate
74
72
  # @return [String] the translated name
@@ -1,6 +1,6 @@
1
1
  module ActiveModelSerializerPlus
2
2
 
3
3
  # Version number.
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.0"
5
5
 
6
6
  end
@@ -34,6 +34,81 @@ class ModelClass
34
34
  end
35
35
  end
36
36
 
37
+ class ObjectClass
38
+ include ActiveModel::Model
39
+ include ActiveModel::Serializers::JSON
40
+ include ActiveModelSerializerPlus::Assignment
41
+
42
+ attr_accessor :x
43
+ attr_accessor :y
44
+
45
+ def attributes
46
+ { 'x' => nil,
47
+ 'y' => nil
48
+ }
49
+ end
50
+ end
51
+
52
+ class ArrayClass
53
+ include ActiveModel::Model
54
+ include ActiveModel::Serializers::JSON
55
+ include ActiveModelSerializerPlus::Assignment
56
+
57
+ attr_accessor :integer_field
58
+ attr_accessor :array_field
59
+
60
+ def attributes
61
+ { 'integer_field' => nil,
62
+ 'array_field' => nil
63
+ }
64
+ end
65
+
66
+ def attribute_types
67
+ { 'array_field' => [ 'Array', 'ObjectClass' ]
68
+ }
69
+ end
70
+ end
71
+
72
+ class HashClass
73
+ include ActiveModel::Model
74
+ include ActiveModel::Serializers::JSON
75
+ include ActiveModelSerializerPlus::Assignment
76
+
77
+ attr_accessor :integer_field
78
+ attr_accessor :hash_field
79
+
80
+ def attributes
81
+ { 'integer_field' => nil,
82
+ 'hash_field' => nil
83
+ }
84
+ end
85
+
86
+ def attribute_types
87
+ { 'hash_field' => [ 'Hash', 'ObjectClass' ]
88
+ }
89
+ end
90
+ end
91
+
92
+ class ContainerClass
93
+ include ActiveModel::Model
94
+ include ActiveModel::Serializers::JSON
95
+ include ActiveModelSerializerPlus::Assignment
96
+
97
+ attr_accessor :integer_field
98
+ attr_accessor :container_field
99
+
100
+ def attributes
101
+ { 'integer_field' => nil,
102
+ 'container_field' => nil
103
+ }
104
+ end
105
+
106
+ def attribute_types
107
+ { 'container_field' => [ 'Container', 'ObjectClass' ]
108
+ }
109
+ end
110
+ end
111
+
37
112
  class AssignmentTest < ActiveSupport::TestCase
38
113
  include ActiveModel::Lint::Tests
39
114
 
@@ -42,6 +117,55 @@ class AssignmentTest < ActiveSupport::TestCase
42
117
  @model.a = 'xyzzy'
43
118
  @model.b = InnerClass.new
44
119
  @model.b.x = 15
120
+
121
+ @array = ArrayClass.new
122
+ @array.integer_field = 15
123
+ @array.array_field = Array.new
124
+ o = ObjectClass.new
125
+ o.x = 21
126
+ o.y = 22
127
+ @array.array_field << o
128
+ o = ObjectClass.new
129
+ o.x = 31
130
+ o.y = 32
131
+ @array.array_field << o
132
+ o = ObjectClass.new
133
+ o.x = 41
134
+ o.y = 42
135
+ @array.array_field << o
136
+
137
+ @hash = HashClass.new
138
+ @hash.integer_field = 16
139
+ @hash.hash_field = Hash.new
140
+ o = ObjectClass.new
141
+ o.x = 21
142
+ o.y = 22
143
+ @hash.hash_field['first'] = o
144
+ o = ObjectClass.new
145
+ o.x = 31
146
+ o.y = 32
147
+ @hash.hash_field['second'] = o
148
+ o = ObjectClass.new
149
+ o.x = 41
150
+ o.y = 42
151
+ @hash.hash_field['third'] = o
152
+
153
+
154
+ @container = ContainerClass.new
155
+ @container.integer_field = 17
156
+ @container.container_field = Hash.new
157
+ o = ObjectClass.new
158
+ o.x = 21
159
+ o.y = 22
160
+ @container.container_field['first'] = o
161
+ o = ObjectClass.new
162
+ o.x = 31
163
+ o.y = 32
164
+ @container.container_field['second'] = o
165
+ o = ObjectClass.new
166
+ o.x = 41
167
+ o.y = 42
168
+ @container.container_field['third'] = o
45
169
  end
46
170
 
47
171
  test 'deserialize ModelClass' do
@@ -61,4 +185,89 @@ class AssignmentTest < ActiveSupport::TestCase
61
185
  assert_kind_of Integer, r.b.x, 'check attribute x'
62
186
  assert_equal 15, r.b.x, 'check attribute x'
63
187
  end
188
+
189
+ test 'deserialize ArrayClass' do
190
+ json = @array.to_json
191
+ assert_kind_of String, json, 'convert model to JSON'
192
+
193
+ r = ArrayClass.new
194
+ r.from_json(json)
195
+ assert_not_nil r, 'check new object'
196
+ assert_kind_of ArrayClass, r, 'check new object'
197
+ assert_not_nil r.integer_field, 'check integer field'
198
+ assert_kind_of Integer, r.integer_field, 'check integer field'
199
+ assert_equal 15, r.integer_field, 'check integer field'
200
+ assert_not_nil r.array_field, 'check array field'
201
+ assert_kind_of Array, r.array_field, 'check array field'
202
+ assert_not_empty r.array_field, 'check array field length'
203
+ assert_equal 3, r.array_field.length, 'check array field length'
204
+ for i in 0..2 do
205
+ assert_not_nil r.array_field[i], "check array element #{i}"
206
+ assert_kind_of ObjectClass, r.array_field[i], "check array element #{i}"
207
+ assert_not_nil r.array_field[i].x, "check array element #{i} x"
208
+ assert_kind_of Integer, r.array_field[i].x, "check array element #{i} x"
209
+ assert_equal (i+2)*10+1, r.array_field[i].x, "check array element #{i} x"
210
+ assert_not_nil r.array_field[i].y, "check array element #{i} y"
211
+ assert_kind_of Integer, r.array_field[i].y, "check array element #{i} y"
212
+ assert_equal (i+2)*10+2, r.array_field[i].y, "check array element #{i} y"
213
+ end
214
+ end
215
+
216
+ test 'deserialize HashClass' do
217
+ json = @hash.to_json
218
+ assert_kind_of String, json, 'convert model to JSON'
219
+
220
+ r = HashClass.new
221
+ r.from_json(json)
222
+ assert_not_nil r, 'check new object'
223
+ assert_kind_of HashClass, r, 'check new object'
224
+ assert_not_nil r.integer_field, 'check integer field'
225
+ assert_kind_of Integer, r.integer_field, 'check integer field'
226
+ assert_equal 16, r.integer_field, 'check integer field'
227
+ assert_not_nil r.hash_field, 'check hash field'
228
+ assert_kind_of Hash, r.hash_field, 'check hash field'
229
+ assert_not_empty r.hash_field, 'check hash field length'
230
+ assert_equal 3, r.hash_field.length, 'check hash field length'
231
+ i = 0
232
+ ['first', 'second', 'third'].each do |idx|
233
+ assert_not_nil r.hash_field[idx], "check hash element #{idx}"
234
+ assert_kind_of ObjectClass, r.hash_field[idx], "check hash element #{idx}"
235
+ assert_not_nil r.hash_field[idx].x, "check hash element #{idx} x"
236
+ assert_kind_of Integer, r.hash_field[idx].x, "check hash element #{idx} x"
237
+ assert_equal (i+2)*10+1, r.hash_field[idx].x, "check hash element #{idx} x"
238
+ assert_not_nil r.hash_field[idx].y, "check hash element #{idx} y"
239
+ assert_kind_of Integer, r.hash_field[idx].y, "check hash element #{idx} y"
240
+ assert_equal (i+2)*10+2, r.hash_field[idx].y, "check hash element #{idx} y"
241
+ i += 1
242
+ end
243
+ end
244
+
245
+ test 'deserialize ContainerClass' do
246
+ json = @container.to_json
247
+ assert_kind_of String, json, 'convert model to JSON'
248
+
249
+ r = ContainerClass.new
250
+ r.from_json(json)
251
+ assert_not_nil r, 'check new object'
252
+ assert_kind_of ContainerClass, r, 'check new object'
253
+ assert_not_nil r.integer_field, 'check integer field'
254
+ assert_kind_of Integer, r.integer_field, 'check integer field'
255
+ assert_equal 17, r.integer_field, 'check integer field'
256
+ assert_not_nil r.container_field, 'check container field'
257
+ assert_kind_of Hash, r.container_field, 'check container field'
258
+ assert_not_empty r.container_field, 'check container field length'
259
+ assert_equal 3, r.container_field.length, 'check container field length'
260
+ i = 0
261
+ ['first', 'second', 'third'].each do |idx|
262
+ assert_not_nil r.container_field[idx], "check container element #{idx}"
263
+ assert_kind_of ObjectClass, r.container_field[idx], "check container element #{idx}"
264
+ assert_not_nil r.container_field[idx].x, "check container element #{idx} x"
265
+ assert_kind_of Integer, r.container_field[idx].x, "check container element #{idx} x"
266
+ assert_equal (i+2)*10+1, r.container_field[idx].x, "check container element #{idx} x"
267
+ assert_not_nil r.container_field[idx].y, "check container element #{idx} y"
268
+ assert_kind_of Integer, r.container_field[idx].y, "check container element #{idx} y"
269
+ assert_equal (i+2)*10+2, r.container_field[idx].y, "check container element #{idx} y"
270
+ i += 1
271
+ end
272
+ end
64
273
  end
@@ -17,4 +17,5 @@ require 'rails/test_help'
17
17
  class ActiveSupport::TestCase
18
18
 
19
19
  # Add more helper methods to be used by all tests here...
20
+
20
21
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_model_serializer_plus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd Knarr
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-09 00:00:00.000000000 Z
11
+ date: 2015-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails