ende 0.4.18 → 0.4.19

Sign up to get free protection for your applications and to get access to all the features.
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'