active_model_serializer_plus 1.0.0 → 1.1.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.
- 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
|