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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +34 -4
- data/lib/active_model_serializer_plus/assignment.rb +204 -24
- data/lib/active_model_serializer_plus/translations.rb +0 -2
- data/lib/active_model_serializer_plus/version.rb +1 -1
- data/test/active_model_serializer_plus/assignment_test.rb +209 -0
- data/test/test_helper.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24bdcf126d5a85b91e9f44683d88da3c00f28aff
|
4
|
+
data.tar.gz: dcf9f939596e70496714ab6665e2f6b67591a41b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59b914a36ebfaa8349f7a31dda8605ff7449e43b78f9e240415d297f9a8d3161905803295947515eb5fc291166e386d3f5b0a018efefdfacf6c3574f1a8f21db
|
7
|
+
data.tar.gz: 2aefb9e4e67ed9083bf73ec03042476efd5c581aa8d6bdfefa02b2dd848e6cb3f16d398a70a234b9a7ae9dc26583bdd2af106da8a6a41c9e93b7863586313867
|
data/CHANGELOG.md
CHANGED
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
|
-
{
|
98
|
-
|
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
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
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
|
@@ -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
|
data/test/test_helper.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2015-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|