ende 0.2.9 → 0.2.10

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 (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
+