ende 0.2.9 → 0.2.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/lib/assets/javascripts/aura/extensions/devise.js.coffee +2 -2
  3. data/lib/assets/javascripts/widgets/viewer/main.js.coffee +1 -1
  4. data/lib/ende/version.rb +1 -1
  5. data/vendor/assets/components/build.js +638 -133
  6. data/vendor/components/indefinido-indemma/.gitignore +14 -0
  7. data/vendor/components/indefinido-indemma/.gitignore~ +2 -0
  8. data/vendor/components/indefinido-indemma/.ruby-gemset +1 -0
  9. data/vendor/components/indefinido-indemma/.ruby-version +1 -0
  10. data/vendor/components/indefinido-indemma/Gemfile +13 -0
  11. data/vendor/components/indefinido-indemma/Guardfile +39 -0
  12. data/vendor/components/indefinido-indemma/History.md +0 -0
  13. data/vendor/components/indefinido-indemma/Readme.md +447 -0
  14. data/vendor/components/indefinido-indemma/build/development.js +340 -0
  15. data/vendor/components/indefinido-indemma/build/release.js +22039 -0
  16. data/vendor/components/indefinido-indemma/build/test.js +22039 -0
  17. data/vendor/components/indefinido-indemma/component.json +7 -3
  18. data/vendor/components/indefinido-indemma/components/chaijs-assertion-error/component.json +18 -0
  19. data/vendor/components/indefinido-indemma/components/chaijs-assertion-error/index.js +110 -0
  20. data/vendor/components/indefinido-indemma/components/chaijs-chai/component.json +47 -0
  21. data/vendor/components/indefinido-indemma/components/chaijs-chai/index.js +1 -0
  22. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/assertion.js +130 -0
  23. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/core/assertions.js +1270 -0
  24. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/interface/assert.js +1080 -0
  25. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/interface/expect.js +12 -0
  26. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/interface/should.js +76 -0
  27. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/addChainableMethod.js +94 -0
  28. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/addMethod.js +37 -0
  29. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/addProperty.js +40 -0
  30. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/eql.js +129 -0
  31. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/flag.js +32 -0
  32. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/getActual.js +19 -0
  33. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/getEnumerableProperties.js +25 -0
  34. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/getMessage.js +49 -0
  35. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/getName.js +20 -0
  36. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/getPathValue.js +102 -0
  37. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/getProperties.js +35 -0
  38. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/index.js +108 -0
  39. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/inspect.js +320 -0
  40. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/objDisplay.js +48 -0
  41. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/overwriteMethod.js +51 -0
  42. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/overwriteProperty.js +54 -0
  43. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/test.js +26 -0
  44. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/transferFlags.js +44 -0
  45. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai/utils/type.js +45 -0
  46. data/vendor/components/indefinido-indemma/components/chaijs-chai/lib/chai.js +80 -0
  47. data/vendor/components/indefinido-indemma/components/component-bind/component.json +14 -0
  48. data/vendor/components/indefinido-indemma/components/component-bind/index.js +24 -0
  49. data/vendor/components/indefinido-indemma/components/component-jquery/component.json +14 -0
  50. data/vendor/components/indefinido-indemma/components/component-jquery/index.js +9601 -0
  51. data/vendor/components/indefinido-indemma/components/component-type/component.json +18 -0
  52. data/vendor/components/indefinido-indemma/components/component-type/index.js +32 -0
  53. data/vendor/components/indefinido-indemma/components/indefinido-advisable/component.json +21 -0
  54. data/vendor/components/indefinido-indemma/components/indefinido-advisable/index.js +1 -0
  55. data/vendor/components/indefinido-indemma/components/indefinido-advisable/lib/advisable.js +60 -0
  56. data/vendor/components/indefinido-indemma/components/indefinido-observable/component.json +25 -0
  57. data/vendor/components/indefinido-indemma/components/indefinido-observable/components/cjohansen-sinon/sinon.js +4290 -0
  58. data/vendor/components/indefinido-indemma/components/indefinido-observable/index.js +1 -0
  59. data/vendor/components/indefinido-indemma/components/indefinido-observable/lib/adapters/rivets.js +26 -0
  60. data/vendor/components/indefinido-indemma/components/indefinido-observable/lib/observable.js +323 -0
  61. data/vendor/components/indefinido-indemma/components/indefinido-observable/vendor/shims/accessors-legacy.js +92 -0
  62. data/vendor/components/indefinido-indemma/components/indefinido-observable/vendor/shims/accessors.js +173 -0
  63. data/vendor/components/indefinido-indemma/components/indefinido-observable/vendor/shims/array.indexOf.js +8 -0
  64. data/vendor/components/indefinido-indemma/components/indefinido-observable/vendor/shims/object.create.js +77 -0
  65. data/vendor/components/indefinido-indemma/components/kapit-observe-utils/component.json +13 -0
  66. data/vendor/components/indefinido-indemma/components/paulmillr-es6-shim/component.json +17 -0
  67. data/vendor/components/indefinido-indemma/components/paulmillr-es6-shim/es6-shim.js +996 -0
  68. data/vendor/components/indefinido-indemma/components/pluma-assimilate/component.json +25 -0
  69. data/vendor/components/indefinido-indemma/components/pluma-assimilate/dist/assimilate.js +127 -0
  70. data/vendor/components/indefinido-indemma/karma.conf.js +86 -0
  71. data/vendor/components/indefinido-indemma/lib/record/associable.js +229 -82
  72. data/vendor/components/indefinido-indemma/lib/record/errors.js +1 -0
  73. data/vendor/components/indefinido-indemma/lib/record/persistable.js +32 -0
  74. data/vendor/components/indefinido-indemma/lib/record/queryable.js +32 -0
  75. data/vendor/components/indefinido-indemma/lib/record/resource.js +12 -4
  76. data/vendor/components/indefinido-indemma/lib/record/rest.js +1 -1
  77. data/vendor/components/indefinido-indemma/lib/record/restfulable.js +38 -27
  78. data/vendor/components/indefinido-indemma/lib/record/scopable.js +15 -2
  79. data/vendor/components/indefinido-indemma/lib/record/storable.js +48 -0
  80. data/vendor/components/indefinido-indemma/lib/record/validatable.js +10 -5
  81. data/vendor/components/indefinido-indemma/lib/record/validations/cpf.js +1 -1
  82. data/vendor/components/indefinido-indemma/lib/record.js +15 -12
  83. data/vendor/components/indefinido-indemma/spec/record/associable_spec.js +137 -0
  84. data/vendor/components/indefinido-indemma/spec/record/persistable_spec.js +36 -0
  85. data/vendor/components/indefinido-indemma/spec/record/queryable_spec.js +33 -0
  86. data/vendor/components/indefinido-indemma/spec/record/resource_spec.js +93 -0
  87. data/vendor/components/indefinido-indemma/spec/record/rest_spec.js +32 -0
  88. data/vendor/components/indefinido-indemma/spec/record/restfulable_spec.js +288 -0
  89. data/vendor/components/indefinido-indemma/spec/record/scopable_spec.js +212 -0
  90. data/vendor/components/indefinido-indemma/spec/record/storable_spec.js +53 -0
  91. data/vendor/components/indefinido-indemma/spec/record/translationable.js +28 -0
  92. data/vendor/components/indefinido-indemma/spec/record/validatable_spec.js +111 -0
  93. data/vendor/components/indefinido-indemma/spec/record/validations/associated_spec.js +43 -0
  94. data/vendor/components/indefinido-indemma/spec/record/validations/confirmation_spec.js +36 -0
  95. data/vendor/components/indefinido-indemma/spec/record/validations/cpf_spec.js +35 -0
  96. data/vendor/components/indefinido-indemma/spec/record/validations/presence_spec.js +28 -0
  97. data/vendor/components/indefinido-indemma/spec/record/validations/remote_spec.js +87 -0
  98. data/vendor/components/indefinido-indemma/spec/record/validations/type_spec.js +48 -0
  99. data/vendor/components/indefinido-indemma/spec/record_spec.js +37 -0
  100. data/vendor/components/indefinido-indemma/spec/spec_helper.js +11 -0
  101. data/vendor/components/indefinido-indemma/spec/support/value_objects/phone.js +45 -0
  102. data/vendor/components/indefinido-indemma/src/lib/extensions/rivets.coffee +17 -0
  103. data/vendor/components/indefinido-indemma/src/lib/record/associable.coffee +342 -0
  104. data/vendor/components/indefinido-indemma/src/lib/record/errors.coffee +20 -0
  105. data/vendor/components/indefinido-indemma/src/lib/record/maid.coffee +16 -0
  106. data/vendor/components/indefinido-indemma/src/lib/record/persistable.coffee +27 -0
  107. data/vendor/components/indefinido-indemma/src/lib/record/queryable.coffee +29 -0
  108. data/vendor/components/indefinido-indemma/src/lib/record/resource.coffee +106 -0
  109. data/vendor/components/indefinido-indemma/src/lib/record/rest.coffee +28 -0
  110. data/vendor/components/indefinido-indemma/src/lib/record/restfulable.coffee +348 -0
  111. data/vendor/components/indefinido-indemma/src/lib/record/scopable.coffee +275 -0
  112. data/vendor/components/indefinido-indemma/src/lib/record/storable.coffee +46 -0
  113. data/vendor/components/indefinido-indemma/src/lib/record/translationable.coffee +18 -0
  114. data/vendor/components/indefinido-indemma/src/lib/record/validatable.coffee +217 -0
  115. data/vendor/components/indefinido-indemma/src/lib/record/validations/associated.coffee +32 -0
  116. data/vendor/components/indefinido-indemma/src/lib/record/validations/confirmation.coffee +19 -0
  117. data/vendor/components/indefinido-indemma/src/lib/record/validations/cpf.coffee +58 -0
  118. data/vendor/components/indefinido-indemma/src/lib/record/validations/presence.coffee +19 -0
  119. data/vendor/components/indefinido-indemma/src/lib/record/validations/remote.coffee +65 -0
  120. data/vendor/components/indefinido-indemma/src/lib/record/validations/type.coffee +32 -0
  121. data/vendor/components/indefinido-indemma/src/lib/record.coffee +136 -0
  122. data/vendor/components/indefinido-indemma/src/spec/record/associable_spec.coffee +130 -0
  123. data/vendor/components/indefinido-indemma/src/spec/record/persistable_spec.coffee +30 -0
  124. data/vendor/components/indefinido-indemma/src/spec/record/queryable_spec.coffee +27 -0
  125. data/vendor/components/indefinido-indemma/src/spec/record/resource_spec.coffee +69 -0
  126. data/vendor/components/indefinido-indemma/src/spec/record/rest_spec.coffee +22 -0
  127. data/vendor/components/indefinido-indemma/src/spec/record/restfulable_spec.coffee +207 -0
  128. data/vendor/components/indefinido-indemma/src/spec/record/scopable_spec.coffee +191 -0
  129. data/vendor/components/indefinido-indemma/src/spec/record/storable_spec.coffee +40 -0
  130. data/vendor/components/indefinido-indemma/src/spec/record/translationable.coffee +19 -0
  131. data/vendor/components/indefinido-indemma/src/spec/record/validatable_spec.coffee +100 -0
  132. data/vendor/components/indefinido-indemma/src/spec/record/validations/associated_spec.coffee +35 -0
  133. data/vendor/components/indefinido-indemma/src/spec/record/validations/confirmation_spec.coffee +25 -0
  134. data/vendor/components/indefinido-indemma/src/spec/record/validations/cpf_spec.coffee +28 -0
  135. data/vendor/components/indefinido-indemma/src/spec/record/validations/presence_spec.coffee +24 -0
  136. data/vendor/components/indefinido-indemma/src/spec/record/validations/remote_spec.coffee +74 -0
  137. data/vendor/components/indefinido-indemma/src/spec/record/validations/type_spec.coffee +33 -0
  138. data/vendor/components/indefinido-indemma/src/spec/record_spec.coffee +23 -0
  139. data/vendor/components/indefinido-indemma/src/spec/spec_helper.coffee +9 -0
  140. data/vendor/components/indefinido-indemma/src/spec/support/value_objects/phone.coffee +30 -0
  141. data/vendor/components/indefinido-indemma/vendor/object/mixin.js +196 -0
  142. data/vendor/components/indefinido-indemma/vendor/owl/pluralize.js +190 -0
  143. metadata +130 -2
@@ -0,0 +1,348 @@
1
+ merge = require('assimilate').withStrategy 'deep'
2
+ type = require 'type'
3
+ observable = require('observable').mixin
4
+ $ = require 'jquery' # TODO remove jquery dependency and use simple promises implementation
5
+ rest = require './rest.js'
6
+
7
+ util =
8
+ model:
9
+ map: (models) ->
10
+ @ model for model in models
11
+
12
+
13
+ restful =
14
+ model:
15
+ # returns an array of promises
16
+ create: (params..., callback) ->
17
+ throw new TypeError("No arguments provided for #{@resource}.create") unless arguments.length
18
+ unless typeof callback == 'function'
19
+ params.push callback
20
+ callback = undefined
21
+
22
+ params.unshift {} unless params.length
23
+
24
+ savings = []
25
+ for attributes in params
26
+ # TODO accept dirty as attribute on record creation
27
+ record = @ attributes
28
+ record.dirty = true
29
+ savings.push record.save callback
30
+
31
+ $.when savings...
32
+
33
+ # returns a promise
34
+ # TODO move to scopable
35
+ all: (conditions = {}, callback) ->
36
+ if typeof conditions == 'function'
37
+ callback = conditions
38
+ conditions = {}
39
+
40
+ # TODO Consider parent resources
41
+ # if @parent and not @parent._id
42
+ # return callback.call @model, []
43
+
44
+
45
+ $.when(rest.get.call @, conditions)
46
+ .then(util.model.map )
47
+ .done callback
48
+
49
+ first: (conditions = {}, callback) ->
50
+ if typeof conditions == 'function'
51
+ callback = conditions
52
+ conditions = {}
53
+
54
+ namespaced = conditions[@resource] || {}
55
+ namespaced.limit = 1
56
+ namespaced.order = 'desc'
57
+
58
+ # TODO should fail when server returns more then one record
59
+ @all conditions, callback
60
+
61
+ # TODO better treating of arguments
62
+ get: (action, data = {}) ->
63
+ # TODO better way to override route
64
+ old_route = @route
65
+ @route = "/#{model.pluralize @resource.name}"
66
+ @route += "/#{action}" if action
67
+
68
+ # TODO not allow resource overriding
69
+ resource = data.resource
70
+ data = data.json() if data and data.json
71
+
72
+ if resource?
73
+ payload = data
74
+ data = {}
75
+ data[resource] = payload
76
+
77
+ promise = rest.get.call @, data
78
+
79
+ route = old_route
80
+
81
+ promise
82
+
83
+ put: rest.put
84
+ delete: rest.delete
85
+
86
+ record:
87
+ reload: (params...) ->
88
+
89
+ # TODO better signature implementation
90
+ data = params.pop()
91
+ params.push data if type(data) != 'object'
92
+
93
+ promise = rest.get.call @, data || {}
94
+ promise.done @assign_attributes
95
+ promise.fail @failed
96
+
97
+ # Bind one time save callbacks
98
+ promise.done param for param in params
99
+
100
+ promise
101
+
102
+ assign_attributes: (attributes) ->
103
+
104
+ # TODO only set associations on nested attributes!
105
+ # First assign has_many associations
106
+ # TODO implement setter on has_many association and move this code there
107
+ for association_name in model[@resource.toString()].has_many
108
+ associations_attributes = attributes[association_name]
109
+
110
+ # TODO copy attributes object and don't change it inside the assignment method
111
+ delete attributes[association_name] # Remove loaded json data
112
+
113
+ # Clear current stored cache on this association
114
+ # TODO implement setter on this association and let user to set
115
+ # it to an empty array
116
+ association = @[association_name]
117
+
118
+ unless association?
119
+ message = "Association '#{association_name}' not found. \n"
120
+ message += "For record with resource #{@resource}. \n"
121
+ message += "Probably defined on server side but not on client side.\n"
122
+ message += "Skipping association assignment!"
123
+ console.warn message
124
+ continue
125
+
126
+ # TODO implement association.clear
127
+ Array.prototype.splice.call association, 0 if association.length
128
+
129
+ # continue if no associations_attributes were found by the server
130
+ continue unless associations_attributes? and associations_attributes.length
131
+
132
+ singular_resource = model.singularize association_name
133
+
134
+ # Normalize json data for building on association
135
+ for association_attributes in associations_attributes
136
+
137
+ # TODO only nest specified nested attributes on model definition
138
+ # TODO create special deserialization method no plural association
139
+ # TODO check if we need to nest attributes in other association types
140
+ for association_name in model[singular_resource].has_many
141
+ association_attributes["#{association_name}_attributes"] = association_attributes[association_name]
142
+
143
+ # TODO copy attributes object and don't change it inside
144
+ # the assignment method
145
+ delete association_attributes[association_name]
146
+
147
+ # Load new associations_attributes on this association
148
+ association.add associations_attributes...
149
+
150
+
151
+ # Nested attributes
152
+ # TODO implement setter on has_one association and move this
153
+ # code there
154
+ for association_name in model[@resource.toString()].has_one
155
+ association_attributes = attributes[association_name]
156
+
157
+ # TODO copy attributes object and don't change it inside the
158
+ # assignment method
159
+ delete attributes[association_name]
160
+ delete attributes[association_name + "_attributes"]
161
+ @[association_name] = @["build_#{association_name}"] association_attributes if association_attributes
162
+
163
+
164
+ # Assign remaining attributes
165
+ # TODO see if it is a best practice not overriding unchanged attributes
166
+ for attribute of attributes when attribute isnt @[attribute]
167
+ @[attribute] = attributes[attribute]
168
+
169
+ destroy: (doned, failed, data) ->
170
+ throw new Error 'Can\'t delete record without id!' unless @id? or @_id?
171
+
172
+ promise = rest.delete.call @, data
173
+ promise.done @destroyed
174
+ promise.fail @failed
175
+
176
+ # Bind one time save callbacks
177
+ promise.done doned
178
+ promise.fail failed
179
+
180
+ promise
181
+
182
+ saving: false
183
+ salvation: null
184
+ save: (doned, failed, data) ->
185
+ return @salvation if @saving
186
+
187
+ # TODO better lock generation
188
+ @lock = JSON.stringify @json()
189
+
190
+ # TODO remove jquery dependency
191
+ # TODO think with wich value makes more sense to resolve the
192
+ # absence of need to save the model
193
+ salvation = $.Deferred().resolveWith @, null unless @dirty
194
+ salvation ||= rest[if @_id then 'put' else 'post'].call @, data
195
+ @salvation = salvation
196
+ @saving = true
197
+
198
+ salvation.done @saved
199
+ salvation.fail @failed
200
+ salvation.always -> @saving = false
201
+
202
+ # Bind one time save callbacks
203
+ salvation.done doned
204
+ salvation.fail failed
205
+
206
+ salvation
207
+
208
+ saved: (data) ->
209
+
210
+ # TODO better lock generation
211
+ if @lock == JSON.stringify(@json())
212
+ @dirty = false
213
+ delete @lock
214
+ # Delayed optimistic lock
215
+ else
216
+ return @save()
217
+
218
+ @assign_attributes data if data?
219
+
220
+ throw "Not supported after_save callback: " + callback for callback in @after_save if @after_save
221
+
222
+ # Parse error json if any
223
+ failed: (xhr, error, status) ->
224
+ payload = xhr.responseJSON
225
+ try payload ||= JSON.parse(xhr.responseText) catch e
226
+ payload ||= xhr.responseText
227
+
228
+
229
+ # When client fail
230
+ switch xhr.status
231
+ # TODO move to validatable
232
+ when 422
233
+
234
+ definition = model[@resource]
235
+
236
+ for attribute_name, messages of payload.errors
237
+
238
+ # TODO add support for error checking message introspection
239
+ # Check for association errors
240
+ if (!definition.associations)
241
+ # TODO update this attribute when associations are dinamically changed
242
+ definition.associations = definition.has_one.concat(definition.has_many.concat(definition.belongs_to))
243
+
244
+ # Only add errors to existing attributes
245
+ # TODO shorten this verification
246
+ unless @hasOwnProperty(attribute_name) or definition.hasOwnProperty(attribute_name) or definition.associations.indexOf(attribute_name) != -1 or attribute_name == 'base'
247
+
248
+ message = "Server returned an validation error message for a attribute that is not defined in your model.\n"
249
+ message += "The attribute was '#{attribute_name}', the model resource was '#{@resource}'.\n"
250
+ message += "The model definition keys were '#{JSON.stringify Object.keys definition }'.\n"
251
+ message += "Please remove server validation, or update your model definition."
252
+ throw new TypeError message
253
+
254
+ for message in messages
255
+ @errors.add attribute_name, 'server', server_message: message
256
+
257
+ # Unknown fail
258
+ else
259
+ message = "Fail in #{@resource}.save:\n"
260
+ message += "Record: #{@}\n"
261
+ message += "Status: #{status} (#{payload.status || xhr.status})\n"
262
+ message += "Error : #{payload.error || payload.message || payload}"
263
+
264
+ # Finish saving
265
+ @saving = false
266
+
267
+ toString: ->
268
+ serialized = {}
269
+ serialized[@resource] = @json()
270
+ JSON.stringify serialized
271
+
272
+ json: (methods = {}) ->
273
+ json = {}
274
+
275
+ for name, value of @ when type(value) isnt 'function'
276
+ continue unless value? # Bypass null, and undefined values
277
+
278
+ if type(value) == 'object'
279
+
280
+ if value.toJSON?
281
+
282
+ json[name] = value.toJSON(methods[name])
283
+
284
+ else
285
+
286
+ # TODO move nested attributes to model definition
287
+ # TODO and implement toJSON there
288
+ for attribute in @nested_attributes when attribute == name
289
+ json["#{name}_attributes"] = value.json(methods[name])
290
+
291
+ else
292
+
293
+ json[name] = value
294
+
295
+ observable.unobserve json
296
+
297
+ # TODO Store reserved words in a array
298
+ # TODO Use _.omit function
299
+ # TODO Use object.defineProperty to not need to delete this properties
300
+ # Remove model reserved words
301
+ delete json.dirty
302
+ delete json.resource
303
+ delete json.route
304
+ delete json.initial_route # TODO implement better initial_route and remove attribute from here
305
+ delete json.after_initialize
306
+ delete json.before_initialize
307
+ delete json.parent_resource
308
+ delete json.nested_attributes
309
+ delete json.saving
310
+ delete json.salvation
311
+ delete json.sustained
312
+ delete json.element
313
+ delete json.default
314
+ delete json.lock
315
+ delete json.validated
316
+ delete json.validation
317
+
318
+ json
319
+
320
+ # TODO put deprecation warning on json method
321
+ # TODO rename json method to toJSON
322
+ restful.toJSON = restful.json
323
+
324
+
325
+ # Extend indemma
326
+ model = window.model # TODO better way to get parent
327
+ record = window.record # TODO better way to get parent
328
+
329
+ model.restfulable = true
330
+
331
+ record.mix (recordable) ->
332
+ merge recordable, restful.record
333
+
334
+
335
+ model.mix (modelable ) ->
336
+ merge modelable , restful.model
337
+
338
+
339
+ model.associable && model.associable.mix (singular_association, plural_association) ->
340
+
341
+ # TODO move route setting to plural_association.after_mix
342
+ plural_association.get = ->
343
+ @route ||= "#{@parent.route}/#{@parent._id}/#{model.pluralize @resource.name}" if @parent?
344
+ rest.get.apply @, arguments
345
+
346
+ plural_association.post = ->
347
+ @route ||= "#{@parent.route}/#{@parent._id}/#{model.pluralize @resource.name}" if @parent?
348
+ rest.post.apply @, arguments
@@ -0,0 +1,275 @@
1
+ require './restfulable'
2
+ require './resource'
3
+
4
+ stampit = require '../../vendor/stampit'
5
+ extend = require 'assimilate'
6
+ merge = extend.withStrategy 'deep'
7
+ $ = require 'jquery'
8
+ rest = require './rest'
9
+
10
+
11
+ scopable =
12
+ builder: stampit().enclose ->
13
+
14
+ # Builds a given scope
15
+ # {param} name Scope name also, the name of method used to invoke it
16
+ # {param} type Default value for scope, or base class to derive default for default type
17
+
18
+ stampit.mixIn (name, type) ->
19
+ if $.type(type) == 'function'
20
+ @["$#{name}"] = type() || new type
21
+ type = $.type @["$#{name}"]
22
+ else
23
+ @["$#{name}"] = defaults[type] || type
24
+
25
+ type = $.type type unless $.type(type) == 'string'
26
+ builder = builders[type]
27
+
28
+ throw "Unknown scope type: '#{type}', For model with resource: '#{@resource}'" unless builder?
29
+
30
+ @scope.declared.push name
31
+ @[name] = builder name: name
32
+ ,
33
+ data: {}
34
+ then: []
35
+ fail: []
36
+ declared: []
37
+ fetch: (data, done, fail) ->
38
+ scope = extend {}, @scope.data
39
+
40
+ if scope.noned?
41
+ deferred = $.Deferred()
42
+ deferred.resolveWith @, [[]]
43
+ else
44
+ deferred = rest.get.call(@, extend scope, data)
45
+
46
+ deferred
47
+ .done(@scope.then.concat done)
48
+ .fail([@scope.fail, fail])
49
+
50
+ @scope.clear()
51
+
52
+ deferred
53
+
54
+ clear: ->
55
+ @data = {}
56
+ @callbacks = []
57
+
58
+ # Shared scope stuff
59
+ base: stampit().state
60
+ name: 'unamed_scope'
61
+
62
+ record:
63
+ # Parse error json if any
64
+ failed: (xhr, error, status) ->
65
+ payload = xhr.responseJSON
66
+ try payload ||= JSON.parse(xhr.responseText) catch e
67
+ payload ||= xhr.responseText
68
+
69
+ # When client fail
70
+ switch xhr.status
71
+ when 422
72
+ @valid = false
73
+ return @errors = payload.errors
74
+ # Unknown fail
75
+ else
76
+ message = "Fail in #{@resource}.save:\n"
77
+ message += "Record: #{@}\n"
78
+ message += "Status: #{status} (#{payload.status || xhr.status})\n"
79
+ message += "Error : #{payload.error || payload.message || payload}"
80
+
81
+ console.error message
82
+ model:
83
+ # TODO implement getter for none property!
84
+ none: ->
85
+ @scope.data.noned = true
86
+ @
87
+
88
+ fetch: (data, done, fail) ->
89
+ @scope.fetch.call @, data, done, fail
90
+
91
+ # TODO optmize this iterations or add support for stampit on associable and merge factories
92
+ # @ = record instance
93
+ forward_scopes_to_associations: ->
94
+ factory = model[@resource.name]
95
+
96
+ for association_name in factory.has_many
97
+ associated_resource = model.singularize association_name
98
+ associated_factory = model[associated_resource]
99
+
100
+ # TODO change this warn message into a exception when
101
+ # associations are renamable
102
+ unless model[associated_resource]
103
+ console.warn("Associated factory not found for associated resource: #{associated_resource}")
104
+ continue
105
+
106
+ association = @[association_name]
107
+ association.scope = scopable.builder association
108
+
109
+
110
+ for scope in associated_factory.scope.declared
111
+ association.scope scope, associated_factory["$#{scope}"]
112
+
113
+ for associated_resource in factory.has_one
114
+ # TODO change this warn message into a exception when
115
+ # associations are renamable
116
+ unless model[associated_resource]
117
+ console.warn("Associated factory not found for associated resource: #{associated_resource}")
118
+ continue
119
+
120
+ for scope in model[associated_resource].scope.declared
121
+ @[associated_resource][scope] = factory[scope]
122
+
123
+ # TODO improve associable inner workings to stampit objects
124
+ if factory.belongs_to.length
125
+ generate_forwarder = (associated_resource) ->
126
+ associated_factory = model[associated_resource]
127
+
128
+ # TODO change this warn message into a exception when
129
+ # associations are renamable
130
+ return console.warn("Associated factory not found for associated resource: #{associated_resource}") unless associated_factory
131
+
132
+ declared_scopes = associated_factory.scope.declared
133
+
134
+ ->
135
+ for scope in declared_scopes
136
+ @[associated_resource][scope] = associated_factory[scope]
137
+
138
+ for associated_resource in factory.belongs_to
139
+ forwarder = generate_forwarder associated_resource
140
+ @after "build_#{associated_resource}", forwarder
141
+
142
+ true
143
+ # @ = model instance
144
+ after_mix: ->
145
+ @scope = scopable.builder @
146
+
147
+ for property, type of @
148
+ if property.charAt(0) == '$'
149
+ name = property.substring 1
150
+ @scope name, type
151
+
152
+ builders =
153
+ # Builds a string scope builder
154
+ string: stampit().enclose ->
155
+ base = scopable.base @
156
+
157
+ stampit.mixIn (value, callbacks...) ->
158
+ callbacks.length and @scope.then = @scope.then.concat callbacks
159
+ @scope.data[base.name] ||= value ? @["$#{base.name}"]
160
+ @
161
+
162
+ # Builds a boolean scope builder
163
+ boolean: stampit().enclose ->
164
+ base = scopable.base @
165
+
166
+ stampit.mixIn (value, callbacks...) ->
167
+ callbacks.length and @scope.then = @scope.then.concat callbacks
168
+ @scope.data[base.name] ||= value ? @["$#{base.name}"]
169
+ @
170
+
171
+ # Builds a array scope builder
172
+ array: stampit().enclose ->
173
+ base = scopable.base @
174
+
175
+ stampit.mixIn (values...) ->
176
+ @scope.data[base.name] ||= values ? @["$#{base.name}"]
177
+ @
178
+
179
+ defaults =
180
+ boolean: true
181
+ array: []
182
+
183
+ # Extend indemma
184
+ model = window.model # TODO better way to get parent
185
+ record = window.record # TODO better way to get parent
186
+
187
+ model.scopable = true
188
+
189
+ # TODO use stampit to extend record and model
190
+ #record.mix (recordable) ->
191
+ # merge recordable, scopable.record
192
+
193
+ model.mix (modelable) ->
194
+ merge modelable, scopable.model
195
+
196
+ modelable.after_mix.push scopable.after_mix
197
+
198
+
199
+ # TODO create a deferred to better mix models
200
+ if model.associable
201
+ model.mix (modelable) ->
202
+ modelable.record.after_initialize.push ->
203
+ scopable.model.forward_scopes_to_associations.call @
204
+
205
+ model.associable.mix (singular_association, plural_association) ->
206
+
207
+ # reload (done callbacks...)
208
+ plural_association.all = plural_association.reload = (data, done, fail) ->
209
+ # TODO move route discovery to plural_association.after_mix
210
+ @route ||= "#{@parent.route}/#{@parent._id}/#{model.pluralize @resource}" if @parent?
211
+ promises = []
212
+
213
+ # TODO better calculate fetch settings
214
+ # dirty = 0
215
+ # if more than 5 records are dirty, we reftech all
216
+ # if dirty < 5
217
+ # for record in @
218
+ # promises.push record.reload()
219
+ # else we reload everthing!
220
+ # else
221
+ #
222
+ # for record in @
223
+ # dirty++ if record.dirty
224
+
225
+ if typeof data == 'function'
226
+ done = data
227
+ data = undefined
228
+
229
+ promises.push @scope.fetch.call @, data, null, scopable.record.failed
230
+
231
+ reload = $.when.apply jQuery, promises
232
+
233
+ # Update association with data sent from the server
234
+ # TODO implement setter on this association and let user to set
235
+ reload.done (records, status) ->
236
+
237
+ # Clear current stored cache on this association
238
+ # it to an empty array
239
+ Array.prototype.splice.call @, 0
240
+
241
+ # return if no records were found by the server
242
+ return unless records.length
243
+
244
+ singular_resource = model.singularize @resource
245
+
246
+ # Normalize json data for building on association
247
+ for record in records
248
+
249
+ # TODO only nest specified nested attributes on model definition
250
+ # TODO create special deserialization method no plural association
251
+ # TODO check if we need to nest attributes in other association tipes
252
+ for association_name in model[singular_resource].has_many
253
+ record["#{association_name}_attributes"] = record[association_name]
254
+ delete record[association_name]
255
+
256
+ # Load new records on this association
257
+ @add.apply @, records
258
+
259
+ # Override the response records object with added to association records
260
+ records.splice 0
261
+ records.push.apply records, @
262
+
263
+
264
+ reload.done done
265
+ reload.fail fail
266
+
267
+ reload
268
+
269
+ plural_association.each = (callback) ->
270
+ @route ||= "#{@parent.route}/#{@parent._id}/#{model.pluralize @resource}" if @parent?
271
+
272
+ # TODO cache models
273
+ @get().done (records) =>
274
+ for record in @
275
+ callback record
@@ -0,0 +1,46 @@
1
+ extend = require 'assimilate'
2
+ merge = extend.withStrategy 'deep'
3
+ stampit = require '../../vendor/stampit'
4
+
5
+ storable = stampit
6
+ store: (keypath, value, options) ->
7
+ collection = @database
8
+ keypath = keypath.toString().split '.'
9
+ key = keypath.pop()
10
+
11
+ for entry in keypath
12
+ collection[entry] ||= {}
13
+ collection = collection[entry]
14
+
15
+ if arguments.length == 1
16
+ @reads++
17
+ collection[key]
18
+ else
19
+ @writes++
20
+
21
+ # TODO use object.defineProperty
22
+ value.sustained = true
23
+ collection[key] = value
24
+
25
+ values: ->
26
+ Object.values @database
27
+ ,
28
+ type: 'object'
29
+ writes: 0
30
+ reads: 0
31
+ , ->
32
+ @database ||= {}
33
+ @
34
+
35
+
36
+ # Extend indemma
37
+ # TODO use stampit to extend record and model
38
+ model = window.model # TODO better way to get parent
39
+ record = window.record # TODO better way to get parent
40
+
41
+ model.storable = true
42
+ module.exports = storable
43
+ #model.mix (modelable) ->
44
+ # merge modelable, storable.model
45
+
46
+
@@ -0,0 +1,18 @@
1
+ root = exports ? window
2
+
3
+ # TODO better way to get core model definition
4
+ # model = require ...
5
+
6
+ # TODO implement method
7
+ # model[resource].validators_on 'field' # Get all validators related to this field
8
+
9
+ extend = require('assimilate')
10
+
11
+ extensions =
12
+ model:
13
+ human_attribute_name: (attribute_name) ->
14
+ @translation?.attributes?[attribute_name] or attribute_name
15
+
16
+ model.mix (modelable) ->
17
+ extend modelable, extensions.model
18
+