angularjs-rails-resource 0.2.1 → 0.2.2
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 +8 -8
- data/README.md +39 -4
- data/angularjs-rails-resource.gemspec +2 -1
- data/lib/angularjs-rails-resource/version.rb +1 -1
- data/test/unit/angularjs/rails/resourceProviderSpec.js +43 -0
- data/test/unit/angularjs/rails/resourceSpec.js +47 -0
- data/test/unit/angularjs/rails/serializationSpec.js +345 -283
- data/vendor/assets/javascripts/angularjs/rails/resource/resource.js +294 -263
- data/vendor/assets/javascripts/angularjs/rails/resource/serialization.js +486 -431
- metadata +7 -4
@@ -1,471 +1,526 @@
|
|
1
1
|
(function (undefined) {
|
2
|
-
angular.module('rails').
|
2
|
+
angular.module('rails').provider('railsSerializer', function() {
|
3
3
|
var defaultOptions = {
|
4
|
-
underscore:
|
5
|
-
camelize:
|
6
|
-
pluralize:
|
7
|
-
exclusionMatchers: []
|
8
|
-
excludeByDefault: false
|
4
|
+
underscore: undefined,
|
5
|
+
camelize: undefined,
|
6
|
+
pluralize: undefined,
|
7
|
+
exclusionMatchers: []
|
9
8
|
};
|
10
9
|
|
11
|
-
|
10
|
+
/**
|
11
|
+
* Configures the underscore method used by the serializer. If not defined then <code>RailsInflector.underscore</code>
|
12
|
+
* will be used.
|
13
|
+
*
|
14
|
+
* @param {function(string):string} fn The function to use for underscore conversion
|
15
|
+
* @returns {railsSerializerProvider} The provider for chaining
|
16
|
+
*/
|
17
|
+
this.underscore = function(fn) {
|
18
|
+
defaultOptions.underscore = fn;
|
19
|
+
return this;
|
20
|
+
};
|
12
21
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
22
|
+
/**
|
23
|
+
* Configures the camelize method used by the serializer. If not defined then <code>RailsInflector.camelize</code>
|
24
|
+
* will be used.
|
25
|
+
*
|
26
|
+
* @param {function(string):string} fn The function to use for camelize conversion
|
27
|
+
* @returns {railsSerializerProvider} The provider for chaining
|
28
|
+
*/
|
29
|
+
this.camelize = function(fn) {
|
30
|
+
defaultOptions.camelize = fn;
|
31
|
+
return this;
|
32
|
+
};
|
18
33
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
customizer.call(this, this);
|
31
|
-
}
|
32
|
-
}
|
34
|
+
/**
|
35
|
+
* Configures the pluralize method used by the serializer. If not defined then <code>RailsInflector.pluralize</code>
|
36
|
+
* will be used.
|
37
|
+
*
|
38
|
+
* @param {function(string):string} fn The function to use for pluralizing strings.
|
39
|
+
* @returns {railsSerializerProvider} The provider for chaining
|
40
|
+
*/
|
41
|
+
this.pluralize = function(fn) {
|
42
|
+
defaultOptions.pluralize = fn;
|
43
|
+
return this;
|
44
|
+
};
|
33
45
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
return this;
|
48
|
-
};
|
49
|
-
|
50
|
-
/**
|
51
|
-
* Accepts a variable list of attribute names that should be included in JSON serialization.
|
52
|
-
* Using this method will by default exclude all other attributes and only the ones explicitly included using <code>only</code> will be serialized.
|
53
|
-
* @param attributeNames... {string} Variable number of attribute name parameters
|
54
|
-
* @returns {Serializer} this for chaining support
|
55
|
-
*/
|
56
|
-
Serializer.prototype.only = function () {
|
57
|
-
var inclusions = this.inclusions;
|
58
|
-
this.options.excludeByDefault = true;
|
59
|
-
|
60
|
-
angular.forEach(arguments, function (attributeName) {
|
61
|
-
inclusions[attributeName] = true;
|
62
|
-
});
|
63
|
-
|
64
|
-
return this;
|
65
|
-
};
|
66
|
-
|
67
|
-
/**
|
68
|
-
* This is a shortcut for rename that allows you to specify a variable number of attributes that should all be renamed to
|
69
|
-
* <code>{attributeName}_attributes</code> to work with the Rails nested_attributes feature.
|
70
|
-
* @param attributeNames... {string} Variable number of attribute name parameters
|
71
|
-
* @returns {Serializer} this for chaining support
|
72
|
-
*/
|
73
|
-
Serializer.prototype.nestedAttribute = function () {
|
74
|
-
var self = this;
|
75
|
-
|
76
|
-
angular.forEach(arguments, function (attributeName) {
|
77
|
-
self.rename(attributeName, attributeName + '_attributes');
|
78
|
-
});
|
79
|
-
|
80
|
-
return this;
|
81
|
-
};
|
82
|
-
|
83
|
-
/**
|
84
|
-
* Specifies an attribute that is a nested resource within the parent object.
|
85
|
-
* Nested resources do not imply nested attributes, if you want both you still have to specify call <code>nestedAttribute</code> as well.
|
86
|
-
*
|
87
|
-
* A nested resource serves two purposes. First, it defines the resource that should be used when constructing resources from the server.
|
88
|
-
* Second, it specifies how the nested object should be serialized.
|
89
|
-
*
|
90
|
-
* An optional third parameter <code>serializer</code> is available to override the serialization logic
|
91
|
-
* of the resource in case you need to serialize it differently in multiple contexts.
|
92
|
-
*
|
93
|
-
* @param attributeName {string} The name of the attribute that is a nested resource
|
94
|
-
* @param resource {string | Resource} A reference to the resource that the attribute is a type of.
|
95
|
-
* @param serializer {string | Serializer} (optional) An optional serializer reference to override the nested resource's default serializer
|
96
|
-
* @returns {Serializer} this for chaining support
|
97
|
-
*/
|
98
|
-
Serializer.prototype.resource = function (attributeName, resource, serializer) {
|
99
|
-
this.nestedResources[attributeName] = resource;
|
100
|
-
|
101
|
-
if (serializer) {
|
102
|
-
this.serializeWith(attributeName, serializer);
|
103
|
-
}
|
46
|
+
/**
|
47
|
+
* Configures the array exclusion matchers by the serializer. Exclusion matchers can be one of the following:
|
48
|
+
* * string - Defines a prefix that is used to test for exclusion
|
49
|
+
* * RegExp - A custom regular expression that is tested against the attribute name
|
50
|
+
* * function - A custom function that accepts a string argument and returns a boolean with true indicating exclusion.
|
51
|
+
*
|
52
|
+
* @param {Array.<string|function(string):boolean|RegExp} exclusions An array of exclusion matchers
|
53
|
+
* @returns {railsSerializerProvider} The provider for chaining
|
54
|
+
*/
|
55
|
+
this.exclusionMatchers = function(exclusions) {
|
56
|
+
defaultOptions.exclusionMatchers = exclusions;
|
57
|
+
return this;
|
58
|
+
};
|
104
59
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
this.
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
* @param value {*} The value to add, if specified as a function then the function will be called during serialization
|
132
|
-
* and should return the value to add.
|
133
|
-
* @returns {Serializer} this for chaining support
|
134
|
-
*/
|
135
|
-
Serializer.prototype.add = function (attributeName, value) {
|
136
|
-
this.customSerializedAttributes[attributeName] = value;
|
137
|
-
return this;
|
138
|
-
};
|
139
|
-
|
140
|
-
|
141
|
-
/**
|
142
|
-
* Allows the attribute to be preserved unmodified in the resulting object.
|
143
|
-
*
|
144
|
-
* @param attributeName {string} The name of the attribute to add
|
145
|
-
* @returns {Serializer} this for chaining support
|
146
|
-
*/
|
147
|
-
Serializer.prototype.preserve = function(attributeName) {
|
148
|
-
this.preservedAttributes[attributeName] = true;
|
149
|
-
return this;
|
150
|
-
};
|
151
|
-
|
152
|
-
/**
|
153
|
-
* Specify a custom serializer to use for an attribute.
|
154
|
-
*
|
155
|
-
* @param attributeName {string} The name of the attribute
|
156
|
-
* @param serializer {string | constructor} A reference to the custom serializer to use for the attribute.
|
157
|
-
* @returns {Serializer} this for chaining support
|
158
|
-
*/
|
159
|
-
Serializer.prototype.serializeWith = function (attributeName, serializer) {
|
160
|
-
this.customSerializers[attributeName] = serializer;
|
161
|
-
return this;
|
162
|
-
};
|
163
|
-
|
164
|
-
/**
|
165
|
-
* Determines whether or not an attribute should be excluded.
|
166
|
-
*
|
167
|
-
* If the option excludeByDefault has been set then attributes will default to excluded and will only
|
168
|
-
* be included if they have been included using the "only" customization function.
|
169
|
-
*
|
170
|
-
* If the option excludeByDefault has not been set then attributes must be explicitly excluded using the "exclude"
|
171
|
-
* customization function or must be matched by one of the exclusionMatchers.
|
172
|
-
*
|
173
|
-
* @param attributeName The name of the attribute to check for exclusion
|
174
|
-
* @returns {boolean} true if excluded, false otherwise
|
175
|
-
*/
|
176
|
-
Serializer.prototype.isExcludedFromSerialization = function (attributeName) {
|
177
|
-
if ((this.options.excludeByDefault && !this.inclusions.hasOwnProperty(attributeName)) || this.exclusions.hasOwnProperty(attributeName)) {
|
178
|
-
return true;
|
60
|
+
this.$get = ['$injector', 'RailsInflector', 'RailsResourceInjector', function ($injector, RailsInflector, RailsResourceInjector) {
|
61
|
+
defaultOptions.underscore = defaultOptions.underscore || RailsInflector.underscore;
|
62
|
+
defaultOptions.camelize = defaultOptions.camelize || RailsInflector.camelize;
|
63
|
+
defaultOptions.pluralize = defaultOptions.pluralize || RailsInflector.pluralize;
|
64
|
+
|
65
|
+
function railsSerializer(options, customizer) {
|
66
|
+
|
67
|
+
function Serializer() {
|
68
|
+
if (angular.isFunction(options)) {
|
69
|
+
customizer = options;
|
70
|
+
options = {};
|
71
|
+
}
|
72
|
+
|
73
|
+
this.exclusions = {};
|
74
|
+
this.inclusions = {};
|
75
|
+
this.serializeMappings = {};
|
76
|
+
this.deserializeMappings = {};
|
77
|
+
this.customSerializedAttributes = {};
|
78
|
+
this.preservedAttributes = {};
|
79
|
+
this.customSerializers = {};
|
80
|
+
this.nestedResources = {};
|
81
|
+
this.options = angular.extend({excludeByDefault: false}, defaultOptions, options || {});
|
82
|
+
|
83
|
+
if (customizer) {
|
84
|
+
customizer.call(this, this);
|
85
|
+
}
|
179
86
|
}
|
180
87
|
|
181
|
-
|
182
|
-
|
88
|
+
/**
|
89
|
+
* Accepts a variable list of attribute names to exclude from JSON serialization.
|
90
|
+
*
|
91
|
+
* @param attributeNames... {string} Variable number of attribute name parameters
|
92
|
+
* @returns {Serializer} this for chaining support
|
93
|
+
*/
|
94
|
+
Serializer.prototype.exclude = function () {
|
95
|
+
var exclusions = this.exclusions;
|
96
|
+
|
97
|
+
angular.forEach(arguments, function (attributeName) {
|
98
|
+
exclusions[attributeName] = false;
|
99
|
+
});
|
183
100
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
101
|
+
return this;
|
102
|
+
};
|
103
|
+
|
104
|
+
/**
|
105
|
+
* Accepts a variable list of attribute names that should be included in JSON serialization.
|
106
|
+
* Using this method will by default exclude all other attributes and only the ones explicitly included using <code>only</code> will be serialized.
|
107
|
+
* @param attributeNames... {string} Variable number of attribute name parameters
|
108
|
+
* @returns {Serializer} this for chaining support
|
109
|
+
*/
|
110
|
+
Serializer.prototype.only = function () {
|
111
|
+
var inclusions = this.inclusions;
|
112
|
+
this.options.excludeByDefault = true;
|
113
|
+
|
114
|
+
angular.forEach(arguments, function (attributeName) {
|
115
|
+
inclusions[attributeName] = true;
|
192
116
|
});
|
193
117
|
|
194
|
-
return
|
195
|
-
}
|
118
|
+
return this;
|
119
|
+
};
|
196
120
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
*
|
206
|
-
* @param attributeName The current attribute name
|
207
|
-
* @returns {*} undefined if the attribute should be excluded or the mapped attribute name
|
208
|
-
*/
|
209
|
-
Serializer.prototype.getSerializedAttributeName = function (attributeName) {
|
210
|
-
var mappedName = this.serializeMappings[attributeName] || attributeName;
|
211
|
-
|
212
|
-
if (this.isExcludedFromSerialization(attributeName) || this.isExcludedFromSerialization(mappedName)) {
|
213
|
-
return undefined;
|
214
|
-
}
|
121
|
+
/**
|
122
|
+
* This is a shortcut for rename that allows you to specify a variable number of attributes that should all be renamed to
|
123
|
+
* <code>{attributeName}_attributes</code> to work with the Rails nested_attributes feature.
|
124
|
+
* @param attributeNames... {string} Variable number of attribute name parameters
|
125
|
+
* @returns {Serializer} this for chaining support
|
126
|
+
*/
|
127
|
+
Serializer.prototype.nestedAttribute = function () {
|
128
|
+
var self = this;
|
215
129
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
/**
|
220
|
-
* Determines whether or not an attribute should be excluded from deserialization.
|
221
|
-
*
|
222
|
-
* By default, we do not exclude any attributes from deserialization.
|
223
|
-
*
|
224
|
-
* @param attributeName The name of the attribute to check for exclusion
|
225
|
-
* @returns {boolean} true if excluded, false otherwise
|
226
|
-
*/
|
227
|
-
Serializer.prototype.isExcludedFromDeserialization = function (attributeName) {
|
228
|
-
return false;
|
229
|
-
};
|
230
|
-
|
231
|
-
/**
|
232
|
-
* Remaps the attribute name to the deserialized form which includes:
|
233
|
-
* - camelizing the name
|
234
|
-
* - checking for exclusion
|
235
|
-
* - remapping to a custom value specified by the rename customization function
|
236
|
-
*
|
237
|
-
* @param attributeName The current attribute name
|
238
|
-
* @returns {*} undefined if the attribute should be excluded or the mapped attribute name
|
239
|
-
*/
|
240
|
-
Serializer.prototype.getDeserializedAttributeName = function (attributeName) {
|
241
|
-
var camelizedName = this.camelize(attributeName);
|
242
|
-
|
243
|
-
camelizedName = this.deserializeMappings[attributeName]
|
244
|
-
|| this.deserializeMappings[camelizedName]
|
245
|
-
|| camelizedName;
|
246
|
-
|
247
|
-
if (this.isExcludedFromDeserialization(attributeName) || this.isExcludedFromDeserialization(camelizedName)) {
|
248
|
-
return undefined;
|
249
|
-
}
|
130
|
+
angular.forEach(arguments, function (attributeName) {
|
131
|
+
self.rename(attributeName, attributeName + '_attributes');
|
132
|
+
});
|
250
133
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
// custom serializer takes precedence over resource serializer
|
277
|
-
if (serializer) {
|
278
|
-
return RailsResourceInjector.createService(serializer)
|
279
|
-
} else if (resource) {
|
280
|
-
return resource.serializer;
|
281
|
-
}
|
134
|
+
return this;
|
135
|
+
};
|
136
|
+
|
137
|
+
/**
|
138
|
+
* Specifies an attribute that is a nested resource within the parent object.
|
139
|
+
* Nested resources do not imply nested attributes, if you want both you still have to specify call <code>nestedAttribute</code> as well.
|
140
|
+
*
|
141
|
+
* A nested resource serves two purposes. First, it defines the resource that should be used when constructing resources from the server.
|
142
|
+
* Second, it specifies how the nested object should be serialized.
|
143
|
+
*
|
144
|
+
* An optional third parameter <code>serializer</code> is available to override the serialization logic
|
145
|
+
* of the resource in case you need to serialize it differently in multiple contexts.
|
146
|
+
*
|
147
|
+
* @param attributeName {string} The name of the attribute that is a nested resource
|
148
|
+
* @param resource {string | Resource} A reference to the resource that the attribute is a type of.
|
149
|
+
* @param serializer {string | Serializer} (optional) An optional serializer reference to override the nested resource's default serializer
|
150
|
+
* @returns {Serializer} this for chaining support
|
151
|
+
*/
|
152
|
+
Serializer.prototype.resource = function (attributeName, resource, serializer) {
|
153
|
+
this.nestedResources[attributeName] = resource;
|
154
|
+
|
155
|
+
if (serializer) {
|
156
|
+
this.serializeWith(attributeName, serializer);
|
157
|
+
}
|
282
158
|
|
283
|
-
|
284
|
-
|
159
|
+
return this;
|
160
|
+
};
|
161
|
+
|
162
|
+
/**
|
163
|
+
* Specifies a custom name mapping for an attribute.
|
164
|
+
* On serializing to JSON the jsonName will be used.
|
165
|
+
* On deserialization, if jsonName is seen then it will be renamed as javascriptName in the resulting resource.
|
166
|
+
*
|
167
|
+
* @param javascriptName {string} The attribute name as it appears in the JavaScript object
|
168
|
+
* @param jsonName {string} The attribute name as it should appear in JSON
|
169
|
+
* @param bidirectional {boolean} (optional) Allows turning off the bidirectional renaming, defaults to true.
|
170
|
+
* @returns {Serializer} this for chaining support
|
171
|
+
*/
|
172
|
+
Serializer.prototype.rename = function (javascriptName, jsonName, bidirectional) {
|
173
|
+
this.serializeMappings[javascriptName] = jsonName;
|
174
|
+
|
175
|
+
if (bidirectional || bidirectional === undefined) {
|
176
|
+
this.deserializeMappings[jsonName] = javascriptName;
|
177
|
+
}
|
178
|
+
return this;
|
179
|
+
};
|
180
|
+
|
181
|
+
/**
|
182
|
+
* Allows custom attribute creation as part of the serialization to JSON.
|
183
|
+
*
|
184
|
+
* @param attributeName {string} The name of the attribute to add
|
185
|
+
* @param value {*} The value to add, if specified as a function then the function will be called during serialization
|
186
|
+
* and should return the value to add.
|
187
|
+
* @returns {Serializer} this for chaining support
|
188
|
+
*/
|
189
|
+
Serializer.prototype.add = function (attributeName, value) {
|
190
|
+
this.customSerializedAttributes[attributeName] = value;
|
191
|
+
return this;
|
192
|
+
};
|
193
|
+
|
194
|
+
|
195
|
+
/**
|
196
|
+
* Allows the attribute to be preserved unmodified in the resulting object.
|
197
|
+
*
|
198
|
+
* @param attributeName {string} The name of the attribute to add
|
199
|
+
* @returns {Serializer} this for chaining support
|
200
|
+
*/
|
201
|
+
Serializer.prototype.preserve = function(attributeName) {
|
202
|
+
this.preservedAttributes[attributeName] = true;
|
203
|
+
return this;
|
204
|
+
};
|
205
|
+
|
206
|
+
/**
|
207
|
+
* Specify a custom serializer to use for an attribute.
|
208
|
+
*
|
209
|
+
* @param attributeName {string} The name of the attribute
|
210
|
+
* @param serializer {string | constructor} A reference to the custom serializer to use for the attribute.
|
211
|
+
* @returns {Serializer} this for chaining support
|
212
|
+
*/
|
213
|
+
Serializer.prototype.serializeWith = function (attributeName, serializer) {
|
214
|
+
this.customSerializers[attributeName] = serializer;
|
215
|
+
return this;
|
216
|
+
};
|
217
|
+
|
218
|
+
/**
|
219
|
+
* Determines whether or not an attribute should be excluded.
|
220
|
+
*
|
221
|
+
* If the option excludeByDefault has been set then attributes will default to excluded and will only
|
222
|
+
* be included if they have been included using the "only" customization function.
|
223
|
+
*
|
224
|
+
* If the option excludeByDefault has not been set then attributes must be explicitly excluded using the "exclude"
|
225
|
+
* customization function or must be matched by one of the exclusionMatchers.
|
226
|
+
*
|
227
|
+
* @param attributeName The name of the attribute to check for exclusion
|
228
|
+
* @returns {boolean} true if excluded, false otherwise
|
229
|
+
*/
|
230
|
+
Serializer.prototype.isExcludedFromSerialization = function (attributeName) {
|
231
|
+
if ((this.options.excludeByDefault && !this.inclusions.hasOwnProperty(attributeName)) || this.exclusions.hasOwnProperty(attributeName)) {
|
232
|
+
return true;
|
233
|
+
}
|
285
234
|
|
235
|
+
if (this.options.exclusionMatchers) {
|
236
|
+
var excluded = false;
|
286
237
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
238
|
+
angular.forEach(this.options.exclusionMatchers, function (matcher) {
|
239
|
+
if (angular.isString(matcher)) {
|
240
|
+
excluded = excluded || attributeName.indexOf(matcher) === 0;
|
241
|
+
} else if (angular.isFunction(matcher)) {
|
242
|
+
excluded = excluded || matcher.call(undefined, attributeName);
|
243
|
+
} else if (matcher instanceof RegExp) {
|
244
|
+
excluded = excluded || matcher.test(attributeName);
|
245
|
+
}
|
246
|
+
});
|
296
247
|
|
297
|
-
|
298
|
-
|
248
|
+
return excluded;
|
249
|
+
}
|
299
250
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
251
|
+
return false;
|
252
|
+
};
|
253
|
+
|
254
|
+
/**
|
255
|
+
* Remaps the attribute name to the serialized form which includes:
|
256
|
+
* - checking for exclusion
|
257
|
+
* - remapping to a custom value specified by the rename customization function
|
258
|
+
* - underscoring the name
|
259
|
+
*
|
260
|
+
* @param attributeName The current attribute name
|
261
|
+
* @returns {*} undefined if the attribute should be excluded or the mapped attribute name
|
262
|
+
*/
|
263
|
+
Serializer.prototype.getSerializedAttributeName = function (attributeName) {
|
264
|
+
var mappedName = this.serializeMappings[attributeName] || attributeName;
|
265
|
+
|
266
|
+
if (this.isExcludedFromSerialization(attributeName) || this.isExcludedFromSerialization(mappedName)) {
|
267
|
+
return undefined;
|
306
268
|
}
|
307
|
-
result = {};
|
308
269
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
270
|
+
return this.underscore(mappedName);
|
271
|
+
};
|
272
|
+
|
273
|
+
/**
|
274
|
+
* Determines whether or not an attribute should be excluded from deserialization.
|
275
|
+
*
|
276
|
+
* By default, we do not exclude any attributes from deserialization.
|
277
|
+
*
|
278
|
+
* @param attributeName The name of the attribute to check for exclusion
|
279
|
+
* @returns {boolean} true if excluded, false otherwise
|
280
|
+
*/
|
281
|
+
Serializer.prototype.isExcludedFromDeserialization = function (attributeName) {
|
282
|
+
return false;
|
283
|
+
};
|
284
|
+
|
285
|
+
/**
|
286
|
+
* Remaps the attribute name to the deserialized form which includes:
|
287
|
+
* - camelizing the name
|
288
|
+
* - checking for exclusion
|
289
|
+
* - remapping to a custom value specified by the rename customization function
|
290
|
+
*
|
291
|
+
* @param attributeName The current attribute name
|
292
|
+
* @returns {*} undefined if the attribute should be excluded or the mapped attribute name
|
293
|
+
*/
|
294
|
+
Serializer.prototype.getDeserializedAttributeName = function (attributeName) {
|
295
|
+
var camelizedName = this.camelize(attributeName);
|
296
|
+
|
297
|
+
camelizedName = this.deserializeMappings[attributeName]
|
298
|
+
|| this.deserializeMappings[camelizedName]
|
299
|
+
|| camelizedName;
|
300
|
+
|
301
|
+
if (this.isExcludedFromDeserialization(attributeName) || this.isExcludedFromDeserialization(camelizedName)) {
|
302
|
+
return undefined;
|
303
|
+
}
|
316
304
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
305
|
+
return camelizedName;
|
306
|
+
};
|
307
|
+
|
308
|
+
/**
|
309
|
+
* Returns a reference to the nested resource that has been specified for the attribute.
|
310
|
+
* @param attributeName The attribute name
|
311
|
+
* @returns {*} undefined if no nested resource has been specified or a reference to the nested resource class
|
312
|
+
*/
|
313
|
+
Serializer.prototype.getNestedResource = function (attributeName) {
|
314
|
+
return RailsResourceInjector.getDependency(this.nestedResources[attributeName]);
|
315
|
+
};
|
316
|
+
|
317
|
+
/**
|
318
|
+
* Returns a custom serializer for the attribute if one has been specified. Custom serializers can be specified
|
319
|
+
* in one of two ways. The serializeWith customization method allows specifying a custom serializer for any attribute.
|
320
|
+
* Or an attribute could have been specified as a nested resource in which case the nested resource's serializer
|
321
|
+
* is used. Custom serializers specified using serializeWith take precedence over the nested resource serializer.
|
322
|
+
*
|
323
|
+
* @param attributeName The attribute name
|
324
|
+
* @returns {*} undefined if no custom serializer has been specified or an instance of the Serializer
|
325
|
+
*/
|
326
|
+
Serializer.prototype.getAttributeSerializer = function (attributeName) {
|
327
|
+
var resource = this.getNestedResource(attributeName),
|
328
|
+
serializer = this.customSerializers[attributeName];
|
329
|
+
|
330
|
+
// custom serializer takes precedence over resource serializer
|
331
|
+
if (serializer) {
|
332
|
+
return RailsResourceInjector.createService(serializer)
|
333
|
+
} else if (resource) {
|
334
|
+
return resource.serializer;
|
335
|
+
}
|
336
336
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
337
|
+
return undefined;
|
338
|
+
};
|
339
|
+
|
340
|
+
|
341
|
+
/**
|
342
|
+
* Prepares the data for serialization to JSON.
|
343
|
+
*
|
344
|
+
* @param data The data to prepare
|
345
|
+
* @returns {*} A new object or array that is ready for JSON serialization
|
346
|
+
*/
|
347
|
+
Serializer.prototype.serializeValue = function (data) {
|
348
|
+
var result = data,
|
349
|
+
self = this;
|
350
|
+
|
351
|
+
if (angular.isArray(data)) {
|
352
|
+
result = [];
|
353
|
+
|
354
|
+
angular.forEach(data, function (value) {
|
355
|
+
result.push(self.serializeValue(value));
|
356
|
+
});
|
357
|
+
} else if (angular.isObject(data)) {
|
358
|
+
if (angular.isDate(data)) {
|
359
|
+
return data;
|
358
360
|
}
|
361
|
+
result = {};
|
362
|
+
|
363
|
+
angular.forEach(data, function (value, key) {
|
364
|
+
// if the value is a function then it can't be serialized to JSON so we'll just skip it
|
365
|
+
if (!angular.isFunction(value)) {
|
366
|
+
self.serializeAttribute(result, key, value);
|
367
|
+
}
|
368
|
+
});
|
369
|
+
}
|
359
370
|
|
360
|
-
|
361
|
-
|
362
|
-
|
371
|
+
return result;
|
372
|
+
};
|
373
|
+
|
374
|
+
/**
|
375
|
+
* Transforms an attribute and its value and stores it on the parent data object. The attribute will be
|
376
|
+
* renamed as needed and the value itself will be serialized as well.
|
377
|
+
*
|
378
|
+
* @param data The object that the attribute will be added to
|
379
|
+
* @param attribute The attribute to transform
|
380
|
+
* @param value The current value of the attribute
|
381
|
+
*/
|
382
|
+
Serializer.prototype.serializeAttribute = function (data, attribute, value) {
|
383
|
+
var serializer = this.getAttributeSerializer(attribute),
|
384
|
+
serializedAttributeName = this.getSerializedAttributeName(attribute);
|
385
|
+
|
386
|
+
// undefined means the attribute should be excluded from serialization
|
387
|
+
if (serializedAttributeName === undefined) {
|
388
|
+
return;
|
389
|
+
}
|
363
390
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
angular.
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
391
|
+
data[serializedAttributeName] = serializer ? serializer.serialize(value) : this.serializeValue(value);
|
392
|
+
};
|
393
|
+
|
394
|
+
/**
|
395
|
+
* Serializes the data by applying various transformations such as:
|
396
|
+
* - Underscoring attribute names
|
397
|
+
* - attribute renaming
|
398
|
+
* - attribute exclusion
|
399
|
+
* - custom attribute addition
|
400
|
+
*
|
401
|
+
* @param data The data to prepare
|
402
|
+
* @returns {*} A new object or array that is ready for JSON serialization
|
403
|
+
*/
|
404
|
+
Serializer.prototype.serialize = function (data) {
|
405
|
+
var result = this.serializeValue(data),
|
406
|
+
self = this;
|
407
|
+
|
408
|
+
if (angular.isObject(result)) {
|
409
|
+
angular.forEach(this.customSerializedAttributes, function (value, key) {
|
410
|
+
if (angular.isFunction(value)) {
|
411
|
+
value = value.call(data, data);
|
412
|
+
}
|
386
413
|
|
387
|
-
|
388
|
-
|
414
|
+
self.serializeAttribute(result, key, value);
|
415
|
+
});
|
389
416
|
}
|
390
417
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
418
|
+
return result;
|
419
|
+
};
|
420
|
+
|
421
|
+
/**
|
422
|
+
* Iterates over the data deserializing each entry on arrays and each key/value on objects.
|
423
|
+
*
|
424
|
+
* @param data The object to deserialize
|
425
|
+
* @param Resource (optional) The resource type to deserialize the result into
|
426
|
+
* @returns {*} A new object or an instance of Resource populated with deserialized data.
|
427
|
+
*/
|
428
|
+
Serializer.prototype.deserializeValue = function (data, Resource) {
|
429
|
+
var result = data,
|
430
|
+
self = this;
|
431
|
+
|
432
|
+
if (angular.isArray(data)) {
|
433
|
+
result = [];
|
434
|
+
|
435
|
+
angular.forEach(data, function (value) {
|
436
|
+
result.push(self.deserializeValue(value, Resource));
|
437
|
+
});
|
438
|
+
} else if (angular.isObject(data)) {
|
439
|
+
result = {};
|
440
|
+
|
441
|
+
if (Resource) {
|
442
|
+
result = new Resource();
|
443
|
+
}
|
395
444
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
* Transforms an attribute and its value and stores it on the parent data object. The attribute will be
|
401
|
-
* renamed as needed and the value itself will be deserialized as well.
|
402
|
-
*
|
403
|
-
* @param data The object that the attribute will be added to
|
404
|
-
* @param attribute The attribute to transform
|
405
|
-
* @param value The current value of the attribute
|
406
|
-
*/
|
407
|
-
Serializer.prototype.deserializeAttribute = function (data, attribute, value) {
|
408
|
-
var serializer,
|
409
|
-
NestedResource,
|
410
|
-
attributeName = this.getDeserializedAttributeName(attribute);
|
411
|
-
|
412
|
-
// undefined means the attribute should be excluded from serialization
|
413
|
-
if (attributeName === undefined) {
|
414
|
-
return;
|
415
|
-
}
|
445
|
+
angular.forEach(data, function (value, key) {
|
446
|
+
self.deserializeAttribute(result, key, value);
|
447
|
+
});
|
448
|
+
}
|
416
449
|
|
417
|
-
|
418
|
-
|
450
|
+
return result;
|
451
|
+
};
|
452
|
+
|
453
|
+
/**
|
454
|
+
* Transforms an attribute and its value and stores it on the parent data object. The attribute will be
|
455
|
+
* renamed as needed and the value itself will be deserialized as well.
|
456
|
+
*
|
457
|
+
* @param data The object that the attribute will be added to
|
458
|
+
* @param attribute The attribute to transform
|
459
|
+
* @param value The current value of the attribute
|
460
|
+
*/
|
461
|
+
Serializer.prototype.deserializeAttribute = function (data, attribute, value) {
|
462
|
+
var serializer,
|
463
|
+
NestedResource,
|
464
|
+
attributeName = this.getDeserializedAttributeName(attribute);
|
465
|
+
|
466
|
+
// undefined means the attribute should be excluded from serialization
|
467
|
+
if (attributeName === undefined) {
|
468
|
+
return;
|
469
|
+
}
|
419
470
|
|
420
|
-
|
421
|
-
|
422
|
-
data[attributeName] = value;
|
423
|
-
} else {
|
424
|
-
data[attributeName] = serializer ? serializer.deserialize(value, NestedResource) : this.deserializeValue(value, NestedResource);
|
425
|
-
}
|
426
|
-
};
|
427
|
-
|
428
|
-
/**
|
429
|
-
* Deserializes the data by applying various transformations such as:
|
430
|
-
* - Camelizing attribute names
|
431
|
-
* - attribute renaming
|
432
|
-
* - attribute exclusion
|
433
|
-
* - nested resource creation
|
434
|
-
*
|
435
|
-
* @param data The object to deserialize
|
436
|
-
* @param Resource (optional) The resource type to deserialize the result into
|
437
|
-
* @returns {*} A new object or an instance of Resource populated with deserialized data
|
438
|
-
*/
|
439
|
-
Serializer.prototype.deserialize = function (data, Resource) {
|
440
|
-
// just calls deserializeValue for now so we can more easily add on custom attribute logic for deserialize too
|
441
|
-
return this.deserializeValue(data, Resource);
|
442
|
-
};
|
443
|
-
|
444
|
-
Serializer.prototype.pluralize = function (value) {
|
445
|
-
if (this.options.pluralize) {
|
446
|
-
return this.options.pluralize(value);
|
447
|
-
}
|
448
|
-
return value;
|
449
|
-
};
|
471
|
+
serializer = this.getAttributeSerializer(attributeName);
|
472
|
+
NestedResource = this.getNestedResource(attributeName);
|
450
473
|
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
474
|
+
// preserved attributes are assigned unmodified
|
475
|
+
if (this.preservedAttributes[attributeName]) {
|
476
|
+
data[attributeName] = value;
|
477
|
+
} else {
|
478
|
+
data[attributeName] = serializer ? serializer.deserialize(value, NestedResource) : this.deserializeValue(value, NestedResource);
|
479
|
+
}
|
480
|
+
};
|
481
|
+
|
482
|
+
/**
|
483
|
+
* Deserializes the data by applying various transformations such as:
|
484
|
+
* - Camelizing attribute names
|
485
|
+
* - attribute renaming
|
486
|
+
* - attribute exclusion
|
487
|
+
* - nested resource creation
|
488
|
+
*
|
489
|
+
* @param data The object to deserialize
|
490
|
+
* @param Resource (optional) The resource type to deserialize the result into
|
491
|
+
* @returns {*} A new object or an instance of Resource populated with deserialized data
|
492
|
+
*/
|
493
|
+
Serializer.prototype.deserialize = function (data, Resource) {
|
494
|
+
// just calls deserializeValue for now so we can more easily add on custom attribute logic for deserialize too
|
495
|
+
return this.deserializeValue(data, Resource);
|
496
|
+
};
|
497
|
+
|
498
|
+
Serializer.prototype.pluralize = function (value) {
|
499
|
+
if (this.options.pluralize) {
|
500
|
+
return this.options.pluralize(value);
|
501
|
+
}
|
502
|
+
return value;
|
503
|
+
};
|
504
|
+
|
505
|
+
Serializer.prototype.underscore = function (value) {
|
506
|
+
if (this.options.underscore) {
|
507
|
+
return this.options.underscore(value);
|
508
|
+
}
|
509
|
+
return value;
|
510
|
+
};
|
457
511
|
|
458
|
-
|
459
|
-
|
460
|
-
|
512
|
+
Serializer.prototype.camelize = function (value) {
|
513
|
+
if (this.options.camelize) {
|
514
|
+
return this.options.camelize(value);
|
515
|
+
}
|
516
|
+
return value;
|
461
517
|
}
|
462
|
-
return value;
|
463
|
-
}
|
464
518
|
|
465
|
-
|
466
|
-
|
519
|
+
return Serializer;
|
520
|
+
}
|
467
521
|
|
468
|
-
|
469
|
-
|
470
|
-
|
522
|
+
railsSerializer.defaultOptions = defaultOptions;
|
523
|
+
return railsSerializer;
|
524
|
+
}];
|
525
|
+
});
|
471
526
|
}());
|