ende 0.4.18 → 0.4.19

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.
Files changed (24) hide show
  1. checksums.yaml +4 -4
  2. data/lib/assets/javascripts/aura/extensions/widget/lifecycleable.js.coffee +1 -0
  3. data/lib/assets/javascripts/aura/extensions/widget/napable.js.coffee +2 -2
  4. data/lib/assets/javascripts/widgets/viewer/main.js.coffee +5 -6
  5. data/lib/ende/version.rb +1 -1
  6. data/vendor/assets/components/ende_build.js +40 -7
  7. data/vendor/components/indefinido-indemma/build/development.js +3 -3
  8. data/vendor/components/indefinido-indemma/build/release.js +40 -7
  9. data/vendor/components/indefinido-indemma/build/test.js +21916 -115
  10. data/vendor/components/indefinido-indemma/component.json +1 -1
  11. data/vendor/components/indefinido-indemma/lib/record/associable.js +14 -2
  12. data/vendor/components/indefinido-indemma/lib/record/restfulable.js +11 -1
  13. data/vendor/components/indefinido-indemma/lib/record/scopable.js +15 -4
  14. data/vendor/components/indefinido-indemma/spec/record/associable_spec.js +3 -2
  15. data/vendor/components/indefinido-indemma/spec/record/scopable_spec.js +83 -53
  16. data/vendor/components/indefinido-indemma/spec/record/validations/cpf_spec.js +5 -6
  17. data/vendor/components/indefinido-indemma/src/lib/record/associable.coffee +6 -0
  18. data/vendor/components/indefinido-indemma/src/lib/record/queryable.coffee +1 -2
  19. data/vendor/components/indefinido-indemma/src/lib/record/restfulable.coffee +14 -1
  20. data/vendor/components/indefinido-indemma/src/lib/record/scopable.coffee +18 -8
  21. data/vendor/components/indefinido-indemma/src/spec/record/associable_spec.coffee +3 -2
  22. data/vendor/components/indefinido-indemma/src/spec/record/scopable_spec.coffee +76 -43
  23. data/vendor/components/indefinido-indemma/src/spec/record/validations/cpf_spec.coffee +3 -4
  24. metadata +2 -2
@@ -2,7 +2,7 @@
2
2
  "name": "indemma",
3
3
  "repo": "indefinido/indemma",
4
4
  "description": "Indemma (mind picture = memory), client side ES5 observable REST model",
5
- "version": "0.1.9",
5
+ "version": "0.1.10",
6
6
  "keywords": [],
7
7
  "dependencies": {
8
8
  "pluma/assimilate": "0.3.0",
@@ -52,7 +52,8 @@ plural = {
52
52
  },
53
53
  push: function() {
54
54
  console.warn("" + this.resource + ".push is deprecated and will be removed, please use add instead");
55
- return Array.prototype.push.apply(this, arguments);
55
+ Array.prototype.push.apply(this, arguments);
56
+ return arguments[0];
56
57
  },
57
58
  length: 0,
58
59
  json: function(methods, omissions) {
@@ -64,7 +65,18 @@ plural = {
64
65
  _results.push(record.json(methods, omissions));
65
66
  }
66
67
  return _results;
67
- }
68
+ },
69
+ find: function(id) {
70
+ var resource, _i, _len;
71
+
72
+ for (_i = 0, _len = this.length; _i < _len; _i++) {
73
+ resource = this[_i];
74
+ if (resource._id === id) {
75
+ return resource;
76
+ }
77
+ }
78
+ },
79
+ filter: Array.prototype.filter || (typeof _ !== "undefined" && _ !== null ? _.filter : void 0)
68
80
  };
69
81
 
70
82
  singular = {
@@ -141,7 +141,7 @@ restful = {
141
141
  return promise;
142
142
  },
143
143
  assign_attributes: function(attributes) {
144
- var association, association_attributes, association_name, associations_attributes, attribute, message, name, singular_resource, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _results;
144
+ var association, association_attributes, association_name, associations_attributes, attribute, message, name, singular_resource, _base, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2, _ref3, _ref4, _results;
145
145
 
146
146
  _ref = model[this.resource.toString()].has_many;
147
147
  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@@ -185,6 +185,16 @@ restful = {
185
185
  this[association_name] = this["build_" + association_name](association_attributes);
186
186
  }
187
187
  }
188
+ _ref3 = model[this.resource.toString()].belongs_to;
189
+ for (_m = 0, _len4 = _ref3.length; _m < _len4; _m++) {
190
+ association_name = _ref3[_m];
191
+ association_attributes = (_ref4 = typeof (_base = attributes[association_name]).json === "function" ? _base.json() : void 0) != null ? _ref4 : attributes[association_name];
192
+ delete attributes[association_name];
193
+ delete attributes[association_name + "_attributes"];
194
+ if (association_attributes) {
195
+ this[association_name] = this["build_" + association_name](association_attributes);
196
+ }
197
+ }
188
198
  _results = [];
189
199
  for (name in attributes) {
190
200
  attribute = attributes[name];
@@ -243,11 +243,13 @@ if (model.associable) {
243
243
  promises.push(this.scope.fetch.call(this, data, null, scopable.record.failed));
244
244
  reload = $.when.apply(jQuery, promises);
245
245
  reload.done(function(records, status) {
246
- var association_name, singular_resource, _i, _j, _len, _len1, _ref;
246
+ var association_name, create, index, singular_resource, target, _i, _j, _k, _len, _len1, _len2, _ref;
247
247
 
248
- Array.prototype.splice.call(this, 0);
249
248
  if (!records.length) {
250
- return;
249
+ if (this.length) {
250
+ Array.prototype.splice.call(this, 0);
251
+ }
252
+ return true;
251
253
  }
252
254
  singular_resource = model.singularize(this.resource);
253
255
  for (_i = 0, _len = records.length; _i < _len; _i++) {
@@ -259,7 +261,16 @@ if (model.associable) {
259
261
  delete record[association_name];
260
262
  }
261
263
  }
262
- this.add.apply(this, records);
264
+ create = [];
265
+ for (index = _k = 0, _len2 = records.length; _k < _len2; index = ++_k) {
266
+ record = records[index];
267
+ if (target = this.find(record._id)) {
268
+ target.assign_attributes(record);
269
+ } else {
270
+ create.push(record);
271
+ }
272
+ }
273
+ this.add.apply(this, create);
263
274
  records.splice(0);
264
275
  return records.push.apply(records, this);
265
276
  });
@@ -124,11 +124,12 @@ describe('model', function() {
124
124
  return association = person().friends;
125
125
  });
126
126
  it('should have query methods', function() {
127
- association.should.have.property('all');
127
+ association.should.have.property('has_many');
128
+ association.should.have.property('find');
128
129
  association.should.have.property('each');
129
130
  return association.should.have.property('reload');
130
131
  });
131
- return describe('#all', function() {
132
+ return describe('#every', function() {
132
133
  return it('should auto observe nested associations attributes');
133
134
  });
134
135
  });
@@ -20,11 +20,8 @@ describe('scopable', function() {
20
20
  });
21
21
  return describe('model', function() {
22
22
  return describe('#(options)', function() {
23
- var person;
24
-
25
- person = null;
26
23
  beforeEach(function() {
27
- return person = model.call({
24
+ return this.person = model.call({
28
25
  $hetero: true,
29
26
  $by_type: [],
30
27
  $by_name: String,
@@ -32,14 +29,14 @@ describe('scopable', function() {
32
29
  });
33
30
  });
34
31
  it('should add scope methods to model', function() {
35
- return person.none.should.be["function"];
32
+ return this.person.none.should.be["function"];
36
33
  });
37
34
  it('should generate scope methods based on model definition', function() {
38
- return person.hetero.should.be["function"];
35
+ return this.person.hetero.should.be["function"];
39
36
  });
40
37
  describe('#none', function() {
41
38
  return it('should return empty response on fetch calls', function(done) {
42
- return person.none().fetch(null, function(people) {
39
+ return this.person.none().fetch(null, function(people) {
43
40
  people.length.should.be.empty;
44
41
  return done();
45
42
  });
@@ -48,28 +45,22 @@ describe('scopable', function() {
48
45
  describe('scope', function() {
49
46
  return describe('#(name, type)', function() {
50
47
  return it('should add scope methods to model', function() {
51
- person.scope('bissexual', Boolean);
52
- return person.bissexual.should.be["function"];
48
+ this.person.scope('bissexual', Boolean);
49
+ return this.person.bissexual.should.be["function"];
53
50
  });
54
51
  });
55
52
  });
56
53
  return describe('#{generated_scope}', function() {
57
- var deferred;
58
-
59
- deferred = null;
60
54
  beforeEach(function() {
61
- deferred = jQuery.Deferred();
62
- sinon.stub(jQuery, "ajax").returns(deferred);
63
- return person.scope.clear();
55
+ this.request = jQuery.Deferred();
56
+ sinon.stub(jQuery, "ajax").returns(this.request);
57
+ return this.person.scope.clear();
64
58
  });
65
59
  afterEach(function() {
66
60
  return jQuery.ajax.restore();
67
61
  });
68
- describe('#all', function() {
69
- var promises;
70
-
71
- deferred = promises = person = null;
72
- return it('should return models when promise is resolved', function(done) {
62
+ describe('#every', function() {
63
+ return it('should fetch models from the server', function(done) {
73
64
  var fetched;
74
65
 
75
66
  fetched = function(people) {
@@ -77,8 +68,8 @@ describe('scopable', function() {
77
68
  people[0].name.should.be.string;
78
69
  return done();
79
70
  };
80
- person.every(fetched);
81
- deferred.resolveWith(person, [
71
+ this.person.every(fetched);
72
+ this.request.resolveWith(this.person, [
82
73
  [
83
74
  {
84
75
  name: 'Arthur'
@@ -92,22 +83,22 @@ describe('scopable', function() {
92
83
  });
93
84
  describe('when string', function() {
94
85
  it('should acumulate data in scope object', function() {
95
- person.by_name();
96
- return person.scope.data.by_name.should.be.a('string');
86
+ this.person.by_name();
87
+ return this.person.scope.data.by_name.should.be.a('string');
97
88
  });
98
89
  return it('should override data throught parameters', function() {
99
- person.by_name('Ford');
100
- return person.scope.data.by_name.should.be.eq('Ford');
90
+ this.person.by_name('Ford');
91
+ return this.person.scope.data.by_name.should.be.eq('Ford');
101
92
  });
102
93
  });
103
94
  describe('when array', function() {
104
95
  it('should acumulate data in scope object', function() {
105
- person.by_type();
106
- return person.scope.data.by_type.should.be.a('array');
96
+ this.person.by_type();
97
+ return this.person.scope.data.by_type.should.be.a('array');
107
98
  });
108
99
  it('should override data throught parameters', function() {
109
- person.by_type(1, 2, 3);
110
- return person.scope.data.by_type.should.contain(1, 2, 3);
100
+ this.person.by_type(1, 2, 3);
101
+ return this.person.scope.data.by_type.should.contain(1, 2, 3);
111
102
  });
112
103
  it('should use default value');
113
104
  it('should allow scope chaining');
@@ -115,45 +106,42 @@ describe('scopable', function() {
115
106
  it('should build correct url', function() {
116
107
  var settings;
117
108
 
118
- person.by_type(1, 3, 4).fetch();
109
+ this.person.by_type(1, 3, 4).fetch();
119
110
  settings = jQuery.ajax.firstCall.args[0];
120
111
  settings.should.have.property('data');
121
112
  settings.data.should.have.property('by_type');
122
113
  return settings.data.by_type.should.include(1, 3, 4);
123
114
  });
124
115
  return it('should make call', function() {
125
- person.by_type(1, 3, 4).fetch();
116
+ this.person.by_type(1, 3, 4).fetch();
126
117
  return jQuery.ajax.callCount.should.be.eq(1);
127
118
  });
128
119
  });
129
120
  });
130
121
  describe('when boolean', function() {
131
122
  it('should acumulate data in scope object', function() {
132
- person.hetero();
133
- return person.scope.data.hetero.should.be.eq(true);
123
+ this.person.hetero();
124
+ return this.person.scope.data.hetero.should.be.eq(true);
134
125
  });
135
126
  it('should override data throught parameters', function() {
136
- person.hetero(false);
137
- return person.scope.data.hetero.should.be.eq(false);
127
+ this.person.hetero(false);
128
+ return this.person.scope.data.hetero.should.be.eq(false);
138
129
  });
139
130
  it('should allow scope chaining');
140
131
  return it('should make ajax call', function() {
141
- person.hetero().fetch();
132
+ this.person.hetero().fetch();
142
133
  return jQuery.ajax.callCount.should.be.eq(1);
143
134
  });
144
135
  });
145
136
  return describe('#{generated_association}', function() {
146
137
  describe('of type belongs_to', function() {
147
- var towel;
148
-
149
- towel = null;
150
138
  beforeEach(function() {
151
- person = model.call({
139
+ this.person = model.call({
152
140
  $hetero: true,
153
141
  $by_type: [],
154
142
  resource: 'person'
155
143
  });
156
- return towel = model.call({
144
+ return this.towel = model.call({
157
145
  resource: 'towel',
158
146
  material: 'cotton',
159
147
  belongs_to: 'person'
@@ -163,7 +151,7 @@ describe('scopable', function() {
163
151
  return it('can be called on association', function() {
164
152
  var soft_towel;
165
153
 
166
- soft_towel = towel({
154
+ soft_towel = this.towel({
167
155
  material: 'silicon microfiber'
168
156
  });
169
157
  soft_towel.build_person();
@@ -172,37 +160,79 @@ describe('scopable', function() {
172
160
  });
173
161
  });
174
162
  return describe('of type has_many', function() {
175
- var arthur, towel;
176
-
177
- arthur = towel = null;
178
163
  beforeEach(function() {
179
- person = model.call({
164
+ this.person = model.call({
180
165
  $hetero: true,
181
166
  $by_type: [],
182
167
  resource: 'person',
183
168
  has_many: 'towels'
184
169
  });
185
- towel = model.call({
170
+ this.towel = model.call({
186
171
  $by_material: [],
187
172
  resource: 'towel',
188
173
  material: 'cotton',
189
174
  belongs_to: 'person'
190
175
  });
191
- return arthur = person({
176
+ this.arthur = this.person({
192
177
  name: 'Arthur'
193
178
  });
179
+ return this.person.scope.clear();
194
180
  });
195
181
  return describe('#{generated_scope}', function() {
196
182
  it('can be called on association', function() {
197
- return expect(arthur.towels).to.respondTo('by_material');
183
+ return expect(this.arthur.towels).to.respondTo('by_material');
198
184
  });
199
- return it('should be serializable into paramenters', function() {
185
+ it('should be serializable into paramenters', function() {
200
186
  var query_string;
201
187
 
202
- arthur.towels.by_material('cotton', 'microfiber');
203
- query_string = decodeURIComponent(jQuery.param(arthur.towels.scope.data));
188
+ this.arthur.towels.by_material('cotton', 'microfiber');
189
+ query_string = decodeURIComponent(jQuery.param(this.arthur.towels.scope.data));
204
190
  return query_string.should.be.eq('by_material[]=cotton&by_material[]=microfiber');
205
191
  });
192
+ return describe('#every', function() {
193
+ it('should empty association when no models are returned', function(done) {
194
+ var fetched,
195
+ _this = this;
196
+
197
+ fetched = function(towels) {
198
+ towels.should.be.array;
199
+ towels.should.be.empty;
200
+ _this.arthur.towels.should.have.length(0);
201
+ this.should.have.length(0) ;
202
+ return done();
203
+ };
204
+ this.arthur.towels.every(fetched);
205
+ this.request.resolveWith(this.arthur.towels, [[]]);
206
+ return jQuery.ajax.callCount.should.be.eq(1);
207
+ });
208
+ return it('should update resources when already exists in association', function(done) {
209
+ var aditions, fetched,
210
+ _this = this;
211
+
212
+ aditions = this.arthur.towels.add({
213
+ _id: 1,
214
+ material: 'colan'
215
+ });
216
+ fetched = function(towels) {
217
+ towels.should.be.array;
218
+ towels.should.have.length(1);
219
+ towels[0].material.should.be.eq('cotton');
220
+ aditions[0].material.should.be.eq('cotton');
221
+ _this.arthur.towels[0].material.should.be.eq('cotton');
222
+ return done();
223
+ };
224
+ this.arthur.towels.every(fetched);
225
+ this.request.resolveWith(this.arthur.towels, [
226
+ [
227
+ {
228
+ _id: 1,
229
+ material: 'cotton'
230
+ }
231
+ ]
232
+ ]);
233
+ return jQuery.ajax.callCount.should.be.eq(1);
234
+ });
235
+ });
206
236
  });
207
237
  });
208
238
  });
@@ -6,26 +6,25 @@ require('indemma/lib/record/validatable');
6
6
 
7
7
  describe('model #() validates_cpf_format', function() {
8
8
  return describe('basic usage', function() {
9
- var model, person;
9
+ var model;
10
10
 
11
11
  model = root.model;
12
- person = null;
13
12
  beforeEach(function() {
14
- return person = model.call({
13
+ return this.person = model.call({
15
14
  resource: 'person',
16
15
  cpf: String,
17
16
  validates_cpf_format: 'cpf'
18
17
  });
19
18
  });
20
19
  afterEach(function() {
21
- return person != null ? person.validators.length = 0 : void 0;
20
+ return this.person.validators.length = 0;
22
21
  });
23
22
  return describe('#validate', function() {
24
23
  return it('should add error to record when fields is in invalid format', function() {
25
24
  var arthur;
26
25
 
27
- arthur = person({
28
- cpf: '871.943.417-00'
26
+ arthur = this.person({
27
+ cpf: '871.95FRANGO-00'
29
28
  });
30
29
  arthur.valid;
31
30
  return arthur.errors.messages.should.have.deep.property('cpf', "O campo cpf não está válido.");
@@ -32,10 +32,16 @@ plural = # has_many ## TODO embeds_many
32
32
  push : ->
33
33
  console.warn "#{@resource}.push is deprecated and will be removed, please use add instead"
34
34
  Array.prototype.push.apply @, arguments
35
+ arguments[0]
35
36
 
36
37
  length : 0
37
38
  json : (methods, omissions) -> record.json(methods, omissions) for record in @
38
39
 
40
+ find : (id) -> return resource for resource in @ when resource._id is id
41
+
42
+ # TODO better support searching
43
+ filter : Array.prototype.filter || _?.filter
44
+
39
45
 
40
46
  singular = # belongs_to, has_one ## TODO embeds_one, embedded_in
41
47
  # @ = record
@@ -9,8 +9,7 @@ queryable =
9
9
  find: (key) ->
10
10
  throw new TypeError "InvalidFind: resource.find was called with a falsey value" unless key
11
11
  @storage.store key
12
- every: ->
13
- @storage.values()
12
+ every: -> @storage.values()
14
13
  where: ->
15
14
  throw new Error 'queryable.where: Not implemented yet'
16
15
 
@@ -178,6 +178,19 @@ restful =
178
178
  @[association_name] = @["build_#{association_name}"] association_attributes if association_attributes
179
179
 
180
180
 
181
+ # Nested attributes
182
+ # TODO implement setter on belongs_to association and move this
183
+ # code there
184
+ for association_name in model[@resource.toString()].belongs_to
185
+ association_attributes = attributes[association_name].json?() ? attributes[association_name]
186
+
187
+ # TODO copy attributes object and don't change it inside the
188
+ # assignment method
189
+ delete attributes[association_name]
190
+ delete attributes[association_name + "_attributes"]
191
+ @[association_name] = @["build_#{association_name}"] association_attributes if association_attributes
192
+
193
+
181
194
  # Assign remaining attributes
182
195
  # TODO see if it is a best practice not overriding unchanged attributes
183
196
  # TODO rename attributes for properties
@@ -423,7 +436,7 @@ restful =
423
436
  json
424
437
 
425
438
 
426
- # TODO put deprecation warning on json method
439
+ # TODO pt udeprecation warning on json method
427
440
  # TODO rename json method to toJSON
428
441
  restful.toJSON = restful.json
429
442
 
@@ -244,12 +244,14 @@ if model.associable
244
244
  # TODO implement setter on this association and let user to set
245
245
  reload.done (records, status) ->
246
246
 
247
- # Clear current stored cache on this association
248
- # it to an empty array
249
- Array.prototype.splice.call @, 0
247
+ # if no records were found by the server on this association
248
+ unless records.length
249
+ # Clear current stored cache on this association
250
+ # it to an empty array
251
+ Array.prototype.splice.call @, 0 if @length
252
+
253
+ return true
250
254
 
251
- # return if no records were found by the server
252
- return unless records.length
253
255
 
254
256
  singular_resource = model.singularize @resource
255
257
 
@@ -263,8 +265,17 @@ if model.associable
263
265
  record["#{association_name}_attributes"] = record[association_name]
264
266
  delete record[association_name]
265
267
 
268
+ # Update found records
269
+ # TODO create update method
270
+ create = []
271
+ for record, index in records
272
+ if target = @find record._id
273
+ target.assign_attributes record
274
+ else
275
+ create.push record
276
+
266
277
  # Load new records on this association
267
- @add.apply @, records
278
+ @add.apply @, create
268
279
 
269
280
  # Override the response records object with added to association records
270
281
  records.splice 0
@@ -281,5 +292,4 @@ if model.associable
281
292
 
282
293
  # TODO cache models
283
294
  @get().done (records) =>
284
- for record in @
285
- callback record
295
+ callback record for record in @
@@ -121,10 +121,11 @@ describe 'model', ->
121
121
  beforeEach -> association = person().friends
122
122
 
123
123
  it 'should have query methods', ->
124
- association.should.have.property 'all'
124
+ association.should.have.property 'has_many'
125
+ association.should.have.property 'find'
125
126
  association.should.have.property 'each'
126
127
  association.should.have.property 'reload'
127
128
 
128
- describe '#all', ->
129
+ describe '#every', ->
129
130
 
130
131
  it 'should auto observe nested associations attributes'