volt 0.8.14 → 0.8.15

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 (150) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/Readme.md +8 -2
  4. data/VERSION +1 -1
  5. data/app/volt/controllers/notices_controller.rb +1 -1
  6. data/app/volt/models/user.rb +2 -2
  7. data/app/volt/tasks/live_query/live_query_pool.rb +1 -1
  8. data/app/volt/tasks/query_tasks.rb +1 -1
  9. data/app/volt/tasks/store_tasks.rb +1 -1
  10. data/app/volt/tasks/user_tasks.rb +2 -2
  11. data/lib/volt/boot.rb +2 -2
  12. data/lib/volt/cli/asset_compile.rb +31 -27
  13. data/lib/volt/cli.rb +64 -65
  14. data/lib/volt/config.rb +25 -23
  15. data/lib/volt/console.rb +17 -16
  16. data/lib/volt/controllers/model_controller.rb +82 -80
  17. data/lib/volt/data_stores/data_store.rb +2 -2
  18. data/lib/volt/data_stores/mongo_driver.rb +2 -2
  19. data/lib/volt/extra_core/inflections.rb +2 -2
  20. data/lib/volt/extra_core/inflector/inflections.rb +185 -183
  21. data/lib/volt/extra_core/inflector/methods.rb +50 -48
  22. data/lib/volt/extra_core/string.rb +2 -2
  23. data/lib/volt/models/array_model.rb +93 -92
  24. data/lib/volt/models/cursor.rb +3 -2
  25. data/lib/volt/models/model.rb +248 -251
  26. data/lib/volt/models/model_hash_behaviour.rb +44 -44
  27. data/lib/volt/models/model_helpers.rb +38 -36
  28. data/lib/volt/models/model_state.rb +16 -17
  29. data/lib/volt/models/model_wrapper.rb +25 -24
  30. data/lib/volt/models/persistors/array_store.rb +145 -143
  31. data/lib/volt/models/persistors/base.rb +18 -16
  32. data/lib/volt/models/persistors/flash.rb +24 -22
  33. data/lib/volt/models/persistors/local_store.rb +46 -44
  34. data/lib/volt/models/persistors/model_identity_map.rb +10 -8
  35. data/lib/volt/models/persistors/model_store.rb +76 -76
  36. data/lib/volt/models/persistors/params.rb +19 -17
  37. data/lib/volt/models/persistors/query/query_listener.rb +65 -63
  38. data/lib/volt/models/persistors/query/query_listener_pool.rb +12 -10
  39. data/lib/volt/models/persistors/store.rb +28 -28
  40. data/lib/volt/models/persistors/store_factory.rb +12 -10
  41. data/lib/volt/models/persistors/store_state.rb +33 -31
  42. data/lib/volt/models/url.rb +96 -104
  43. data/lib/volt/models/validations.rb +56 -54
  44. data/lib/volt/models/validators/length_validator.rb +24 -22
  45. data/lib/volt/models/validators/presence_validator.rb +14 -12
  46. data/lib/volt/page/bindings/attribute_binding.rb +106 -106
  47. data/lib/volt/page/bindings/base_binding.rb +23 -21
  48. data/lib/volt/page/bindings/component_binding.rb +3 -1
  49. data/lib/volt/page/bindings/content_binding.rb +34 -34
  50. data/lib/volt/page/bindings/each_binding.rb +113 -113
  51. data/lib/volt/page/bindings/event_binding.rb +38 -34
  52. data/lib/volt/page/bindings/if_binding.rb +56 -54
  53. data/lib/volt/page/bindings/template_binding/grouped_controllers.rb +24 -22
  54. data/lib/volt/page/bindings/template_binding.rb +182 -185
  55. data/lib/volt/page/channel.rb +79 -77
  56. data/lib/volt/page/channel_stub.rb +29 -27
  57. data/lib/volt/page/document.rb +6 -5
  58. data/lib/volt/page/document_events.rb +54 -52
  59. data/lib/volt/page/page.rb +139 -138
  60. data/lib/volt/page/string_template_renderer.rb +36 -36
  61. data/lib/volt/page/sub_context.rb +26 -25
  62. data/lib/volt/page/targets/attribute_section.rb +27 -25
  63. data/lib/volt/page/targets/attribute_target.rb +7 -6
  64. data/lib/volt/page/targets/base_section.rb +27 -26
  65. data/lib/volt/page/targets/binding_document/base_node.rb +3 -1
  66. data/lib/volt/page/targets/binding_document/component_node.rb +85 -82
  67. data/lib/volt/page/targets/binding_document/html_node.rb +11 -9
  68. data/lib/volt/page/targets/dom_section.rb +78 -77
  69. data/lib/volt/page/targets/dom_target.rb +8 -6
  70. data/lib/volt/page/targets/dom_template.rb +90 -88
  71. data/lib/volt/page/targets/helpers/comment_searchers.rb +51 -49
  72. data/lib/volt/page/tasks.rb +59 -57
  73. data/lib/volt/page/template_renderer.rb +17 -14
  74. data/lib/volt/page/url_tracker.rb +26 -24
  75. data/lib/volt/reactive/computation.rb +87 -88
  76. data/lib/volt/reactive/dependency.rb +30 -28
  77. data/lib/volt/reactive/eventable.rb +64 -62
  78. data/lib/volt/reactive/hash_dependency.rb +25 -23
  79. data/lib/volt/reactive/reactive_accessors.rb +34 -32
  80. data/lib/volt/reactive/reactive_array.rb +162 -162
  81. data/lib/volt/reactive/reactive_hash.rb +37 -35
  82. data/lib/volt/router/routes.rb +99 -101
  83. data/lib/volt/server/component_handler.rb +20 -21
  84. data/lib/volt/server/component_templates.rb +72 -70
  85. data/lib/volt/server/html_parser/attribute_scope.rb +109 -99
  86. data/lib/volt/server/html_parser/each_scope.rb +17 -16
  87. data/lib/volt/server/html_parser/if_view_scope.rb +51 -49
  88. data/lib/volt/server/html_parser/sandlebars_parser.rb +184 -177
  89. data/lib/volt/server/html_parser/textarea_scope.rb +24 -22
  90. data/lib/volt/server/html_parser/view_handler.rb +66 -65
  91. data/lib/volt/server/html_parser/view_parser.rb +23 -21
  92. data/lib/volt/server/html_parser/view_scope.rb +142 -141
  93. data/lib/volt/server/rack/asset_files.rb +81 -79
  94. data/lib/volt/server/rack/component_code.rb +17 -15
  95. data/lib/volt/server/rack/component_html_renderer.rb +14 -12
  96. data/lib/volt/server/rack/component_paths.rb +72 -71
  97. data/lib/volt/server/rack/index_files.rb +36 -39
  98. data/lib/volt/server/rack/opal_files.rb +43 -41
  99. data/lib/volt/server/rack/source_map_server.rb +23 -21
  100. data/lib/volt/server/socket_connection_handler.rb +46 -45
  101. data/lib/volt/server/socket_connection_handler_stub.rb +21 -19
  102. data/lib/volt/server.rb +60 -58
  103. data/lib/volt/spec/setup.rb +3 -3
  104. data/lib/volt/tasks/dispatcher.rb +24 -23
  105. data/lib/volt/tasks/task_handler.rb +35 -33
  106. data/lib/volt/utils/ejson.rb +8 -6
  107. data/lib/volt/utils/generic_counting_pool.rb +33 -31
  108. data/lib/volt/utils/generic_pool.rb +73 -70
  109. data/lib/volt/utils/local_storage.rb +42 -38
  110. data/lib/volt/volt/environment.rb +1 -1
  111. data/lib/volt.rb +44 -42
  112. data/spec/apps/kitchen_sink/app/main/assets/css/todos.css +28 -0
  113. data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
  114. data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +2 -2
  115. data/spec/apps/kitchen_sink/app/main/controllers/todos_controller.rb +17 -0
  116. data/spec/apps/kitchen_sink/app/main/views/main/main.html +1 -0
  117. data/spec/apps/kitchen_sink/app/main/views/todos/index.html +24 -0
  118. data/spec/apps/kitchen_sink/config.ru +1 -1
  119. data/spec/controllers/reactive_accessors_spec.rb +5 -5
  120. data/spec/extra_core/inflector_spec.rb +2 -2
  121. data/spec/integration/list_spec.rb +68 -0
  122. data/spec/models/model_spec.rb +57 -57
  123. data/spec/models/persistors/params_spec.rb +6 -6
  124. data/spec/models/persistors/store_spec.rb +7 -7
  125. data/spec/models/validations_spec.rb +3 -3
  126. data/spec/page/bindings/content_binding_spec.rb +7 -7
  127. data/spec/page/bindings/template_binding_spec.rb +4 -5
  128. data/spec/page/sub_context_spec.rb +2 -2
  129. data/spec/reactive/computation_spec.rb +10 -10
  130. data/spec/reactive/dependency_spec.rb +2 -2
  131. data/spec/reactive/eventable_spec.rb +4 -4
  132. data/spec/reactive/reactive_array_spec.rb +13 -13
  133. data/spec/router/routes_spec.rb +5 -5
  134. data/spec/server/html_parser/sandlebars_parser_spec.rb +9 -9
  135. data/spec/server/html_parser/view_parser_spec.rb +27 -27
  136. data/spec/server/rack/asset_files_spec.rb +5 -5
  137. data/spec/server/rack/component_paths_spec.rb +2 -2
  138. data/spec/tasks/live_query_spec.rb +2 -2
  139. data/spec/tasks/query_tasks.rb +1 -1
  140. data/spec/tasks/query_tracker_spec.rb +1 -1
  141. data/spec/templates/targets/binding_document/component_node_spec.rb +2 -2
  142. data/spec/utils/generic_counting_pool_spec.rb +2 -2
  143. data/spec/utils/generic_pool_spec.rb +2 -2
  144. data/templates/component/controllers/main_controller.rb +1 -1
  145. data/templates/model/model.rb.tt +2 -2
  146. data/templates/newgem/app/newgem/controllers/main_controller.rb.tt +2 -2
  147. data/templates/project/app/main/controllers/main_controller.rb +1 -1
  148. data/templates/project/config.ru +1 -1
  149. metadata +10 -3
  150. data/app/volt/assets/js/vertxbus.js +0 -216
@@ -6,335 +6,332 @@ require 'volt/models/validations'
6
6
  require 'volt/models/model_state'
7
7
  require 'volt/reactive/reactive_hash'
8
8
 
9
- class NilMethodCall < NoMethodError
10
- end
9
+ module Volt
11
10
 
11
+ class NilMethodCall < NoMethodError
12
+ end
12
13
 
13
- class Model
14
- include ModelWrapper
15
- include ModelHelpers
16
- include ModelHashBehaviour
17
- include Validations
18
- include ModelState
14
+ class Model
15
+ include ModelWrapper
16
+ include ModelHelpers
17
+ include ModelHashBehaviour
18
+ include Validations
19
+ include ModelState
19
20
 
20
- attr_reader :attributes
21
- attr_reader :parent, :path, :persistor, :options
21
+ attr_reader :attributes
22
+ attr_reader :parent, :path, :persistor, :options
22
23
 
23
- def initialize(attributes={}, options={}, initial_state=nil)
24
- @deps = HashDependency.new
25
- self.options = options
24
+ def initialize(attributes = {}, options = {}, initial_state = nil)
25
+ @deps = HashDependency.new
26
+ self.options = options
26
27
 
27
- self.send(:attributes=, attributes, true)
28
+ send(:attributes=, attributes, true)
28
29
 
29
- # Models start in a loaded state since they are normally setup from an
30
- # ArrayModel, which will have the data when they get added.
31
- @state = :loaded
30
+ # Models start in a loaded state since they are normally setup from an
31
+ # ArrayModel, which will have the data when they get added.
32
+ @state = :loaded
32
33
 
33
- @persistor.loaded(initial_state) if @persistor
34
- end
34
+ @persistor.loaded(initial_state) if @persistor
35
+ end
35
36
 
36
- # the id is stored in a field named _id, so we setup _id to proxy to this
37
- def _id
38
- @attributes && @attributes[:_id]
39
- end
37
+ # the id is stored in a field named _id, so we setup _id to proxy to this
38
+ def _id
39
+ @attributes && @attributes[:_id]
40
+ end
40
41
 
41
- def _id=(val)
42
- self.__id = val
43
- end
42
+ def _id=(val)
43
+ self.__id = val
44
+ end
44
45
 
45
- # Update the options
46
- def options=(options)
47
- @options = options
48
- @parent = options[:parent]
49
- @path = options[:path] || []
50
- @class_paths = options[:class_paths]
51
- @persistor = setup_persistor(options[:persistor])
52
- end
46
+ # Update the options
47
+ def options=(options)
48
+ @options = options
49
+ @parent = options[:parent]
50
+ @path = options[:path] || []
51
+ @class_paths = options[:class_paths]
52
+ @persistor = setup_persistor(options[:persistor])
53
+ end
53
54
 
54
- # Assign multiple attributes as a hash, directly.
55
- def attributes=(attrs, initial_setup=false)
56
- @attributes = {}
55
+ # Assign multiple attributes as a hash, directly.
56
+ def attributes=(attrs, initial_setup = false)
57
+ @attributes = {}
57
58
 
58
- attrs = wrap_values(attrs)
59
+ attrs = wrap_values(attrs)
60
+
61
+ if attrs
62
+ # Assign id first
63
+ id = attrs.delete(:_id)
64
+ self._id = id if id
65
+
66
+ # Assign each attribute using setters
67
+ attrs.each_pair do |key, value|
68
+ if self.respond_to?(:"#{key}=")
69
+ # If a method without an underscore is defined, call that.
70
+ send(:"#{key}=", value)
71
+ else
72
+ # Otherwise, use the _ version
73
+ send(:"_#{key}=", value)
74
+ end
75
+ end
76
+ else
77
+ @attributes = attrs
78
+ end
59
79
 
60
- if attrs
61
- # Assign id first
62
- id = attrs.delete(:_id)
63
- self._id = id if id
80
+ # Trigger and change all
81
+ @deps.changed_all!
82
+ @deps = HashDependency.new
64
83
 
65
- # Assign each attribute using setters
66
- attrs.each_pair do |key, value|
67
- if self.respond_to?(:"#{key}=")
68
- # If a method without an underscore is defined, call that.
69
- self.send(:"#{key}=", value)
70
- else
71
- # Otherwise, use the _ version
72
- self.send(:"_#{key}=", value)
84
+ unless initial_setup
85
+
86
+ # Let the persistor know something changed
87
+ if @persistor
88
+ # the changed method on a persistor should return a promise that will
89
+ # be resolved when the save is complete, or fail with a hash of errors.
90
+ return @persistor.changed
73
91
  end
74
92
  end
75
- else
76
- @attributes = attrs
77
93
  end
78
94
 
79
- # Trigger and change all
80
- @deps.changed_all!
81
- @deps = HashDependency.new
82
-
83
- unless initial_setup
95
+ alias_method :assign_attributes, :attributes=
84
96
 
85
- # Let the persistor know something changed
86
- if @persistor
87
- # the changed method on a persistor should return a promise that will
88
- # be resolved when the save is complete, or fail with a hash of errors.
89
- return @persistor.changed
97
+ # Pass the comparison through
98
+ def ==(val)
99
+ if val.is_a?(Model)
100
+ # Use normal comparison for a model
101
+ super
102
+ else
103
+ # Compare to attributes otherwise
104
+ attributes == val
90
105
  end
91
106
  end
92
- end
93
- alias_method :assign_attributes, :attributes=
94
-
95
- # Pass the comparison through
96
- def ==(val)
97
- if val.is_a?(Model)
98
- # Use normal comparison for a model
99
- return super
100
- else
101
- # Compare to attributes otherwise
102
- return attributes == val
103
- end
104
- end
105
107
 
106
- # Pass through needed
107
- def !
108
- !attributes
109
- end
108
+ # Pass through needed
109
+ def !
110
+ !attributes
111
+ end
110
112
 
111
113
 
112
- def method_missing(method_name, *args, &block)
113
- if method_name[0] == '_'
114
- if method_name[-1] == '='
115
- # Assigning an attribute with =
116
- assign_attribute(method_name, *args, &block)
114
+ def method_missing(method_name, *args, &block)
115
+ if method_name[0] == '_'
116
+ if method_name[-1] == '='
117
+ # Assigning an attribute with =
118
+ assign_attribute(method_name, *args, &block)
119
+ else
120
+ read_attribute(method_name)
121
+ end
117
122
  else
118
- read_attribute(method_name)
123
+ # Call on parent
124
+ super
119
125
  end
120
- else
121
- # Call on parent
122
- super
123
126
  end
124
- end
125
127
 
126
- # Do the assignment to a model and trigger a changed event
127
- def assign_attribute(method_name, *args, &block)
128
- self.expand!
129
- # Assign, without the =
130
- attribute_name = method_name[1..-2].to_sym
128
+ # Do the assignment to a model and trigger a changed event
129
+ def assign_attribute(method_name, *args, &block)
130
+ self.expand!
131
+ # Assign, without the =
132
+ attribute_name = method_name[1..-2].to_sym
131
133
 
132
- value = args[0]
134
+ value = args[0]
133
135
 
134
- @attributes[attribute_name] = wrap_value(value, [attribute_name])
136
+ @attributes[attribute_name] = wrap_value(value, [attribute_name])
135
137
 
136
- @deps.changed!(attribute_name)
138
+ @deps.changed!(attribute_name)
137
139
 
138
- # Let the persistor know something changed
139
- @persistor.changed(attribute_name) if @persistor
140
- end
140
+ # Let the persistor know something changed
141
+ @persistor.changed(attribute_name) if @persistor
142
+ end
141
143
 
142
- # When reading an attribute, we need to handle reading on:
143
- # 1) a nil model, which returns a wrapped error
144
- # 2) reading directly from attributes
145
- # 3) trying to read a key that doesn't exist.
146
- def read_attribute(method_name)
147
- # Reading an attribute, we may get back a nil model.
148
- method_name = method_name.to_sym
149
-
150
- if method_name[0] != '_' && @attributes == nil
151
- # The method we are calling is on a nil model, return a wrapped
152
- # exception.
153
- return return_undefined_method(method_name)
154
- else
155
- attr_name = method_name[1..-1].to_sym
156
- # See if the value is in attributes
157
- value = (@attributes && @attributes[attr_name])
158
-
159
- # Track dependency
160
- @deps.depend(attr_name)
161
-
162
- if value
163
- # key was in attributes or cache
164
- return value
144
+ # When reading an attribute, we need to handle reading on:
145
+ # 1) a nil model, which returns a wrapped error
146
+ # 2) reading directly from attributes
147
+ # 3) trying to read a key that doesn't exist.
148
+ def read_attribute(method_name)
149
+ # Reading an attribute, we may get back a nil model.
150
+ method_name = method_name.to_sym
151
+
152
+ if method_name[0] != '_' && @attributes == nil
153
+ # The method we are calling is on a nil model, return a wrapped
154
+ # exception.
155
+ return_undefined_method(method_name)
165
156
  else
166
- # TODO: implement a timed out cache flusing
167
- new_model = read_new_model(attr_name)
168
- @attributes ||= {}
169
- @attributes[attr_name] = new_model
157
+ attr_name = method_name[1..-1].to_sym
158
+ # See if the value is in attributes
159
+ value = (@attributes && @attributes[attr_name])
170
160
 
171
- return new_model
161
+ # Track dependency
162
+ @deps.depend(attr_name)
163
+
164
+ if value
165
+ # key was in attributes or cache
166
+ value
167
+ else
168
+ new_model = read_new_model(attr_name)
169
+ @attributes ||= {}
170
+ @attributes[attr_name] = new_model
171
+ new_model
172
+ end
172
173
  end
173
174
  end
174
- end
175
175
 
176
- # Get a new model, make it easy to override
177
- def read_new_model(method_name)
178
- if @persistor && @persistor.respond_to?(:read_new_model)
179
- return @persistor.read_new_model(method_name)
180
- else
181
- opts = @options.merge(parent: self, path: path + [method_name])
182
- if method_name.plural?
183
- return new_array_model([], opts)
176
+ # Get a new model, make it easy to override
177
+ def read_new_model(method_name)
178
+ if @persistor && @persistor.respond_to?(:read_new_model)
179
+ return @persistor.read_new_model(method_name)
184
180
  else
185
- return new_model(nil, opts)
181
+ opts = @options.merge(parent: self, path: path + [method_name])
182
+ if method_name.plural?
183
+ return new_array_model([], opts)
184
+ else
185
+ return new_model(nil, opts)
186
+ end
186
187
  end
187
188
  end
188
- end
189
189
 
190
- def return_undefined_method(method_name)
191
- # Methods called on nil capture an error so the user can know where
192
- # their nil calls are. This error can be re-raised at a later point.
193
- begin
194
- raise NilMethodCall.new("undefined method `#{method_name}' for #{self.to_s}")
195
- rescue => e
196
- result = e
197
-
198
- # Cleanup backtrace
199
- # TODO: this could be better
200
- result.backtrace.reject! {|line| line['lib/models/model.rb'] || line['lib/models/live_value.rb'] }
190
+ def return_undefined_method(method_name)
191
+ # Methods called on nil capture an error so the user can know where
192
+ # their nil calls are. This error can be re-raised at a later point.
193
+ begin
194
+ raise NilMethodCall.new("undefined method `#{method_name}' for #{self.to_s}")
195
+ rescue => e
196
+ result = e
197
+
198
+ # Cleanup backtrace
199
+ # TODO: this could be better
200
+ result.backtrace.reject! { |line| line['lib/models/model.rb'] || line['lib/models/live_value.rb'] }
201
+ end
201
202
  end
202
- end
203
203
 
204
- def new_model(attributes, options)
205
- class_at_path(options[:path]).new(attributes, options)
206
- end
204
+ def new_model(attributes, options)
205
+ class_at_path(options[:path]).new(attributes, options)
206
+ end
207
207
 
208
- def new_array_model(attributes, options)
209
- # Start with an empty query
210
- options = options.dup
211
- options[:query] = {}
208
+ def new_array_model(attributes, options)
209
+ # Start with an empty query
210
+ options = options.dup
211
+ options[:query] = {}
212
212
 
213
- ArrayModel.new(attributes, options)
214
- end
213
+ ArrayModel.new(attributes, options)
214
+ end
215
215
 
216
- def trigger_by_attribute!(event_name, attribute, *passed_args)
217
- trigger_by_scope!(event_name, *passed_args) do |scope|
218
- method_name, *args, block = scope
216
+ def trigger_by_attribute!(event_name, attribute, *passed_args)
217
+ trigger_by_scope!(event_name, *passed_args) do |scope|
218
+ method_name, *args, block = scope
219
219
 
220
- # TODO: Opal bug
221
- args ||= []
220
+ # TODO: Opal bug
221
+ args ||= []
222
222
 
223
- # Any methods without _ are not directly related to one attribute, so
224
- # they should all trigger
225
- !method_name || method_name[0] != '_' || (method_name == attribute.to_sym && args.size == 0)
223
+ # Any methods without _ are not directly related to one attribute, so
224
+ # they should all trigger
225
+ !method_name || method_name[0] != '_' || (method_name == attribute.to_sym && args.size == 0)
226
+ end
226
227
  end
227
- end
228
228
 
229
- # If this model is nil, it makes it into a hash model, then
230
- # sets it up to track from the parent.
231
- def expand!
232
- if attributes.nil?
233
- @attributes = {}
234
- if @parent
235
- @parent.expand!
229
+ # If this model is nil, it makes it into a hash model, then
230
+ # sets it up to track from the parent.
231
+ def expand!
232
+ if attributes.nil?
233
+ @attributes = {}
234
+ if @parent
235
+ @parent.expand!
236
236
 
237
- @parent.send(:"_#{@path.last}=", self)
237
+ @parent.send(:"_#{@path.last}=", self)
238
+ end
238
239
  end
239
240
  end
240
- end
241
-
242
- # Initialize an empty array and append to it
243
- def <<(value)
244
- if @parent
245
- @parent.expand!
246
- else
247
- raise "Model data should be stored in sub collections."
248
- end
249
241
 
250
- # Grab the last section of the path, so we can do the assign on the parent
251
- path = @path.last
252
- result = @parent.send(path)
242
+ # Initialize an empty array and append to it
243
+ def <<(value)
244
+ if @parent
245
+ @parent.expand!
246
+ else
247
+ raise "Model data should be stored in sub collections."
248
+ end
253
249
 
254
- if result.nil?
255
- # If this isn't a model yet, instantiate it
256
- @parent.send(:"#{path}=", new_array_model([], @options))
250
+ # Grab the last section of the path, so we can do the assign on the parent
251
+ path = @path.last
257
252
  result = @parent.send(path)
258
- end
259
253
 
260
- # Add the new item
261
- result << value
254
+ if result.nil?
255
+ # If this isn't a model yet, instantiate it
256
+ @parent.send(:"#{path}=", new_array_model([], @options))
257
+ result = @parent.send(path)
258
+ end
262
259
 
263
- return nil
264
- end
260
+ # Add the new item
261
+ result << value
265
262
 
266
- def inspect
267
- str = nil
268
- Computation.run_without_tracking do
269
- str = "<#{self.class.to_s}:#{object_id} #{attributes.inspect}>"
263
+ nil
270
264
  end
271
265
 
272
- return str
273
- end
274
-
275
- def save!
276
- # Compute the erros once
277
- errors = self.errors
278
-
279
- if errors.size == 0
280
- save_to = options[:save_to]
281
- if save_to
282
- if save_to.is_a?(ArrayModel)
283
- # Add to the collection
284
- new_model = save_to << self.attributes
285
-
286
- # Set the buffer's id to track the main model's id
287
- self.attributes[:_id] = new_model._id
288
- options[:save_to] = new_model
266
+ def inspect
267
+ Computation.run_without_tracking do
268
+ "<#{self.class.to_s}:#{object_id} #{attributes.inspect}>"
269
+ end
270
+ end
289
271
 
290
- # TODO: return a promise that resolves if the append works
272
+ def save!
273
+ # Compute the erros once
274
+ errors = self.errors
275
+
276
+ if errors.size == 0
277
+ save_to = options[:save_to]
278
+ if save_to
279
+ if save_to.is_a?(ArrayModel)
280
+ # Add to the collection
281
+ new_model = save_to << self.attributes
282
+
283
+ # Set the buffer's id to track the main model's id
284
+ self.attributes[:_id] = new_model._id
285
+ options[:save_to] = new_model
286
+
287
+ # TODO: return a promise that resolves if the append works
288
+ else
289
+ # We have a saved model
290
+ return save_to.assign_attributes(self.attributes)
291
+ end
291
292
  else
292
- # We have a saved model
293
- return save_to.assign_attributes(self.attributes)
293
+ raise "Model is not a buffer, can not be saved, modifications should be persisted as they are made."
294
294
  end
295
+
296
+ Promise.new.resolve({})
295
297
  else
296
- raise "Model is not a buffer, can not be saved, modifications should be persisted as they are made."
297
- end
298
+ # Some errors, mark all fields
299
+ self.class.validations.keys.each do |key|
300
+ mark_field!(key.to_sym)
301
+ end
298
302
 
299
- return Promise.new.resolve({})
300
- else
301
- # Some errors, mark all fields
302
- self.class.validations.keys.each do |key|
303
- mark_field!(key.to_sym)
303
+ Promise.new.reject(errors)
304
304
  end
305
-
306
- return Promise.new.reject(errors)
307
305
  end
308
- end
309
306
 
310
307
 
311
- # Returns a buffered version of the model
312
- def buffer
313
- model_path = options[:path]
308
+ # Returns a buffered version of the model
309
+ def buffer
310
+ model_path = options[:path]
314
311
 
315
- # When we grab a buffer off of a plual class (subcollection), we get it as a model.
316
- if model_path.last.plural? && model_path[-1] != :[]
317
- model_klass = class_at_path(model_path + [:[]])
318
- else
319
- model_klass = class_at_path(model_path)
320
- end
312
+ # When we grab a buffer off of a plual class (subcollection), we get it as a model.
313
+ if model_path.last.plural? && model_path[-1] != :[]
314
+ model_klass = class_at_path(model_path + [:[]])
315
+ else
316
+ model_klass = class_at_path(model_path)
317
+ end
321
318
 
322
- new_options = options.merge(path: model_path, save_to: self).reject {|k,_| k.to_sym == :persistor }
323
- model = model_klass.new({}, new_options, :loading)
319
+ new_options = options.merge(path: model_path, save_to: self).reject { |k, _| k.to_sym == :persistor }
320
+ model = model_klass.new({}, new_options, :loading)
324
321
 
325
- if state == :loaded
326
- setup_buffer(model)
327
- else
328
- self.parent.then do
322
+ if state == :loaded
329
323
  setup_buffer(model)
324
+ else
325
+ self.parent.then do
326
+ setup_buffer(model)
327
+ end
330
328
  end
331
- end
332
329
 
333
- return model
334
- end
330
+ model
331
+ end
335
332
 
336
333
 
337
- private
334
+ private
338
335
  def setup_buffer(model)
339
336
  model.attributes = self.attributes
340
337
  model.change_state_to(:loaded)
@@ -346,5 +343,5 @@ class Model
346
343
  @persistor = persistor.new(self)
347
344
  end
348
345
  end
349
-
346
+ end
350
347
  end