ember-data-source 1.0.0.beta.1 → 1.0.0.beta.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 49a8abeac26b84118c0106e9e494759469b7fb6d
4
- data.tar.gz: d43a9c9df58de30ce5ae8a097d37f350aa9bc1c4
3
+ metadata.gz: 3ab50c82ea065fb1d9eb982e0fde381caa4184de
4
+ data.tar.gz: 4f52807164f630f58e6144e3a11bc41e09b2c26c
5
5
  SHA512:
6
- metadata.gz: a5ab28522f356d624f719a3d03a829963f546d7da1109be23e743df25ae6109f51ced2a374973da26bb8f74ae2a81d21ac3204f55dc0874bffe87d00259f8c29
7
- data.tar.gz: 718c1b74121a1362aeda3a351635a9c3ec5361ff5a212b8c110122f43c15f12ce5d96d230bc4c37ef2f9bf4c2a9b6c544ae109067d63b15d8f2f35b3227bd2d2
6
+ metadata.gz: 483401b7507bc40fc841672dbf04d3cad28886cae33f342957bb77bfe0ab654d53d0ec21869da0426aa15907c8a028a65e7aa7a14fcea999644287fb50ce3111
7
+ data.tar.gz: b4a40bc1be9f8fcc995b2e5a99710ce824dad66b345f9cfd5f16e82687f3a99bf84971817e88565ef7473843ac4e80066e0cbb1f89a968c00d2d5607f6e76dbf
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0-beta.1
1
+ 1.0.0-beta.2
@@ -1,5 +1,5 @@
1
- // Version: v1.0.0-beta.1
2
- // Last commit: e9489ab (2013-09-01 00:38:13 -0700)
1
+ // Version: v1.0.0-beta.2
2
+ // Last commit: d1158e2 (2013-09-04 16:03:06 -0700)
3
3
 
4
4
 
5
5
  (function() {
@@ -41,249 +41,6 @@ var define, requireModule;
41
41
  return seen[name] = exports || value;
42
42
  };
43
43
  })();
44
- (function() {
45
- Ember.String.pluralize = function(word) {
46
- return Ember.Inflector.inflector.pluralize(word);
47
- };
48
-
49
- Ember.String.singularize = function(word) {
50
- return Ember.Inflector.inflector.singularize(word);
51
- };
52
-
53
- })();
54
-
55
-
56
-
57
- (function() {
58
- var BLANK_REGEX = /^\s*$/;
59
-
60
- function loadUncountable(rules, uncountable) {
61
- for (var i = 0, length = uncountable.length; i < length; i++) {
62
- rules.uncountable[uncountable[i]] = true;
63
- }
64
- }
65
-
66
- function loadIrregular(rules, irregularPairs) {
67
- var pair;
68
-
69
- for (var i = 0, length = irregularPairs.length; i < length; i++) {
70
- pair = irregularPairs[i];
71
-
72
- rules.irregular[pair[0]] = pair[1];
73
- rules.irregularInverse[pair[1]] = pair[0];
74
- }
75
- }
76
-
77
- function Inflector(ruleSet) {
78
- ruleSet = ruleSet || {};
79
- ruleSet.uncountable = ruleSet.uncountable || {};
80
- ruleSet.irregularPairs= ruleSet.irregularPairs|| {};
81
-
82
- var rules = this.rules = {
83
- plurals: ruleSet.plurals || [],
84
- singular: ruleSet.singular || [],
85
- irregular: {},
86
- irregularInverse: {},
87
- uncountable: {}
88
- };
89
-
90
- loadUncountable(rules, ruleSet.uncountable);
91
- loadIrregular(rules, ruleSet.irregularPairs);
92
- }
93
-
94
- Inflector.prototype = {
95
- pluralize: function(word) {
96
- return this.inflect(word, this.rules.plurals);
97
- },
98
-
99
- singularize: function(word) {
100
- return this.inflect(word, this.rules.singular);
101
- },
102
-
103
- inflect: function(word, typeRules) {
104
- var inflection, substitution, result, lowercase, isBlank,
105
- isUncountable, isIrregular, isIrregularInverse, rule;
106
-
107
- isBlank = BLANK_REGEX.test(word);
108
-
109
- if (isBlank) {
110
- return word;
111
- }
112
-
113
- lowercase = word.toLowerCase();
114
-
115
- isUncountable = this.rules.uncountable[lowercase];
116
-
117
- if (isUncountable) {
118
- return word;
119
- }
120
-
121
- isIrregular = this.rules.irregular[lowercase];
122
-
123
- if (isIrregular) {
124
- return isIrregular;
125
- }
126
-
127
- isIrregularInverse = this.rules.irregularInverse[lowercase];
128
-
129
- if (isIrregularInverse) {
130
- return isIrregularInverse;
131
- }
132
-
133
- for (var i = typeRules.length, min = 0; i > min; i--) {
134
- inflection = typeRules[i-1];
135
- rule = inflection[0];
136
-
137
- if (rule.test(word)) {
138
- break;
139
- }
140
- }
141
-
142
- inflection = inflection || [];
143
-
144
- rule = inflection[0];
145
- substitution = inflection[1];
146
-
147
- result = word.replace(rule, substitution);
148
-
149
- return result;
150
- }
151
- };
152
-
153
- Ember.Inflector = Inflector;
154
-
155
- })();
156
-
157
-
158
-
159
- (function() {
160
- Ember.Inflector.defaultRules = {
161
- plurals: [
162
- [/$/, 's'],
163
- [/s$/i, 's'],
164
- [/^(ax|test)is$/i, '$1es'],
165
- [/(octop|vir)us$/i, '$1i'],
166
- [/(octop|vir)i$/i, '$1i'],
167
- [/(alias|status)$/i, '$1es'],
168
- [/(bu)s$/i, '$1ses'],
169
- [/(buffal|tomat)o$/i, '$1oes'],
170
- [/([ti])um$/i, '$1a'],
171
- [/([ti])a$/i, '$1a'],
172
- [/sis$/i, 'ses'],
173
- [/(?:([^f])fe|([lr])f)$/i, '$1$2ves'],
174
- [/(hive)$/i, '$1s'],
175
- [/([^aeiouy]|qu)y$/i, '$1ies'],
176
- [/(x|ch|ss|sh)$/i, '$1es'],
177
- [/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'],
178
- [/^(m|l)ouse$/i, '$1ice'],
179
- [/^(m|l)ice$/i, '$1ice'],
180
- [/^(ox)$/i, '$1en'],
181
- [/^(oxen)$/i, '$1'],
182
- [/(quiz)$/i, '$1zes']
183
- ],
184
-
185
- singular: [
186
- [/s$/i, ''],
187
- [/(ss)$/i, '$1'],
188
- [/(n)ews$/i, '$1ews'],
189
- [/([ti])a$/i, '$1um'],
190
- [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '$1sis'],
191
- [/(^analy)(sis|ses)$/i, '$1sis'],
192
- [/([^f])ves$/i, '$1fe'],
193
- [/(hive)s$/i, '$1'],
194
- [/(tive)s$/i, '$1'],
195
- [/([lr])ves$/i, '$1f'],
196
- [/([^aeiouy]|qu)ies$/i, '$1y'],
197
- [/(s)eries$/i, '$1eries'],
198
- [/(m)ovies$/i, '$1ovie'],
199
- [/(x|ch|ss|sh)es$/i, '$1'],
200
- [/^(m|l)ice$/i, '$1ouse'],
201
- [/(bus)(es)?$/i, '$1'],
202
- [/(o)es$/i, '$1'],
203
- [/(shoe)s$/i, '$1'],
204
- [/(cris|test)(is|es)$/i, '$1is'],
205
- [/^(a)x[ie]s$/i, '$1xis'],
206
- [/(octop|vir)(us|i)$/i, '$1us'],
207
- [/(alias|status)(es)?$/i, '$1'],
208
- [/^(ox)en/i, '$1'],
209
- [/(vert|ind)ices$/i, '$1ex'],
210
- [/(matr)ices$/i, '$1ix'],
211
- [/(quiz)zes$/i, '$1'],
212
- [/(database)s$/i, '$1']
213
- ],
214
-
215
- irregularPairs: [
216
- ['person', 'people'],
217
- ['man', 'men'],
218
- ['child', 'children'],
219
- ['sex', 'sexes'],
220
- ['move', 'moves'],
221
- ['cow', 'kine'],
222
- ['zombie', 'zombies']
223
- ],
224
-
225
- uncountable: [
226
- 'equipment',
227
- 'information',
228
- 'rice',
229
- 'money',
230
- 'species',
231
- 'series',
232
- 'fish',
233
- 'sheep',
234
- 'jeans',
235
- 'police'
236
- ]
237
- };
238
-
239
- })();
240
-
241
-
242
-
243
- (function() {
244
- if (Ember.EXTEND_PROTOTYPES) {
245
- /**
246
- See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}}
247
-
248
- @method pluralize
249
- @for String
250
- */
251
- String.prototype.pluralize = function() {
252
- return Ember.String.pluralize(this);
253
- };
254
-
255
- /**
256
- See {{#crossLink "Ember.String/singularize"}}{{/crossLink}}
257
-
258
- @method singularize
259
- @for String
260
- */
261
- String.prototype.singularize = function() {
262
- return Ember.String.singularize(this);
263
- };
264
- }
265
-
266
- })();
267
-
268
-
269
-
270
- (function() {
271
- Ember.Inflector.inflector = new Ember.Inflector(Ember.Inflector.defaultRules);
272
-
273
- })();
274
-
275
-
276
-
277
- (function() {
278
-
279
- })();
280
-
281
-
282
- })();
283
- // Version: v1.0.0-beta.1
284
- // Last commit: e9489ab (2013-09-01 00:38:13 -0700)
285
-
286
-
287
44
  (function() {
288
45
  /**
289
46
  @module ember-data
@@ -309,120 +66,9 @@ if ('undefined' === typeof DS) {
309
66
 
310
67
 
311
68
 
312
- (function() {
313
- /**
314
- @module ember-data
315
- */
316
-
317
- var isNone = Ember.isNone, isEmpty = Ember.isEmpty;
318
-
319
- /**
320
- DS.JSONTransforms is a hash of transforms used by DS.Serializer.
321
-
322
- @class JSONTransforms
323
- @static
324
- @namespace DS
325
- */
326
- DS.JSONTransforms = {
327
- string: {
328
- deserialize: function(serialized) {
329
- return isNone(serialized) ? null : String(serialized);
330
- },
331
-
332
- serialize: function(deserialized) {
333
- return isNone(deserialized) ? null : String(deserialized);
334
- }
335
- },
336
-
337
- number: {
338
- deserialize: function(serialized) {
339
- return isEmpty(serialized) ? null : Number(serialized);
340
- },
341
-
342
- serialize: function(deserialized) {
343
- return isEmpty(deserialized) ? null : Number(deserialized);
344
- }
345
- },
346
-
347
- // Handles the following boolean inputs:
348
- // "TrUe", "t", "f", "FALSE", 0, (non-zero), or boolean true/false
349
- 'boolean': {
350
- deserialize: function(serialized) {
351
- var type = typeof serialized;
352
-
353
- if (type === "boolean") {
354
- return serialized;
355
- } else if (type === "string") {
356
- return serialized.match(/^true$|^t$|^1$/i) !== null;
357
- } else if (type === "number") {
358
- return serialized === 1;
359
- } else {
360
- return false;
361
- }
362
- },
363
-
364
- serialize: function(deserialized) {
365
- return Boolean(deserialized);
366
- }
367
- },
368
-
369
- date: {
370
- deserialize: function(serialized) {
371
- var type = typeof serialized;
372
-
373
- if (type === "string") {
374
- return new Date(Ember.Date.parse(serialized));
375
- } else if (type === "number") {
376
- return new Date(serialized);
377
- } else if (serialized === null || serialized === undefined) {
378
- // if the value is not present in the data,
379
- // return undefined, not null.
380
- return serialized;
381
- } else {
382
- return null;
383
- }
384
- },
385
-
386
- serialize: function(date) {
387
- if (date instanceof Date) {
388
- var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
389
- var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
390
-
391
- var pad = function(num) {
392
- return num < 10 ? "0"+num : ""+num;
393
- };
394
-
395
- var utcYear = date.getUTCFullYear(),
396
- utcMonth = date.getUTCMonth(),
397
- utcDayOfMonth = date.getUTCDate(),
398
- utcDay = date.getUTCDay(),
399
- utcHours = date.getUTCHours(),
400
- utcMinutes = date.getUTCMinutes(),
401
- utcSeconds = date.getUTCSeconds();
402
-
403
-
404
- var dayOfWeek = days[utcDay];
405
- var dayOfMonth = pad(utcDayOfMonth);
406
- var month = months[utcMonth];
407
-
408
- return dayOfWeek + ", " + dayOfMonth + " " + month + " " + utcYear + " " +
409
- pad(utcHours) + ":" + pad(utcMinutes) + ":" + pad(utcSeconds) + " GMT";
410
- } else {
411
- return null;
412
- }
413
- }
414
- }
415
- };
416
-
417
- })();
418
-
419
-
420
-
421
69
  (function() {
422
70
  var get = Ember.get, set = Ember.set, isNone = Ember.isNone;
423
71
 
424
- var transforms = DS.JSONTransforms;
425
-
426
72
  // Simple dispatcher to support overriding the aliased
427
73
  // method in subclasses.
428
74
  function aliasMethod(methodName) {
@@ -434,55 +80,20 @@ function aliasMethod(methodName) {
434
80
  DS.JSONSerializer = Ember.Object.extend({
435
81
  primaryKey: 'id',
436
82
 
437
- deserialize: function(type, data) {
438
- var store = get(this, 'store');
439
-
83
+ applyTransforms: function(type, data) {
440
84
  type.eachTransformedAttribute(function(key, type) {
441
- data[key] = transforms[type].deserialize(data[key]);
442
- });
443
-
444
- type.eachRelationship(function(key, relationship) {
445
- // A link (usually a URL) was already provided in
446
- // normalized form
447
- if (data.links && data.links[key]) {
448
- return;
449
- }
450
-
451
- var type = relationship.type,
452
- value = data[key];
453
-
454
- if (value == null) { return; }
455
-
456
- if (relationship.kind === 'belongsTo') {
457
- this.deserializeRecordId(data, key, relationship, value);
458
- } else if (relationship.kind === 'hasMany') {
459
- this.deserializeRecordIds(data, key, relationship, value);
460
- }
85
+ var transform = this.transformFor(type);
86
+ data[key] = transform.deserialize(data[key]);
461
87
  }, this);
462
88
 
463
89
  return data;
464
90
  },
465
91
 
466
- deserializeRecordId: function(data, key, relationship, id) {
467
- if (isNone(id) || id instanceof DS.Model) {
468
- return;
469
- }
470
-
471
- var type;
92
+ normalize: function(type, hash) {
93
+ if (!hash) { return hash; }
472
94
 
473
- if (typeof id === 'number' || typeof id === 'string') {
474
- type = this.typeFor(relationship, key, data);
475
- data[key] = get(this, 'store').recordForId(type, id);
476
- } else if (typeof id === 'object') {
477
- // polymorphic
478
- data[key] = get(this, 'store').recordForId(id.type, id.id);
479
- }
480
- },
481
-
482
- deserializeRecordIds: function(data, key, relationship, ids) {
483
- for (var i=0, l=ids.length; i<l; i++) {
484
- this.deserializeRecordId(ids, i, relationship, ids[i]);
485
- }
95
+ this.applyTransforms(type, hash);
96
+ return hash;
486
97
  },
487
98
 
488
99
  // SERIALIZE
@@ -500,20 +111,8 @@ DS.JSONSerializer = Ember.Object.extend({
500
111
  }
501
112
  }
502
113
 
503
- var attrs = get(this, 'attrs');
504
-
505
114
  record.eachAttribute(function(key, attribute) {
506
- var value = get(record, key), type = attribute.type;
507
-
508
- if (type) {
509
- value = transforms[type].serialize(value);
510
- }
511
-
512
- // if provided, use the mapping provided by `attrs` in
513
- // the serializer
514
- key = attrs && attrs[key] || key;
515
-
516
- json[key] = value;
115
+ this.serializeAttribute(record, json, key, attribute);
517
116
  }, this);
518
117
 
519
118
  record.eachRelationship(function(key, relationship) {
@@ -527,6 +126,22 @@ DS.JSONSerializer = Ember.Object.extend({
527
126
  return json;
528
127
  },
529
128
 
129
+ serializeAttribute: function(record, json, key, attribute) {
130
+ var attrs = get(this, 'attrs');
131
+ var value = get(record, key), type = attribute.type;
132
+
133
+ if (type) {
134
+ var transform = this.transformFor(type);
135
+ value = transform.serialize(value);
136
+ }
137
+
138
+ // if provided, use the mapping provided by `attrs` in
139
+ // the serializer
140
+ key = attrs && attrs[key] || key;
141
+
142
+ json[key] = value;
143
+ },
144
+
530
145
  serializeBelongsTo: function(record, json, relationship) {
531
146
  var key = relationship.key;
532
147
 
@@ -541,11 +156,22 @@ DS.JSONSerializer = Ember.Object.extend({
541
156
  }
542
157
  },
543
158
 
544
- serializeHasMany: Ember.K,
159
+ serializeHasMany: function(record, json, relationship) {
160
+ var key = relationship.key;
161
+
162
+ var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
163
+
164
+ if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') {
165
+ json[key] = get(record, key).mapBy('id');
166
+ // TODO support for polymorphic manyToNone and manyToMany relationships
167
+ }
168
+ },
545
169
 
546
170
  // EXTRACT
547
171
 
548
172
  extract: function(store, type, payload, id, requestType) {
173
+ this.extractMeta(store, type, payload);
174
+
549
175
  var specificExtract = "extract" + requestType.charAt(0).toUpperCase() + requestType.substr(1);
550
176
  return this[specificExtract](store, type, payload, id, requestType);
551
177
  },
@@ -563,12 +189,20 @@ DS.JSONSerializer = Ember.Object.extend({
563
189
  extractSave: aliasMethod('extractSingle'),
564
190
 
565
191
  extractSingle: function(store, type, payload) {
566
- return payload;
192
+ return this.normalize(type, payload);
567
193
  },
568
194
 
569
195
  extractArray: function(store, type, payload) {
570
- return payload;
196
+ return this.normalize(type, payload);
571
197
  },
198
+
199
+ extractMeta: function(store, type, payload) {
200
+ if (payload && payload.meta) {
201
+ store.metaForType(type, payload.meta);
202
+ delete payload.meta;
203
+ }
204
+ },
205
+
572
206
  // HELPERS
573
207
 
574
208
  typeFor: function(relationship, key, data) {
@@ -579,8 +213,8 @@ DS.JSONSerializer = Ember.Object.extend({
579
213
  }
580
214
  },
581
215
 
582
- eachEmbeddedRecord: function() {
583
- // this is used by transaction.add
216
+ transformFor: function(attributeType) {
217
+ return this.container.lookup('transform:' + attributeType);
584
218
  }
585
219
  });
586
220
 
@@ -698,6 +332,139 @@ DS.DebugAdapter = Ember.DataAdapter.extend({
698
332
 
699
333
 
700
334
 
335
+ (function() {
336
+ DS.Transform = Ember.Object.extend({
337
+
338
+ serialize: Ember.required(),
339
+
340
+ deserialize: Ember.required()
341
+
342
+ });
343
+ })();
344
+
345
+
346
+
347
+ (function() {
348
+
349
+ DS.BooleanTransform = DS.Transform.extend({
350
+ deserialize: function(serialized) {
351
+ var type = typeof serialized;
352
+
353
+ if (type === "boolean") {
354
+ return serialized;
355
+ } else if (type === "string") {
356
+ return serialized.match(/^true$|^t$|^1$/i) !== null;
357
+ } else if (type === "number") {
358
+ return serialized === 1;
359
+ } else {
360
+ return false;
361
+ }
362
+ },
363
+
364
+ serialize: function(deserialized) {
365
+ return Boolean(deserialized);
366
+ }
367
+ });
368
+
369
+ })();
370
+
371
+
372
+
373
+ (function() {
374
+ DS.DateTransform = DS.Transform.extend({
375
+
376
+ deserialize: function(serialized) {
377
+ var type = typeof serialized;
378
+
379
+ if (type === "string") {
380
+ return new Date(Ember.Date.parse(serialized));
381
+ } else if (type === "number") {
382
+ return new Date(serialized);
383
+ } else if (serialized === null || serialized === undefined) {
384
+ // if the value is not present in the data,
385
+ // return undefined, not null.
386
+ return serialized;
387
+ } else {
388
+ return null;
389
+ }
390
+ },
391
+
392
+ serialize: function(date) {
393
+ if (date instanceof Date) {
394
+ var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
395
+ var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
396
+
397
+ var pad = function(num) {
398
+ return num < 10 ? "0"+num : ""+num;
399
+ };
400
+
401
+ var utcYear = date.getUTCFullYear(),
402
+ utcMonth = date.getUTCMonth(),
403
+ utcDayOfMonth = date.getUTCDate(),
404
+ utcDay = date.getUTCDay(),
405
+ utcHours = date.getUTCHours(),
406
+ utcMinutes = date.getUTCMinutes(),
407
+ utcSeconds = date.getUTCSeconds();
408
+
409
+
410
+ var dayOfWeek = days[utcDay];
411
+ var dayOfMonth = pad(utcDayOfMonth);
412
+ var month = months[utcMonth];
413
+
414
+ return dayOfWeek + ", " + dayOfMonth + " " + month + " " + utcYear + " " +
415
+ pad(utcHours) + ":" + pad(utcMinutes) + ":" + pad(utcSeconds) + " GMT";
416
+ } else {
417
+ return null;
418
+ }
419
+ }
420
+
421
+ });
422
+
423
+ })();
424
+
425
+
426
+
427
+ (function() {
428
+ var empty = Ember.isEmpty;
429
+
430
+ DS.NumberTransform = DS.Transform.extend({
431
+
432
+ deserialize: function(serialized) {
433
+ return empty(serialized) ? null : Number(serialized);
434
+ },
435
+
436
+ serialize: function(deserialized) {
437
+ return empty(deserialized) ? null : Number(deserialized);
438
+ }
439
+ });
440
+ })();
441
+
442
+
443
+
444
+ (function() {
445
+ var none = Ember.isNone, empty = Ember.isEmpty;
446
+
447
+ DS.StringTransform = DS.Transform.extend({
448
+
449
+ deserialize: function(serialized) {
450
+ return none(serialized) ? null : String(serialized);
451
+ },
452
+
453
+ serialize: function(deserialized) {
454
+ return none(deserialized) ? null : String(deserialized);
455
+ }
456
+
457
+ });
458
+ })();
459
+
460
+
461
+
462
+ (function() {
463
+
464
+ })();
465
+
466
+
467
+
701
468
  (function() {
702
469
  /**
703
470
  @module ember-data
@@ -718,7 +485,7 @@ var set = Ember.set;
718
485
  For example, imagine an Ember.js application with the following classes:
719
486
 
720
487
  App.Store = DS.Store.extend({
721
- adapter: 'App.MyCustomAdapter'
488
+ adapter: 'custom'
722
489
  });
723
490
 
724
491
  App.PostsController = Ember.ArrayController.extend({
@@ -751,17 +518,16 @@ Ember.onLoad('Ember.Application', function(Application) {
751
518
  }
752
519
  });
753
520
 
754
- // Keep ED compatible with previous versions of ember
755
- // TODO: Remove the if statement for Ember 1.0
756
- if (DS.DebugAdapter) {
757
- Application.initializer({
758
- name: "dataAdapter",
521
+ Application.initializer({
522
+ name: "transforms",
759
523
 
760
- initialize: function(container, application) {
761
- application.register('dataAdapter:main', DS.DebugAdapter);
762
- }
763
- });
764
- }
524
+ initialize: function(container, application) {
525
+ application.register('transform:boolean', DS.BooleanTransform);
526
+ application.register('transform:date', DS.DateTransform);
527
+ application.register('transform:number', DS.NumberTransform);
528
+ application.register('transform:string', DS.StringTransform);
529
+ }
530
+ });
765
531
 
766
532
  Application.initializer({
767
533
  name: "dataAdapter",
@@ -1209,6 +975,7 @@ DS.ManyArray = DS.RecordArray.extend({
1209
975
  */
1210
976
 
1211
977
  var get = Ember.get;
978
+ var forEach = Ember.ArrayPolyfills.forEach;
1212
979
 
1213
980
  var resolveMapConflict = function(oldValue, newValue) {
1214
981
  return oldValue;
@@ -1304,7 +1071,7 @@ DS._Mappable = Ember.Mixin.create({
1304
1071
 
1305
1072
  var classMap = classMeta[mapName];
1306
1073
  if (classMap) {
1307
- classMap.forEach(eachMap, this);
1074
+ forEach.call(classMap, eachMap, this);
1308
1075
  }
1309
1076
 
1310
1077
  function eachMap(key, value) {
@@ -1322,7 +1089,6 @@ DS._Mappable = Ember.Mixin.create({
1322
1089
  }
1323
1090
  }
1324
1091
 
1325
-
1326
1092
  });
1327
1093
 
1328
1094
  DS._Mappable.generateMapFunctionFor = function(mapName, transform) {
@@ -1501,12 +1267,15 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
1501
1267
  This property is cacheable, so the same instance of a specified
1502
1268
  adapter class should be used for the lifetime of the store.
1503
1269
 
1504
- @property _adapter
1270
+ @property defaultAdapter
1505
1271
  @private
1506
1272
  @returns DS.Adapter
1507
1273
  */
1508
- _adapter: Ember.computed(function() {
1274
+ defaultAdapter: Ember.computed(function() {
1509
1275
  var adapter = get(this, 'adapter');
1276
+
1277
+ Ember.assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name or a factory', !(adapter instanceof DS.Adapter));
1278
+
1510
1279
  if (typeof adapter === 'string') {
1511
1280
  adapter = this.container.lookup('adapter:' + adapter) || this.container.lookup('adapter:application') || this.container.lookup('adapter:_rest');
1512
1281
  }
@@ -1878,19 +1647,20 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
1878
1647
  var unloadedRecords = records.filterProperty('isEmpty', true),
1879
1648
  manyArray = this.recordArrayManager.createManyArray(type, records);
1880
1649
 
1881
- unloadedRecords.forEach(function(record) {
1650
+ forEach(unloadedRecords, function(record) {
1882
1651
  record.loadingData();
1883
1652
  });
1884
1653
 
1885
1654
  manyArray.loadingRecordsCount = unloadedRecords.length;
1886
1655
 
1887
1656
  if (unloadedRecords.length) {
1888
- unloadedRecords.forEach(function(record) {
1657
+ forEach(unloadedRecords, function(record) {
1889
1658
  this.recordArrayManager.registerWaitingRecordArray(record, manyArray);
1890
1659
  }, this);
1891
1660
 
1892
1661
  this.fetchMany(unloadedRecords, owner, resolver);
1893
1662
  } else {
1663
+ if (resolver) { resolver.resolve(); }
1894
1664
  manyArray.set('isLoaded', true);
1895
1665
  Ember.run.once(manyArray, 'trigger', 'didLoad');
1896
1666
  }
@@ -2027,6 +1797,8 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
2027
1797
  @return {DS.RecordArray}
2028
1798
  */
2029
1799
  all: function(type) {
1800
+ type = this.modelFor(type);
1801
+
2030
1802
  var typeMap = this.typeMapFor(type),
2031
1803
  findAllCache = typeMap.findAllCache;
2032
1804
 
@@ -2308,14 +2080,15 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
2308
2080
  @method _load
2309
2081
  @private
2310
2082
  @param {DS.Model} type
2311
- @param data
2312
- @param prematerialized
2083
+ @param {Object} data
2084
+ @param {Boolean} partial the data should be merged into
2085
+ the existing fata, not replace it.
2313
2086
  */
2314
- _load: function(type, data) {
2087
+ _load: function(type, data, partial) {
2315
2088
  var id = coerceId(data.id),
2316
2089
  record = this.recordForId(type, id);
2317
2090
 
2318
- record.setupData(data);
2091
+ record.setupData(data, partial);
2319
2092
  this.recordArrayManager.recordDidChange(record);
2320
2093
 
2321
2094
  return record;
@@ -2405,17 +2178,26 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
2405
2178
  @returns DS.Model the record that was created or
2406
2179
  updated.
2407
2180
  */
2408
- push: function(type, data) {
2181
+ push: function(type, data, _partial) {
2182
+ // _partial is an internal param used by `update`.
2183
+ // If passed, it means that the data should be
2184
+ // merged into the existing data, not replace it.
2185
+
2409
2186
  var serializer = this.serializerFor(type);
2410
2187
  type = this.modelFor(type);
2411
2188
 
2412
- data = serializer.deserialize(type, data);
2189
+ // normalize relationship IDs into records
2190
+ data = normalizeRelationships(this, type, data);
2413
2191
 
2414
- this._load(type, data);
2192
+ this._load(type, data, _partial);
2415
2193
 
2416
2194
  return this.recordForId(type, data.id);
2417
2195
  },
2418
2196
 
2197
+ update: function(type, data) {
2198
+ return this.push(type, data, true);
2199
+ },
2200
+
2419
2201
  /**
2420
2202
  If you have an Array of normalized data to push,
2421
2203
  you can call `pushMany` with the Array, and it will
@@ -2432,6 +2214,20 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
2432
2214
  }, this);
2433
2215
  },
2434
2216
 
2217
+ /**
2218
+ If you have some metadata to set for a type
2219
+ you can call `metaForType`.
2220
+
2221
+ @method metaForType
2222
+ @param {String} type
2223
+ @param {Object} metadata
2224
+ */
2225
+ metaForType: function(type, metadata) {
2226
+ type = this.modelFor(type);
2227
+
2228
+ Ember.merge(this.typeMapFor(type).metadata, metadata);
2229
+ },
2230
+
2435
2231
  /**
2436
2232
  Build a brand new record for a given type, ID, and
2437
2233
  initial data.
@@ -2566,7 +2362,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
2566
2362
  adapter = container.lookup('adapter:' + type.typeKey) || container.lookup('adapter:application');
2567
2363
  }
2568
2364
 
2569
- return adapter || get(this, '_adapter');
2365
+ return adapter || get(this, 'defaultAdapter');
2570
2366
  },
2571
2367
 
2572
2368
  // ..............................
@@ -2590,19 +2386,65 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
2590
2386
  @param {String} type the record to serialize
2591
2387
  */
2592
2388
  serializerFor: function(type) {
2593
- var container = this.container;
2389
+ type = this.modelFor(type);
2390
+ var adapter = this.adapterForType(type);
2391
+
2392
+ return serializerFor(this.container, type.typeKey, adapter && adapter.defaultSerializer);
2393
+ }
2394
+ });
2395
+
2396
+ function normalizeRelationships(store, type, data) {
2397
+ type.eachRelationship(function(key, relationship) {
2398
+ // A link (usually a URL) was already provided in
2399
+ // normalized form
2400
+ if (data.links && data.links[key]) {
2401
+ return;
2402
+ }
2594
2403
 
2595
- // TODO: Make tests pass without this
2404
+ var type = relationship.type,
2405
+ value = data[key];
2596
2406
 
2597
- if (!container) {
2598
- return DS.JSONSerializer.create({ store: this });
2407
+ if (value == null) { return; }
2408
+
2409
+ if (relationship.kind === 'belongsTo') {
2410
+ deserializeRecordId(store, data, key, relationship, value);
2411
+ } else if (relationship.kind === 'hasMany') {
2412
+ deserializeRecordIds(store, data, key, relationship, value);
2599
2413
  }
2414
+ });
2600
2415
 
2601
- return container.lookup('serializer:'+type) ||
2602
- container.lookup('serializer:application') ||
2603
- container.lookup('serializer:_default');
2416
+ return data;
2417
+ }
2418
+
2419
+ function deserializeRecordId(store, data, key, relationship, id) {
2420
+ if (isNone(id) || id instanceof DS.Model) {
2421
+ return;
2604
2422
  }
2605
- });
2423
+
2424
+ var type;
2425
+
2426
+ if (typeof id === 'number' || typeof id === 'string') {
2427
+ type = typeFor(relationship, key, data);
2428
+ data[key] = store.recordForId(type, id);
2429
+ } else if (typeof id === 'object') {
2430
+ // polymorphic
2431
+ data[key] = store.recordForId(id.type, id.id);
2432
+ }
2433
+ }
2434
+
2435
+ function typeFor(relationship, key, data) {
2436
+ if (relationship.options.polymorphic) {
2437
+ return data[key + "_type"];
2438
+ } else {
2439
+ return relationship.type;
2440
+ }
2441
+ }
2442
+
2443
+ function deserializeRecordIds(store, data, key, relationship, ids) {
2444
+ for (var i=0, l=ids.length; i<l; i++) {
2445
+ deserializeRecordId(store, ids, i, relationship, ids[i]);
2446
+ }
2447
+ }
2606
2448
 
2607
2449
  // Delegation to the adapter and promise management
2608
2450
 
@@ -2621,15 +2463,20 @@ function isThenable(object) {
2621
2463
  return object && typeof object.then === 'function';
2622
2464
  }
2623
2465
 
2624
- function serializerFor(adapter, type) {
2466
+ function serializerFor(container, type, defaultSerializer) {
2467
+ return container.lookup('serializer:'+type) ||
2468
+ container.lookup('serializer:application') ||
2469
+ container.lookup('serializer:' + defaultSerializer) ||
2470
+ container.lookup('serializer:_default');
2471
+ }
2472
+
2473
+ function serializerForAdapter(adapter, type) {
2625
2474
  var serializer = adapter.serializer,
2626
2475
  defaultSerializer = adapter.defaultSerializer,
2627
2476
  container = adapter.container;
2628
2477
 
2629
2478
  if (container && serializer === undefined) {
2630
- serializer = container.lookup('serializer:'+type.typeKey) ||
2631
- container.lookup('serializer:application') ||
2632
- container.lookup('serializer:' + defaultSerializer || 'serializer:_default');
2479
+ serializer = serializerFor(container, type.typeKey, defaultSerializer);
2633
2480
  }
2634
2481
 
2635
2482
  if (serializer === null || serializer === undefined) {
@@ -2643,7 +2490,7 @@ function serializerFor(adapter, type) {
2643
2490
 
2644
2491
  function _find(adapter, store, type, id, resolver) {
2645
2492
  var promise = adapter.find(store, type, id),
2646
- serializer = serializerFor(adapter, type);
2493
+ serializer = serializerForAdapter(adapter, type);
2647
2494
 
2648
2495
  return resolve(promise).then(function(payload) {
2649
2496
  Ember.assert("You made a request for a " + type.typeKey + " with id " + id + ", but the adapter's response did not have any data", payload);
@@ -2655,7 +2502,7 @@ function _find(adapter, store, type, id, resolver) {
2655
2502
 
2656
2503
  function _findMany(adapter, store, type, ids, owner, resolver) {
2657
2504
  var promise = adapter.findMany(store, type, ids, owner),
2658
- serializer = serializerFor(adapter, type);
2505
+ serializer = serializerForAdapter(adapter, type);
2659
2506
 
2660
2507
  return resolve(promise).then(function(payload) {
2661
2508
  payload = serializer.extract(store, type, payload, null, 'findMany');
@@ -2666,7 +2513,7 @@ function _findMany(adapter, store, type, ids, owner, resolver) {
2666
2513
 
2667
2514
  function _findHasMany(adapter, store, record, link, relationship, resolver) {
2668
2515
  var promise = adapter.findHasMany(store, record, link, relationship),
2669
- serializer = serializerFor(adapter, relationship.type);
2516
+ serializer = serializerForAdapter(adapter, relationship.type);
2670
2517
 
2671
2518
  return resolve(promise).then(function(payload) {
2672
2519
  payload = serializer.extract(store, relationship.type, payload, null, 'findHasMany');
@@ -2678,7 +2525,7 @@ function _findHasMany(adapter, store, record, link, relationship, resolver) {
2678
2525
 
2679
2526
  function _findAll(adapter, store, type, sinceToken, resolver) {
2680
2527
  var promise = adapter.findAll(store, type, sinceToken),
2681
- serializer = serializerFor(adapter, type);
2528
+ serializer = serializerForAdapter(adapter, type);
2682
2529
 
2683
2530
  return resolve(promise).then(function(payload) {
2684
2531
  payload = serializer.extract(store, type, payload, null, 'findAll');
@@ -2691,7 +2538,7 @@ function _findAll(adapter, store, type, sinceToken, resolver) {
2691
2538
 
2692
2539
  function _findQuery(adapter, store, type, query, recordArray, resolver) {
2693
2540
  var promise = adapter.findQuery(store, type, query, recordArray),
2694
- serializer = serializerFor(adapter, type);
2541
+ serializer = serializerForAdapter(adapter, type);
2695
2542
 
2696
2543
  return resolve(promise).then(function(payload) {
2697
2544
  payload = serializer.extract(store, type, payload, null, 'findAll');
@@ -2704,7 +2551,7 @@ function _findQuery(adapter, store, type, query, recordArray, resolver) {
2704
2551
  function _commit(adapter, store, operation, record, resolver) {
2705
2552
  var type = record.constructor,
2706
2553
  promise = adapter[operation](store, type, record),
2707
- serializer = serializerFor(adapter, type);
2554
+ serializer = serializerForAdapter(adapter, type);
2708
2555
 
2709
2556
  Ember.assert("Your adapter's '" + operation + "' method must return a promise, but it returned " + promise, isThenable(promise));
2710
2557
 
@@ -2978,7 +2825,7 @@ var DirtyState = {
2978
2825
  get(record, 'store').reloadRecord(record, resolver);
2979
2826
  },
2980
2827
 
2981
- becameClean: function(record) {
2828
+ rolledBack: function(record) {
2982
2829
  record.transitionTo('loaded.saved');
2983
2830
  },
2984
2831
 
@@ -3108,6 +2955,10 @@ var createdState = dirtyState({
3108
2955
  isNew: true
3109
2956
  });
3110
2957
 
2958
+ createdState.uncommitted.rolledBack = function(record) {
2959
+ record.transitionTo('deleted.saved');
2960
+ };
2961
+
3111
2962
  var updatedState = dirtyState({
3112
2963
  dirtyType: 'updated'
3113
2964
  });
@@ -3138,6 +2989,14 @@ var RootState = {
3138
2989
  isNew: false,
3139
2990
  isValid: true,
3140
2991
 
2992
+ // DEFAULT EVENTS
2993
+
2994
+ // Trying to roll back if you're not in the dirty state
2995
+ // doesn't change your state. For example, if you're in the
2996
+ // in-flight state, rolling back the record doesn't move
2997
+ // you out of the in-flight state.
2998
+ rolledBack: Ember.K,
2999
+
3141
3000
  // SUBSTATES
3142
3001
 
3143
3002
  // A record begins its lifecycle in the `empty` state.
@@ -3301,7 +3160,7 @@ var RootState = {
3301
3160
  becomeDirty: Ember.K,
3302
3161
  deleteRecord: Ember.K,
3303
3162
 
3304
- becameClean: function(record) {
3163
+ rolledBack: function(record) {
3305
3164
  record.transitionTo('loaded.saved');
3306
3165
  }
3307
3166
  },
@@ -3322,6 +3181,11 @@ var RootState = {
3322
3181
  record.transitionTo('saved');
3323
3182
 
3324
3183
  record.send('invokeLifecycleCallbacks');
3184
+ },
3185
+
3186
+ becameError: function(record) {
3187
+ record.transitionTo('uncommitted');
3188
+ record.triggerLater('becameError', record);
3325
3189
  }
3326
3190
  },
3327
3191
 
@@ -3701,8 +3565,18 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
3701
3565
  Ember.run.once(this, this.updateRecordArrays);
3702
3566
  },
3703
3567
 
3704
- setupData: function(data) {
3705
- this._data = data;
3568
+ setupData: function(data, partial) {
3569
+ if (partial) {
3570
+ Ember.merge(this._data, data);
3571
+ } else {
3572
+ this._data = data;
3573
+ }
3574
+
3575
+ var relationships = this._relationships;
3576
+
3577
+ this.eachRelationship(function(name, rel) {
3578
+ if (rel.options.async) { relationships[name] = null; }
3579
+ });
3706
3580
 
3707
3581
  if (data) { this.pushedData(); }
3708
3582
 
@@ -3730,8 +3604,8 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
3730
3604
  },
3731
3605
 
3732
3606
  rollback: function() {
3733
- this._setup();
3734
- this.send('becameClean');
3607
+ this._attributes = {};
3608
+ this.send('rolledBack');
3735
3609
 
3736
3610
  this.suspendRelationshipObservers(function() {
3737
3611
  this.notifyPropertyChange('data');
@@ -3962,21 +3836,48 @@ DS.Model.reopen({
3962
3836
  }
3963
3837
  });
3964
3838
 
3965
- function getAttr(record, options, key) {
3966
- var attributes = get(record, 'data');
3967
- var value = attributes[key];
3968
-
3969
- if (value === undefined) {
3970
- if (typeof options.defaultValue === "function") {
3971
- value = options.defaultValue();
3972
- } else {
3973
- value = options.defaultValue;
3974
- }
3839
+ function getDefaultValue(record, options, key) {
3840
+ if (typeof options.defaultValue === "function") {
3841
+ return options.defaultValue();
3842
+ } else {
3843
+ return options.defaultValue;
3975
3844
  }
3845
+ }
3976
3846
 
3977
- return value;
3847
+ function hasValue(record, key) {
3848
+ return record._attributes.hasOwnProperty(key) ||
3849
+ record._inFlightAttributes.hasOwnProperty(key) ||
3850
+ record._data.hasOwnProperty(key);
3851
+ }
3852
+
3853
+ function getValue(record, key) {
3854
+ if (record._attributes.hasOwnProperty(key)) {
3855
+ return record._attributes[key];
3856
+ } else if (record._inFlightAttributes.hasOwnProperty(key)) {
3857
+ return record._inFlightAttributes[key];
3858
+ } else {
3859
+ return record._data[key];
3860
+ }
3978
3861
  }
3979
3862
 
3863
+ /**
3864
+ `DS.attr` defines an attribute on a DS.Model.
3865
+ By default, attributes are passed through as-is, however you can specify an
3866
+ optional type to have the value automatically transformed.
3867
+ Ember Data ships with four basic transform types:
3868
+ 'string', 'number', 'boolean' and 'date'.
3869
+ You can define your own transforms by subclassing DS.Transform.
3870
+
3871
+ DS.attr takes an optional hash as a second parameter, currently
3872
+ supported options are:
3873
+ 'defaultValue': Pass a string or a function to be called to set the attribute
3874
+ to a default value if none is supplied.
3875
+
3876
+ @method attr
3877
+ @param {String} type the attribute type
3878
+ @param {Object} options a hash of options
3879
+ */
3880
+
3980
3881
  DS.attr = function(type, options) {
3981
3882
  options = options || {};
3982
3883
 
@@ -3987,17 +3888,19 @@ DS.attr = function(type, options) {
3987
3888
  };
3988
3889
 
3989
3890
  return Ember.computed(function(key, value, oldValue) {
3891
+ var currentValue;
3892
+
3990
3893
  if (arguments.length > 1) {
3991
3894
  Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('<type>')` from " + this.constructor.toString(), key !== 'id');
3992
3895
  this.send('didSetProperty', { name: key, oldValue: this._attributes[key] || this._inFlightAttributes[key] || this._data[key], value: value });
3993
3896
  this._attributes[key] = value;
3994
- } else if (this._attributes[key]) {
3995
- return this._attributes[key];
3897
+ return value;
3898
+ } else if (hasValue(this, key)) {
3899
+ return getValue(this, key);
3996
3900
  } else {
3997
- value = getAttr(this, options, key);
3901
+ return getDefaultValue(this, options, key);
3998
3902
  }
3999
3903
 
4000
- return value;
4001
3904
  // `data` is never set directly. However, it may be
4002
3905
  // invalidated from the state manager's setData
4003
3906
  // event.
@@ -4542,14 +4445,21 @@ var get = Ember.get, set = Ember.set,
4542
4445
  function asyncBelongsTo(type, options, meta) {
4543
4446
  return Ember.computed(function(key, value) {
4544
4447
  var data = get(this, 'data'),
4545
- store = get(this, 'store');
4448
+ store = get(this, 'store'),
4449
+ belongsTo;
4546
4450
 
4547
4451
  if (arguments.length === 2) {
4548
- Ember.assert("You can only add a '" + type + "' record to this relationship", !value || store.modelFor(type).detectInstance(value));
4452
+ Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof store.modelFor(type));
4549
4453
  return value === undefined ? null : value;
4550
4454
  }
4551
4455
 
4552
- return store.fetchRecord(data[key]);
4456
+ belongsTo = data[key];
4457
+
4458
+ if(!isNone(belongsTo) && get(belongsTo, 'isEmpty')) {
4459
+ return store.fetchRecord(belongsTo);
4460
+ } else {
4461
+ return null;
4462
+ }
4553
4463
  }).property('data').meta(meta);
4554
4464
  }
4555
4465
 
@@ -4579,7 +4489,7 @@ DS.belongsTo = function(type, options) {
4579
4489
  }
4580
4490
 
4581
4491
  if (arguments.length === 2) {
4582
- Ember.assert("You can only add a '" + type + "' record to this relationship", !value || typeClass.detectInstance(value));
4492
+ Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof typeClass);
4583
4493
  return value === undefined ? null : value;
4584
4494
  }
4585
4495
 
@@ -5376,7 +5286,7 @@ DS.RecordArrayManager = Ember.Object.extend({
5376
5286
  */
5377
5287
 
5378
5288
  var get = Ember.get, set = Ember.set, merge = Ember.merge;
5379
- var forEach = Ember.EnumerableUtils.forEach;
5289
+ var map = Ember.ArrayPolyfills.map;
5380
5290
  var resolve = Ember.RSVP.resolve;
5381
5291
 
5382
5292
  var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
@@ -5441,7 +5351,7 @@ function aliasMethod(methodName) {
5441
5351
  * `deleteRecords()`
5442
5352
  * `commit()`
5443
5353
 
5444
- For an example implementation, see `DS.RestAdapter`, the
5354
+ For an example implementation, see `DS.RESTAdapter`, the
5445
5355
  included REST adapter.
5446
5356
 
5447
5357
  @class Adapter
@@ -5589,7 +5499,7 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
5589
5499
  @property {Array} ids
5590
5500
  */
5591
5501
  findMany: function(store, type, ids) {
5592
- var promises = ids.map(function(id) {
5502
+ var promises = map.call(ids, function(id) {
5593
5503
  return this.find(store, type, id);
5594
5504
  }, this);
5595
5505
 
@@ -5712,7 +5622,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
5712
5622
  var fixtures = this.fixturesForType(type),
5713
5623
  fixture;
5714
5624
 
5715
- Ember.warn("Unable to find fixtures for model type " + type.toString(), fixtures);
5625
+ Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures);
5716
5626
 
5717
5627
  if (fixtures) {
5718
5628
  fixture = Ember.A(fixtures).findProperty('id', id);
@@ -5734,7 +5644,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
5734
5644
  findMany: function(store, type, ids) {
5735
5645
  var fixtures = this.fixturesForType(type);
5736
5646
 
5737
- Ember.assert("Unable to find fixtures for model type "+type.toString(), !!fixtures);
5647
+ Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures);
5738
5648
 
5739
5649
  if (fixtures) {
5740
5650
  fixtures = fixtures.filter(function(item) {
@@ -5757,7 +5667,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
5757
5667
  findAll: function(store, type) {
5758
5668
  var fixtures = this.fixturesForType(type);
5759
5669
 
5760
- Ember.assert("Unable to find fixtures for model type "+type.toString(), !!fixtures);
5670
+ Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures);
5761
5671
 
5762
5672
  return this.simulateRemoteCall(function() {
5763
5673
  return fixtures;
@@ -5774,7 +5684,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
5774
5684
  findQuery: function(store, type, query, array) {
5775
5685
  var fixtures = this.fixturesForType(type);
5776
5686
 
5777
- Ember.assert("Unable to find fixtures for model type "+type.toString(), !!fixtures);
5687
+ Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures);
5778
5688
 
5779
5689
  fixtures = this.queryFixtures(fixtures, query, type);
5780
5690
 
@@ -5914,17 +5824,48 @@ DS.FixtureAdapter = DS.Adapter.extend({
5914
5824
  */
5915
5825
 
5916
5826
  var get = Ember.get, set = Ember.set;
5917
-
5918
- DS.rejectionHandler = function(reason) {
5919
- Ember.Logger.assert([reason, reason.message, reason.stack]);
5920
-
5921
- throw reason;
5922
- };
5827
+ var forEach = Ember.ArrayPolyfills.forEach;
5923
5828
 
5924
5829
  function coerceId(id) {
5925
5830
  return id == null ? null : id+'';
5926
5831
  }
5927
5832
 
5833
+ /**
5834
+ Normally, applications will use the `RESTSerializer` by implementing
5835
+ the `normalize` method and individual normalizations under
5836
+ `normalizeHash`.
5837
+
5838
+ This allows you to do whatever kind of munging you need, and is
5839
+ especially useful if your server is inconsistent and you need to
5840
+ do munging differently for many different kinds of responses.
5841
+
5842
+ See the `normalize` documentation for more information.
5843
+
5844
+ ## Across the Board Normalization
5845
+
5846
+ There are also a number of hooks that you might find useful to defined
5847
+ across-the-board rules for your payload. These rules will be useful
5848
+ if your server is consistent, or if you're building an adapter for
5849
+ an infrastructure service, like Parse, and want to encode service
5850
+ conventions.
5851
+
5852
+ For example, if all of your keys are underscored and all-caps, but
5853
+ otherwise consistent with the names you use in your models, you
5854
+ can implement across-the-board rules for how to convert an attribute
5855
+ name in your model to a key in your JSON.
5856
+
5857
+ ```js
5858
+ App.ApplicationSerializer = DS.RESTSerializer.extend({
5859
+ keyForAttribute: function(attr) {
5860
+ return Ember.String.underscore(attr).toUpperCase();
5861
+ }
5862
+ });
5863
+ ```
5864
+
5865
+ You can also implement `keyForRelationship`, which takes the name
5866
+ of the relationship as the first parameter, and the kind of
5867
+ relationship (`hasMany` or `belongsTo`) as the second parameter.
5868
+ */
5928
5869
  DS.RESTSerializer = DS.JSONSerializer.extend({
5929
5870
  /**
5930
5871
  Normalizes a part of the JSON payload returned by
@@ -5990,15 +5931,17 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
5990
5931
  @param {Object} hash
5991
5932
  @returns Object
5992
5933
  */
5993
- normalize: function(type, prop, hash) {
5934
+ normalize: function(type, hash, prop) {
5994
5935
  this.normalizeId(hash);
5995
- this.normalizeAttributes(hash);
5936
+ this.normalizeUsingDeclaredMapping(type, hash);
5937
+ this.normalizeAttributes(type, hash);
5938
+ this.normalizeRelationships(type, hash);
5996
5939
 
5997
5940
  if (this.normalizeHash && this.normalizeHash[prop]) {
5998
5941
  return this.normalizeHash[prop](hash);
5999
5942
  }
6000
5943
 
6001
- return hash;
5944
+ return this._super(type, hash, prop);
6002
5945
  },
6003
5946
 
6004
5947
  /**
@@ -6014,20 +5957,56 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
6014
5957
  delete hash[primaryKey];
6015
5958
  },
6016
5959
 
5960
+ /**
5961
+ @method normalizeUsingDeclaredMapping
5962
+ @private
5963
+ */
5964
+ normalizeUsingDeclaredMapping: function(type, hash) {
5965
+ var attrs = get(this, 'attrs'), payloadKey, key;
5966
+
5967
+ if (attrs) {
5968
+ for (key in attrs) {
5969
+ payloadKey = attrs[key];
5970
+
5971
+ hash[key] = hash[payloadKey];
5972
+ delete hash[payloadKey];
5973
+ }
5974
+ }
5975
+ },
5976
+
6017
5977
  /**
6018
5978
  @method normalizeAttributes
6019
5979
  @private
6020
5980
  */
6021
- normalizeAttributes: function(hash) {
6022
- var attrs = get(this, 'attrs');
5981
+ normalizeAttributes: function(type, hash) {
5982
+ var payloadKey, key;
5983
+
5984
+ if (this.keyForAttribute) {
5985
+ type.eachAttribute(function(key) {
5986
+ payloadKey = this.keyForAttribute(key);
5987
+ if (key === payloadKey) { return; }
5988
+
5989
+ hash[key] = hash[payloadKey];
5990
+ delete hash[payloadKey];
5991
+ }, this);
5992
+ }
5993
+ },
6023
5994
 
6024
- if (!attrs) { return; }
5995
+ /**
5996
+ @method normalizeRelationships
5997
+ @private
5998
+ */
5999
+ normalizeRelationships: function(type, hash) {
6000
+ var payloadKey, key;
6025
6001
 
6026
- for (var key in attrs) {
6027
- var payloadKey = attrs[key];
6002
+ if (this.keyForRelationship) {
6003
+ type.eachRelationship(function(key, relationship) {
6004
+ payloadKey = this.keyForRelationship(key, relationship.kind);
6005
+ if (key === payloadKey) { return; }
6028
6006
 
6029
- hash[key] = hash[payloadKey];
6030
- delete hash[payloadKey];
6007
+ hash[key] = hash[payloadKey];
6008
+ delete hash[payloadKey];
6009
+ }, this);
6031
6010
  }
6032
6011
  },
6033
6012
 
@@ -6114,7 +6093,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
6114
6093
  for (var prop in payload) {
6115
6094
  // legacy support for singular names
6116
6095
  if (prop === primaryTypeName) {
6117
- primaryRecord = this.normalize(primaryType, prop, payload[prop]);
6096
+ primaryRecord = this.normalize(primaryType, payload[prop], prop);
6118
6097
  continue;
6119
6098
  }
6120
6099
 
@@ -6122,8 +6101,8 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
6122
6101
  type = store.modelFor(typeName);
6123
6102
 
6124
6103
  /*jshint loopfunc:true*/
6125
- payload[prop].forEach(function(hash) {
6126
- hash = this.normalize(type, prop, hash);
6104
+ forEach.call(payload[prop], function(hash) {
6105
+ hash = this.normalize(type, hash, prop);
6127
6106
 
6128
6107
  var isFirstCreatedRecord = typeName === primaryTypeName && !recordId && !primaryRecord,
6129
6108
  isUpdatedRecord = typeName === primaryTypeName && coerceId(hash.id) === recordId;
@@ -6251,7 +6230,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
6251
6230
 
6252
6231
  /*jshint loopfunc:true*/
6253
6232
  var normalizedArray = payload[prop].map(function(hash) {
6254
- return this.normalize(type, prop, hash);
6233
+ return this.normalize(type, hash, prop);
6255
6234
  }, this);
6256
6235
 
6257
6236
  if (isPrimary) {
@@ -6427,6 +6406,18 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
6427
6406
  }
6428
6407
  });
6429
6408
 
6409
+ })();
6410
+
6411
+
6412
+
6413
+ (function() {
6414
+ /**
6415
+ @module ember-data
6416
+ */
6417
+
6418
+ var get = Ember.get, set = Ember.set;
6419
+ var forEach = Ember.ArrayPolyfills.forEach;
6420
+
6430
6421
  /**
6431
6422
  The REST adapter allows your store to communicate with an HTTP server by
6432
6423
  transmitting JSON via XHR. Most Ember.js apps that consume a JSON API
@@ -6498,11 +6489,11 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
6498
6489
 
6499
6490
  ### Host customization
6500
6491
 
6501
- An adapter can target other hosts by setting the `url` property.
6492
+ An adapter can target other hosts by setting the `host` property.
6502
6493
 
6503
6494
  ```js
6504
6495
  DS.RESTAdapter.reopen({
6505
- url: 'https://api.example.com'
6496
+ host: 'https://api.example.com'
6506
6497
  });
6507
6498
  ```
6508
6499
 
@@ -6544,7 +6535,7 @@ DS.RESTAdapter = DS.Adapter.extend({
6544
6535
  @returns Promise
6545
6536
  */
6546
6537
  find: function(store, type, id) {
6547
- return this.ajax(this.buildURL(type, id), 'GET');
6538
+ return this.ajax(this.buildURL(type.typeKey, id), 'GET');
6548
6539
  },
6549
6540
 
6550
6541
  /**
@@ -6559,10 +6550,17 @@ DS.RESTAdapter = DS.Adapter.extend({
6559
6550
  @see RESTAdapter/ajax
6560
6551
  @param {DS.Store} store
6561
6552
  @param {subclass of DS.Model} type
6553
+ @param {String} sinceToken
6562
6554
  @returns Promise
6563
6555
  */
6564
- findAll: function(store, type) {
6565
- return this.ajax(this.buildURL(type), 'GET');
6556
+ findAll: function(store, type, sinceToken) {
6557
+ var query;
6558
+
6559
+ if (sinceToken) {
6560
+ query = { since: sinceToken };
6561
+ }
6562
+
6563
+ return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query });
6566
6564
  },
6567
6565
 
6568
6566
  /**
@@ -6584,7 +6582,7 @@ DS.RESTAdapter = DS.Adapter.extend({
6584
6582
  @returns Promise
6585
6583
  */
6586
6584
  findQuery: function(store, type, query) {
6587
- return this.ajax(this.buildURL(type), 'GET', query);
6585
+ return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query });
6588
6586
  },
6589
6587
 
6590
6588
  /**
@@ -6623,8 +6621,8 @@ DS.RESTAdapter = DS.Adapter.extend({
6623
6621
  @param {Array<String>} ids
6624
6622
  @returns Promise
6625
6623
  */
6626
- findMany: function(store, type, ids) {
6627
- return this.ajax(this.buildURL(type), 'GET', { ids: ids });
6624
+ findMany: function(store, type, ids, owner) {
6625
+ return this.ajax(this.buildURL(type.typeKey), 'GET', { data: { ids: ids } });
6628
6626
  },
6629
6627
 
6630
6628
  /**
@@ -6680,9 +6678,9 @@ DS.RESTAdapter = DS.Adapter.extend({
6680
6678
  */
6681
6679
  createRecord: function(store, type, record) {
6682
6680
  var data = {};
6683
- data[type.typeKey] = this.serializerFor(type.typeKey).serialize(record, { includeId: true });
6681
+ data[type.typeKey] = store.serializerFor(type.typeKey).serialize(record, { includeId: true });
6684
6682
 
6685
- return this.ajax(this.buildURL(type), "POST", { data: data });
6683
+ return this.ajax(this.buildURL(type.typeKey), "POST", { data: data });
6686
6684
  },
6687
6685
 
6688
6686
  /**
@@ -6704,11 +6702,11 @@ DS.RESTAdapter = DS.Adapter.extend({
6704
6702
  */
6705
6703
  updateRecord: function(store, type, record) {
6706
6704
  var data = {};
6707
- data[type.typeKey] = this.serializerFor(type.typeKey).serialize(record);
6705
+ data[type.typeKey] = store.serializerFor(type.typeKey).serialize(record);
6708
6706
 
6709
6707
  var id = get(record, 'id');
6710
6708
 
6711
- return this.ajax(this.buildURL(type, id), "PUT", { data: data });
6709
+ return this.ajax(this.buildURL(type.typeKey, id), "PUT", { data: data });
6712
6710
  },
6713
6711
 
6714
6712
  /**
@@ -6728,38 +6726,65 @@ DS.RESTAdapter = DS.Adapter.extend({
6728
6726
  deleteRecord: function(store, type, record) {
6729
6727
  var id = get(record, 'id');
6730
6728
 
6731
- return this.ajax(this.buildURL(type, id), "DELETE");
6729
+ return this.ajax(this.buildURL(type.typeKey, id), "DELETE");
6730
+ },
6731
+
6732
+ /**
6733
+ Builds a URL for a given type and optional ID.
6734
+
6735
+ If an ID is specified, it adds the ID to the root generated
6736
+ for the type, separated by a `/`.
6737
+
6738
+ @method buildURL
6739
+ @param {String} type
6740
+ @param {String} id
6741
+ @returns String
6742
+ */
6743
+ buildURL: function(type, id) {
6744
+ var host = get(this, 'host'),
6745
+ namespace = get(this, 'namespace'),
6746
+ url = [];
6747
+
6748
+ if (host) { url.push(host); }
6749
+ if (namespace) { url.push(namespace); }
6750
+
6751
+ url.push(this.rootForType(type));
6752
+ if (id) { url.push(id); }
6753
+
6754
+ url = url.join('/');
6755
+ if (!host) { url = '/' + url; }
6756
+
6757
+ return url;
6732
6758
  },
6733
6759
 
6734
6760
  /**
6735
- Builds a URL for a given type and optional ID.
6761
+ Determines the pathname root for a given type.
6736
6762
 
6737
6763
  By default, it pluralizes the type's name (for example,
6738
6764
  'post' becomes 'posts' and 'person' becomes 'people').
6739
6765
 
6740
- If an ID is specified, it adds the ID to the plural form
6741
- of the type, separated by a `/`.
6766
+ ### Pathname root customization
6742
6767
 
6743
- @method buildURL
6744
- @param {subclass of DS.Model} type
6745
- @param {String} id
6746
- @returns String
6747
- */
6748
- buildURL: function(type, id) {
6749
- var url = "/" + Ember.String.pluralize(type.typeKey);
6750
- if (id) { url += "/" + id; }
6768
+ For example if you have an object LineItem with an
6769
+ endpoint of "/line_items/".
6751
6770
 
6752
- return url;
6753
- },
6771
+ ```js
6772
+ DS.RESTAdapter.reopen({
6773
+ rootForType: function(type) {
6774
+ var decamelized = Ember.String.decamelize(type);
6775
+ return Ember.String.pluralize(decamelized);
6776
+ };
6777
+ });
6778
+ ```
6754
6779
 
6755
- serializerFor: function(type) {
6756
- // This logic has to be kept in sync with DS.Store#serializerFor
6757
- return this.container.lookup('serializer:' + type) ||
6758
- this.container.lookup('serializer:application') ||
6759
- this.container.lookup('serializer:_rest');
6780
+ @method rootForType
6781
+ @param {String} type
6782
+ @returns String
6783
+ **/
6784
+ rootForType: function(type) {
6785
+ return Ember.String.pluralize(type);
6760
6786
  },
6761
6787
 
6762
-
6763
6788
  /**
6764
6789
  Takes a URL, an HTTP method and a hash of data, and makes an
6765
6790
  HTTP request.
@@ -6801,7 +6826,7 @@ DS.RESTAdapter = DS.Adapter.extend({
6801
6826
  if (adapter.headers !== undefined) {
6802
6827
  var headers = adapter.headers;
6803
6828
  hash.beforeSend = function (xhr) {
6804
- Ember.keys(headers).forEach(function(key) {
6829
+ forEach.call(Ember.keys(headers), function(key) {
6805
6830
  xhr.setRequestHeader(key, headers[key]);
6806
6831
  });
6807
6832
  };
@@ -6945,3 +6970,242 @@ DS.Model.reopen({
6945
6970
 
6946
6971
  })();
6947
6972
 
6973
+ (function() {
6974
+ Ember.String.pluralize = function(word) {
6975
+ return Ember.Inflector.inflector.pluralize(word);
6976
+ };
6977
+
6978
+ Ember.String.singularize = function(word) {
6979
+ return Ember.Inflector.inflector.singularize(word);
6980
+ };
6981
+
6982
+ })();
6983
+
6984
+
6985
+
6986
+ (function() {
6987
+ var BLANK_REGEX = /^\s*$/;
6988
+
6989
+ function loadUncountable(rules, uncountable) {
6990
+ for (var i = 0, length = uncountable.length; i < length; i++) {
6991
+ rules.uncountable[uncountable[i]] = true;
6992
+ }
6993
+ }
6994
+
6995
+ function loadIrregular(rules, irregularPairs) {
6996
+ var pair;
6997
+
6998
+ for (var i = 0, length = irregularPairs.length; i < length; i++) {
6999
+ pair = irregularPairs[i];
7000
+
7001
+ rules.irregular[pair[0]] = pair[1];
7002
+ rules.irregularInverse[pair[1]] = pair[0];
7003
+ }
7004
+ }
7005
+
7006
+ function Inflector(ruleSet) {
7007
+ ruleSet = ruleSet || {};
7008
+ ruleSet.uncountable = ruleSet.uncountable || {};
7009
+ ruleSet.irregularPairs= ruleSet.irregularPairs|| {};
7010
+
7011
+ var rules = this.rules = {
7012
+ plurals: ruleSet.plurals || [],
7013
+ singular: ruleSet.singular || [],
7014
+ irregular: {},
7015
+ irregularInverse: {},
7016
+ uncountable: {}
7017
+ };
7018
+
7019
+ loadUncountable(rules, ruleSet.uncountable);
7020
+ loadIrregular(rules, ruleSet.irregularPairs);
7021
+ }
7022
+
7023
+ Inflector.prototype = {
7024
+ pluralize: function(word) {
7025
+ return this.inflect(word, this.rules.plurals);
7026
+ },
7027
+
7028
+ singularize: function(word) {
7029
+ return this.inflect(word, this.rules.singular);
7030
+ },
7031
+
7032
+ inflect: function(word, typeRules) {
7033
+ var inflection, substitution, result, lowercase, isBlank,
7034
+ isUncountable, isIrregular, isIrregularInverse, rule;
7035
+
7036
+ isBlank = BLANK_REGEX.test(word);
7037
+
7038
+ if (isBlank) {
7039
+ return word;
7040
+ }
7041
+
7042
+ lowercase = word.toLowerCase();
7043
+
7044
+ isUncountable = this.rules.uncountable[lowercase];
7045
+
7046
+ if (isUncountable) {
7047
+ return word;
7048
+ }
7049
+
7050
+ isIrregular = this.rules.irregular[lowercase];
7051
+
7052
+ if (isIrregular) {
7053
+ return isIrregular;
7054
+ }
7055
+
7056
+ isIrregularInverse = this.rules.irregularInverse[lowercase];
7057
+
7058
+ if (isIrregularInverse) {
7059
+ return isIrregularInverse;
7060
+ }
7061
+
7062
+ for (var i = typeRules.length, min = 0; i > min; i--) {
7063
+ inflection = typeRules[i-1];
7064
+ rule = inflection[0];
7065
+
7066
+ if (rule.test(word)) {
7067
+ break;
7068
+ }
7069
+ }
7070
+
7071
+ inflection = inflection || [];
7072
+
7073
+ rule = inflection[0];
7074
+ substitution = inflection[1];
7075
+
7076
+ result = word.replace(rule, substitution);
7077
+
7078
+ return result;
7079
+ }
7080
+ };
7081
+
7082
+ Ember.Inflector = Inflector;
7083
+
7084
+ })();
7085
+
7086
+
7087
+
7088
+ (function() {
7089
+ Ember.Inflector.defaultRules = {
7090
+ plurals: [
7091
+ [/$/, 's'],
7092
+ [/s$/i, 's'],
7093
+ [/^(ax|test)is$/i, '$1es'],
7094
+ [/(octop|vir)us$/i, '$1i'],
7095
+ [/(octop|vir)i$/i, '$1i'],
7096
+ [/(alias|status)$/i, '$1es'],
7097
+ [/(bu)s$/i, '$1ses'],
7098
+ [/(buffal|tomat)o$/i, '$1oes'],
7099
+ [/([ti])um$/i, '$1a'],
7100
+ [/([ti])a$/i, '$1a'],
7101
+ [/sis$/i, 'ses'],
7102
+ [/(?:([^f])fe|([lr])f)$/i, '$1$2ves'],
7103
+ [/(hive)$/i, '$1s'],
7104
+ [/([^aeiouy]|qu)y$/i, '$1ies'],
7105
+ [/(x|ch|ss|sh)$/i, '$1es'],
7106
+ [/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'],
7107
+ [/^(m|l)ouse$/i, '$1ice'],
7108
+ [/^(m|l)ice$/i, '$1ice'],
7109
+ [/^(ox)$/i, '$1en'],
7110
+ [/^(oxen)$/i, '$1'],
7111
+ [/(quiz)$/i, '$1zes']
7112
+ ],
7113
+
7114
+ singular: [
7115
+ [/s$/i, ''],
7116
+ [/(ss)$/i, '$1'],
7117
+ [/(n)ews$/i, '$1ews'],
7118
+ [/([ti])a$/i, '$1um'],
7119
+ [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '$1sis'],
7120
+ [/(^analy)(sis|ses)$/i, '$1sis'],
7121
+ [/([^f])ves$/i, '$1fe'],
7122
+ [/(hive)s$/i, '$1'],
7123
+ [/(tive)s$/i, '$1'],
7124
+ [/([lr])ves$/i, '$1f'],
7125
+ [/([^aeiouy]|qu)ies$/i, '$1y'],
7126
+ [/(s)eries$/i, '$1eries'],
7127
+ [/(m)ovies$/i, '$1ovie'],
7128
+ [/(x|ch|ss|sh)es$/i, '$1'],
7129
+ [/^(m|l)ice$/i, '$1ouse'],
7130
+ [/(bus)(es)?$/i, '$1'],
7131
+ [/(o)es$/i, '$1'],
7132
+ [/(shoe)s$/i, '$1'],
7133
+ [/(cris|test)(is|es)$/i, '$1is'],
7134
+ [/^(a)x[ie]s$/i, '$1xis'],
7135
+ [/(octop|vir)(us|i)$/i, '$1us'],
7136
+ [/(alias|status)(es)?$/i, '$1'],
7137
+ [/^(ox)en/i, '$1'],
7138
+ [/(vert|ind)ices$/i, '$1ex'],
7139
+ [/(matr)ices$/i, '$1ix'],
7140
+ [/(quiz)zes$/i, '$1'],
7141
+ [/(database)s$/i, '$1']
7142
+ ],
7143
+
7144
+ irregularPairs: [
7145
+ ['person', 'people'],
7146
+ ['man', 'men'],
7147
+ ['child', 'children'],
7148
+ ['sex', 'sexes'],
7149
+ ['move', 'moves'],
7150
+ ['cow', 'kine'],
7151
+ ['zombie', 'zombies']
7152
+ ],
7153
+
7154
+ uncountable: [
7155
+ 'equipment',
7156
+ 'information',
7157
+ 'rice',
7158
+ 'money',
7159
+ 'species',
7160
+ 'series',
7161
+ 'fish',
7162
+ 'sheep',
7163
+ 'jeans',
7164
+ 'police'
7165
+ ]
7166
+ };
7167
+
7168
+ })();
7169
+
7170
+
7171
+
7172
+ (function() {
7173
+ if (Ember.EXTEND_PROTOTYPES) {
7174
+ /**
7175
+ See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}}
7176
+
7177
+ @method pluralize
7178
+ @for String
7179
+ */
7180
+ String.prototype.pluralize = function() {
7181
+ return Ember.String.pluralize(this);
7182
+ };
7183
+
7184
+ /**
7185
+ See {{#crossLink "Ember.String/singularize"}}{{/crossLink}}
7186
+
7187
+ @method singularize
7188
+ @for String
7189
+ */
7190
+ String.prototype.singularize = function() {
7191
+ return Ember.String.singularize(this);
7192
+ };
7193
+ }
7194
+
7195
+ })();
7196
+
7197
+
7198
+
7199
+ (function() {
7200
+ Ember.Inflector.inflector = new Ember.Inflector(Ember.Inflector.defaultRules);
7201
+
7202
+ })();
7203
+
7204
+
7205
+
7206
+ (function() {
7207
+
7208
+ })();
7209
+
7210
+
7211
+ })();