volt 0.7.23 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +8 -1
  3. data/CHANGELOG.md +22 -0
  4. data/Gemfile +8 -0
  5. data/Guardfile +2 -2
  6. data/Readme.md +139 -136
  7. data/VERSION +1 -1
  8. data/app/volt/assets/js/setImmediate.js +175 -0
  9. data/app/volt/tasks/live_query/data_store.rb +0 -2
  10. data/app/volt/tasks/live_query/live_query.rb +4 -4
  11. data/docs/GETTING_STARTED.md +24 -3
  12. data/docs/WHY.md +1 -22
  13. data/lib/volt.rb +20 -1
  14. data/lib/volt/console.rb +20 -0
  15. data/lib/volt/controllers/model_controller.rb +25 -11
  16. data/lib/volt/extra_core/object.rb +2 -14
  17. data/lib/volt/extra_core/string.rb +4 -0
  18. data/lib/volt/models.rb +0 -1
  19. data/lib/volt/models/array_model.rb +8 -16
  20. data/lib/volt/models/cursor.rb +1 -1
  21. data/lib/volt/models/model.rb +40 -60
  22. data/lib/volt/models/model_hash_behaviour.rb +10 -24
  23. data/lib/volt/models/model_helpers.rb +2 -2
  24. data/lib/volt/models/model_state.rb +1 -1
  25. data/lib/volt/models/model_wrapper.rb +4 -4
  26. data/lib/volt/models/persistors/array_store.rb +44 -28
  27. data/lib/volt/models/persistors/base.rb +1 -1
  28. data/lib/volt/models/persistors/model_store.rb +1 -1
  29. data/lib/volt/models/persistors/params.rb +5 -1
  30. data/lib/volt/models/persistors/query/query_listener.rb +2 -0
  31. data/lib/volt/models/persistors/store.rb +3 -2
  32. data/lib/volt/models/persistors/store_state.rb +7 -2
  33. data/lib/volt/models/url.rb +35 -29
  34. data/lib/volt/models/validations.rb +7 -17
  35. data/lib/volt/page/bindings/attribute_binding.rb +57 -39
  36. data/lib/volt/page/bindings/base_binding.rb +0 -14
  37. data/lib/volt/page/bindings/content_binding.rb +15 -18
  38. data/lib/volt/page/bindings/each_binding.rb +67 -34
  39. data/lib/volt/page/bindings/if_binding.rb +15 -12
  40. data/lib/volt/page/bindings/template_binding.rb +77 -59
  41. data/lib/volt/page/bindings/template_binding/grouped_controllers.rb +19 -4
  42. data/lib/volt/page/channel.rb +22 -38
  43. data/lib/volt/page/channel_stub.rb +3 -6
  44. data/lib/volt/page/page.rb +24 -26
  45. data/lib/volt/page/string_template_renderer.rb +46 -0
  46. data/lib/volt/page/sub_context.rb +7 -1
  47. data/lib/volt/page/targets/binding_document/component_node.rb +11 -9
  48. data/lib/volt/page/tasks.rb +3 -2
  49. data/lib/volt/page/url_tracker.rb +4 -3
  50. data/lib/volt/reactive/computation.rb +131 -0
  51. data/lib/volt/reactive/dependency.rb +71 -0
  52. data/lib/volt/reactive/eventable.rb +82 -0
  53. data/lib/volt/reactive/hash_dependency.rb +36 -0
  54. data/lib/volt/{controllers → reactive}/reactive_accessors.rb +8 -11
  55. data/lib/volt/reactive/reactive_array.rb +100 -193
  56. data/lib/volt/reactive/reactive_hash.rb +49 -0
  57. data/lib/volt/server/html_parser/attribute_scope.rb +24 -4
  58. data/lib/volt/server/html_parser/if_view_scope.rb +15 -15
  59. data/lib/volt/server/html_parser/view_scope.rb +31 -1
  60. data/spec/apps/kitchen_sink/Gemfile +4 -8
  61. data/spec/apps/kitchen_sink/app/main/config/dependencies.rb +8 -0
  62. data/spec/apps/kitchen_sink/app/main/config/routes.rb +8 -1
  63. data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +8 -0
  64. data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +73 -0
  65. data/spec/apps/kitchen_sink/app/main/views/main/index.html +6 -1
  66. data/spec/apps/kitchen_sink/app/main/views/main/main.html +26 -6
  67. data/spec/apps/kitchen_sink/app/main/views/main/store.html +6 -0
  68. data/spec/controllers/reactive_accessors_spec.rb +13 -15
  69. data/spec/integration/bindings_spec.rb +159 -0
  70. data/spec/integration/templates_spec.rb +15 -0
  71. data/spec/models/model_spec.rb +130 -228
  72. data/spec/reactive/computation_spec.rb +63 -0
  73. data/spec/reactive/dependency_spec.rb +5 -0
  74. data/spec/reactive/eventable_spec.rb +48 -0
  75. data/spec/reactive/reactive_array_spec.rb +97 -0
  76. data/spec/router/routes_spec.rb +26 -27
  77. data/spec/server/html_parser/view_parser_spec.rb +3 -21
  78. data/spec/server/rack/asset_files_spec.rb +1 -1
  79. data/templates/project/app/main/views/main/main.html +2 -2
  80. metadata +29 -41
  81. data/lib/volt/extra_core/time.rb +0 -16
  82. data/lib/volt/page/draw_cycle.rb +0 -31
  83. data/lib/volt/page/memory_test.rb +0 -26
  84. data/lib/volt/page/reactive_template.rb +0 -32
  85. data/lib/volt/reactive/array_extensions.rb +0 -12
  86. data/lib/volt/reactive/destructive_methods.rb +0 -19
  87. data/lib/volt/reactive/event_chain.rb +0 -125
  88. data/lib/volt/reactive/events.rb +0 -216
  89. data/lib/volt/reactive/object_tracking.rb +0 -14
  90. data/lib/volt/reactive/reactive_block.rb +0 -88
  91. data/lib/volt/reactive/reactive_generator.rb +0 -44
  92. data/lib/volt/reactive/reactive_tags.rb +0 -71
  93. data/lib/volt/reactive/reactive_value.rb +0 -427
  94. data/lib/volt/reactive/string_extensions.rb +0 -31
  95. data/spec/integration/test_integration_spec.rb +0 -14
  96. data/spec/models/event_chain_spec.rb +0 -150
  97. data/spec/models/model_buffers_spec.rb +0 -9
  98. data/spec/models/old_model_spec.rb +0 -67
  99. data/spec/models/reactive_array_spec.rb +0 -364
  100. data/spec/models/reactive_block_spec.rb +0 -13
  101. data/spec/models/reactive_call_times_spec.rb +0 -28
  102. data/spec/models/reactive_generator_spec.rb +0 -58
  103. data/spec/models/reactive_tags_spec.rb +0 -35
  104. data/spec/models/reactive_value_spec.rb +0 -370
  105. data/spec/models/store_spec.rb +0 -16
  106. data/spec/models/string_extensions_spec.rb +0 -57
@@ -23,6 +23,10 @@ class String
23
23
  Inflector.singularize(self)
24
24
  end
25
25
 
26
+ def titleize
27
+ self.gsub('_', ' ').split(' ').map {|w| w.capitalize }.join(' ')
28
+ end
29
+
26
30
  def plural?
27
31
  # TODO: Temp implementation
28
32
  self.pluralize == self
@@ -1,5 +1,4 @@
1
1
  require 'volt/extra_core/extra_core'
2
- require 'volt/reactive/reactive_value'
3
2
  require 'volt/models/model'
4
3
  require 'volt/models/cursor'
5
4
  require 'volt/models/persistors/store_factory'
@@ -1,3 +1,4 @@
1
+ require 'volt/reactive/reactive_array'
1
2
  require 'volt/models/model_wrapper'
2
3
  require 'volt/models/model_helpers'
3
4
  require 'volt/models/model_state'
@@ -36,21 +37,14 @@ class ArrayModel < ReactiveArray
36
37
  @persistor.loaded if @persistor
37
38
  end
38
39
 
39
- tag_method(:find) do
40
- destructive!
41
- pass_reactive!
42
- end
43
- def find(*args)
40
+ def find(*args, &block)
44
41
  if @persistor
45
- return @persistor.find(*args)
42
+ return @persistor.find(*args, &block)
46
43
  else
47
44
  raise "this model's persistance layer does not support find, try using store"
48
45
  end
49
46
  end
50
47
 
51
- tag_method(:then) do
52
- destructive!
53
- end
54
48
  def then(*args, &block)
55
49
  if @persistor
56
50
  return @persistor.then(*args, &block)
@@ -65,9 +59,10 @@ class ArrayModel < ReactiveArray
65
59
 
66
60
  # Make sure it gets wrapped
67
61
  def <<(model)
68
- if model.cur.is_a?(Model)
62
+ # TODORW: handle changes
63
+ if model.is_a?(Model)
69
64
  # Set the new path
70
- model.cur.options = @options.merge(path: @options[:path] + [:[]])
65
+ model.options = @options.merge(path: @options[:path] + [:[]])
71
66
  else
72
67
  model = wrap_values([model]).first
73
68
  end
@@ -117,12 +112,9 @@ class ArrayModel < ReactiveArray
117
112
  end
118
113
 
119
114
  # Otherwise inspect normally
120
- super
115
+ return super
121
116
  end
122
117
 
123
- tag_method(:buffer) do
124
- destructive!
125
- end
126
118
  def buffer
127
119
  model_path = options[:path] + [:[]]
128
120
  model_klass = class_at_path(model_path)
@@ -130,7 +122,7 @@ class ArrayModel < ReactiveArray
130
122
  new_options = options.merge(path: model_path, save_to: self).reject {|k,_| k.to_sym == :persistor }
131
123
  model = model_klass.new({}, new_options)
132
124
 
133
- return ReactiveValue.new(model)
125
+ return model
134
126
  end
135
127
 
136
128
  private
@@ -1,6 +1,6 @@
1
1
  require 'volt/models/array_model'
2
2
 
3
3
  class Cursor < ArrayModel
4
-
4
+
5
5
 
6
6
  end
@@ -1,42 +1,34 @@
1
1
  require 'volt/models/model_wrapper'
2
2
  require 'volt/models/array_model'
3
3
  require 'volt/models/model_helpers'
4
- require 'volt/reactive/object_tracking'
5
4
  require 'volt/models/model_hash_behaviour'
6
5
  require 'volt/models/validations'
7
6
  require 'volt/models/model_state'
8
-
7
+ require 'volt/reactive/reactive_hash'
9
8
 
10
9
  class NilMethodCall < NoMethodError
11
- def true?
12
- false
13
- end
14
-
15
- def false?
16
- true
17
- end
18
10
  end
19
11
 
12
+
20
13
  class Model
21
- include ReactiveTags
22
14
  include ModelWrapper
23
- include ObjectTracking
24
15
  include ModelHelpers
25
16
  include ModelHashBehaviour
26
17
  include Validations
27
18
  include ModelState
28
19
 
29
- attr_accessor :attributes
20
+ attr_reader :attributes
30
21
  attr_reader :parent, :path, :persistor, :options
31
22
 
32
23
  def initialize(attributes={}, options={}, initial_state=nil)
24
+ @deps = HashDependency.new
33
25
  self.options = options
34
26
 
35
27
  self.send(:attributes=, attributes, true)
36
28
 
37
29
  @cache = {}
38
30
 
39
- # Models stat in a loaded state since they are normally setup from an
31
+ # Models start in a loaded state since they are normally setup from an
40
32
  # ArrayModel, which will have the data when they get added.
41
33
  @state = :loaded
42
34
 
@@ -56,8 +48,11 @@ class Model
56
48
  def attributes=(attrs, initial_setup=false)
57
49
  @attributes = wrap_values(attrs)
58
50
 
51
+ # Trigger and change all
52
+ @deps.changed_all!
53
+ @deps = HashDependency.new
54
+
59
55
  unless initial_setup
60
- trigger!('changed')
61
56
 
62
57
  # Let the persistor know something changed
63
58
  if @persistor
@@ -86,11 +81,6 @@ class Model
86
81
  end
87
82
 
88
83
 
89
- tag_all_methods do
90
- pass_reactive! do |method_name|
91
- method_name[0] == '_' && method_name[-1] == '='
92
- end
93
- end
94
84
  def method_missing(method_name, *args, &block)
95
85
  if method_name[0] == '_'
96
86
  if method_name[-1] == '='
@@ -116,10 +106,9 @@ class Model
116
106
  attribute_name = method_name[0..-2].to_sym
117
107
 
118
108
  value = args[0]
119
- __assign_element(attribute_name, value)
120
109
 
121
110
  attributes[attribute_name] = wrap_value(value, [attribute_name])
122
- trigger_by_attribute!('changed', attribute_name)
111
+ @deps.changed!(attribute_name)
123
112
 
124
113
  # Let the persistor know something changed
125
114
  @persistor.changed(attribute_name) if @persistor
@@ -144,6 +133,9 @@ class Model
144
133
  # Also check @cache
145
134
  value ||= (@cache && @cache[method_name])
146
135
 
136
+ # Track dependency
137
+ @deps.depend(method_name)
138
+
147
139
  if value
148
140
  # key was in attributes or cache
149
141
  return value
@@ -162,9 +154,14 @@ class Model
162
154
  # Get a new model, make it easy to override
163
155
  def read_new_model(method_name)
164
156
  if @persistor && @persistor.respond_to?(:read_new_model)
165
- @persistor.read_new_model(method_name)
157
+ return @persistor.read_new_model(method_name)
166
158
  else
167
- return new_model(nil, @options.merge(parent: self, path: path + [method_name]))
159
+ opts = @options.merge(parent: self, path: path + [method_name])
160
+ if method_name.plural?
161
+ return new_array_model([], opts)
162
+ else
163
+ return new_model(nil, opts)
164
+ end
168
165
  end
169
166
  end
170
167
 
@@ -225,9 +222,6 @@ class Model
225
222
  end
226
223
  end
227
224
 
228
- tag_method(:<<) do
229
- pass_reactive!
230
- end
231
225
  # Initialize an empty array and append to it
232
226
  def <<(value)
233
227
  if @parent
@@ -249,14 +243,20 @@ class Model
249
243
  # Add the new item
250
244
  result << value
251
245
 
252
- trigger!('added', nil, 0)
253
- trigger!('changed')
246
+ # TODORW:
247
+ # trigger!('added', nil, 0)
248
+ # trigger!('changed')
254
249
 
255
250
  return nil
256
251
  end
257
252
 
258
253
  def inspect
259
- "<#{self.class.to_s}:#{object_id} #{attributes.inspect}>"
254
+ str = nil
255
+ Computation.run_without_tracking do
256
+ str = "<#{self.class.to_s}:#{object_id} #{attributes.inspect}>"
257
+ end
258
+
259
+ return str
260
260
  end
261
261
 
262
262
  def deep_cur
@@ -294,7 +294,6 @@ class Model
294
294
  self.class.validations.keys.each do |key|
295
295
  mark_field!(key.to_sym)
296
296
  end
297
- trigger_for_methods!('changed', :errors, :marked_errors)
298
297
 
299
298
  return Promise.new.reject(errors)
300
299
  end
@@ -302,12 +301,15 @@ class Model
302
301
 
303
302
 
304
303
  # Returns a buffered version of the model
305
- tag_method(:buffer) do
306
- destructive!
307
- end
308
304
  def buffer
309
305
  model_path = options[:path]
310
- model_klass = class_at_path(model_path)
306
+
307
+ # When we grab a buffer off of a plual class (subcollection), we get it as a model.
308
+ if model_path.last.plural? && model_path[-1] != :[]
309
+ model_klass = class_at_path(model_path + [:[]])
310
+ else
311
+ model_klass = class_at_path(model_path)
312
+ end
311
313
 
312
314
  new_options = options.merge(path: model_path, save_to: self).reject {|k,_| k.to_sym == :persistor }
313
315
  model = model_klass.new({}, new_options, :loading)
@@ -320,36 +322,14 @@ class Model
320
322
  end
321
323
  end
322
324
 
323
- return ReactiveValue.new(model)
325
+ return model
324
326
  end
325
327
 
326
328
 
327
329
  private
328
- def setup_buffer(model)
329
- model.attributes = self.attributes
330
- model.change_state_to(:loaded)
331
- end
332
-
333
- # Clear the previous value and assign a new one
334
- def __assign_element(key, value)
335
- __clear_element(key)
336
- __track_element(key, value)
337
- end
338
-
339
- # TODO: Somewhat duplicated from ReactiveArray
340
- def __clear_element(key)
341
- # Cleanup any tracking on an index
342
- # TODO: is this send a security risk?
343
- if @reactive_element_listeners && @reactive_element_listeners[key]
344
- @reactive_element_listeners[key].remove
345
- @reactive_element_listeners.delete(key)
346
- end
347
- end
348
-
349
- def __track_element(key, value)
350
- __setup_tracking(key, value) do |event, key, args|
351
- trigger_by_attribute!(event, key, *args)
352
- end
330
+ def setup_buffer(model)
331
+ model.attributes = self.attributes
332
+ model.change_state_to(:loaded)
353
333
  end
354
334
 
355
335
  # Takes the persistor if there is one and
@@ -2,18 +2,17 @@
2
2
  # Moving this into a module cleans up the main Model class for things that
3
3
  # make it behave like a model.
4
4
  module ModelHashBehaviour
5
- def self.included(base)
6
- # In modules, since we need to tag on the main class, we setup the
7
- # tags with included.
8
- base.tag_method(:delete) do
9
- destructive!
10
- end
11
5
 
12
- base.tag_method(:clear) do
13
- destructive!
14
- end
15
- end
6
+ def delete(name)
7
+ name = name.to_sym
16
8
 
9
+ value = attributes.delete(name)
10
+ @deps.delete(name)
11
+
12
+ @persistor.removed(name) if @persistor
13
+
14
+ return value
15
+ end
17
16
 
18
17
  def nil?
19
18
  attributes.nil?
@@ -27,25 +26,12 @@ module ModelHashBehaviour
27
26
  attributes.true?
28
27
  end
29
28
 
30
- def delete(name)
31
- name = name.to_sym
32
- __clear_element(name)
33
- value = attributes.delete(name)
34
- trigger_by_attribute!('changed', name)
35
-
36
- @persistor.removed(name) if @persistor
37
-
38
- return value
39
- end
40
-
41
-
42
29
  def clear
43
30
  attributes.each_pair do |key,value|
44
- __clear_element(key)
31
+ @deps.changed!(key)
45
32
  end
46
33
 
47
34
  attributes.clear
48
- trigger!('changed')
49
35
 
50
36
  @persistor.removed(nil) if @persistor
51
37
  end
@@ -12,8 +12,8 @@ module ModelHelpers
12
12
  end
13
13
 
14
14
  # Pass to the persisotr
15
- def event_added(event, scope_provider, first, first_for_event)
16
- @persistor.event_added(event, scope_provider, first, first_for_event) if @persistor
15
+ def event_added(event, first, first_for_event)
16
+ @persistor.event_added(event, first, first_for_event) if @persistor
17
17
  end
18
18
 
19
19
  # Pass to the persistor
@@ -15,7 +15,7 @@ module ModelState
15
15
  end
16
16
 
17
17
  def loaded?
18
- state == :loaded
18
+ self.state == :loaded
19
19
  end
20
20
 
21
21
 
@@ -2,9 +2,9 @@ module ModelWrapper
2
2
  # For cretain values, we wrap them to make the behave as a
3
3
  # model.
4
4
  def wrap_value(value, lookup)
5
- if value.cur.is_a?(Array)
5
+ if value.is_a?(Array)
6
6
  value = new_array_model(value, @options.merge(parent: self, path: path + lookup))
7
- elsif value.cur.is_a?(Hash)
7
+ elsif value.is_a?(Hash)
8
8
  value = new_model(value, @options.merge(parent: self, path: path + lookup))
9
9
  end
10
10
 
@@ -12,10 +12,10 @@ module ModelWrapper
12
12
  end
13
13
 
14
14
  def wrap_values(values, lookup=[])
15
- if values.cur.is_a?(Array)
15
+ if values.is_a?(Array)
16
16
  # Coming from an array
17
17
  values = values.map {|v| wrap_value(v,lookup + [:[]]) }
18
- elsif values.cur.is_a?(Hash)
18
+ elsif values.is_a?(Hash)
19
19
  pairs = values.map do |k,v|
20
20
  path = lookup + [k]
21
21
 
@@ -17,28 +17,32 @@ module Persistors
17
17
  def initialize(model, tasks=nil)
18
18
  super
19
19
 
20
- query = @model.options[:query]
21
-
22
- @query = ReactiveValue.from_hash(query || {})
20
+ @query = @model.options[:query]
23
21
  end
24
22
 
25
- def event_added(event, scope_provider, first, first_for_event)
23
+ def event_added(event, first, first_for_event)
26
24
  # First event, we load the data.
27
- load_data if first
25
+ if first
26
+ @has_events = true
27
+ load_data
28
+ end
28
29
  end
29
30
 
30
31
  def event_removed(event, last, last_for_event)
31
32
  # Remove listener where there are no more events on this model
32
- stop_listening if last
33
+ if last
34
+ @has_events = false
35
+ stop_listening
36
+ end
33
37
  end
34
38
 
35
39
  # Called when an event is removed and we no longer want to keep in
36
40
  # sync with the database.
37
- def stop_listening
38
- if @query_changed_listener
39
- @query_changed_listener.remove
40
- @query_changed_listener = nil
41
- end
41
+ def stop_listening(stop_watching_query=true)
42
+ return if @has_events
43
+ return if @fetch_promises && @fetch_promises.size > 0
44
+
45
+ @query_computation.stop if @query_computation && stop_watching_query
42
46
 
43
47
  if @query_listener
44
48
  @query_listener.remove_store(self)
@@ -52,22 +56,21 @@ module Persistors
52
56
  def load_data
53
57
  # Don't load data from any queried
54
58
  if @state == :not_loaded || @state == :dirty
55
- # puts "Load Data at #{@model.path.inspect} - query: #{@query.inspect}"# on #{@model.inspect}"
59
+ # puts "Load Data at #{@model.path.inspect} - query: #{@query.inspect} on #{self.inspect}"
56
60
  change_state_to :loading
57
61
 
58
- @query_changed_listener.remove if @query_changed_listener
59
- if @query.reactive?
60
- # puts "SETUP REACTIVE QUERY LISTENER: #{@query.inspect}"
61
- # Query might change, change the query when it does
62
- @query_changed_listener = @query.on('changed') do
63
- stop_listening
62
+ if @query.is_a?(Proc)
63
+ @query_computation = -> do
64
+ puts "Run Query Again"
65
+ stop_listening(false)
64
66
 
65
- # Don't load again if all of the listeners are gone
66
- load_data if @model.has_listeners?
67
- end
68
- end
67
+ change_state_to :loading
69
68
 
70
- run_query(@model, @query.deep_cur)
69
+ run_query(@model, @query.call)
70
+ end.watch!
71
+ else
72
+ run_query(@model, @query)
73
+ end
71
74
  end
72
75
  end
73
76
 
@@ -78,6 +81,9 @@ module Persistors
78
81
  end
79
82
 
80
83
  def run_query(model, query={})
84
+ @model.clear
85
+
86
+ # puts "Run Query: #{query.inspect}"
81
87
  collection = model.path.last
82
88
  # Scope to the parent
83
89
  if model.path.size > 1
@@ -98,10 +104,20 @@ module Persistors
98
104
  @query_listener.add_store(self)
99
105
  end
100
106
 
101
- def find(query={})
102
- model = Cursor.new([], @model.options.merge(:query => query))
107
+ # Find can take either a query object, or a block that returns a query object. Use
108
+ # the block style if you need reactive updating queries
109
+ def find(query=nil, &block)
110
+ # Set a default query if there is no block
111
+ if block
112
+ if query
113
+ raise "Query should not be passed in to a find if a block is specified"
114
+ end
115
+ query = block
116
+ else
117
+ query ||= {}
118
+ end
103
119
 
104
- return ReactiveValue.new(model)
120
+ return Cursor.new([], @model.options.merge(:query => query))
105
121
  end
106
122
 
107
123
  # Returns a promise that is resolved/rejected when the query is complete. Any
@@ -130,7 +146,7 @@ module Persistors
130
146
  new_options = @model.options.merge(path: @model.path + [:[]], parent: @model)
131
147
 
132
148
  # Don't add if the model is already in the ArrayModel
133
- if !@model.cur.array.find {|v| v['_id'] == data['_id'] }
149
+ if !@model.array.find {|v| v['_id'] == data['_id'] }
134
150
  # Find the existing model, or create one
135
151
  new_model = @@identity_map.find(data['_id']) { @model.new_model(data.symbolize_keys, new_options, :loaded) }
136
152
 
@@ -159,9 +175,9 @@ module Persistors
159
175
  @model.path[-1]
160
176
  end
161
177
 
162
-
163
178
  # When a model is added to this collection, we call its "changed"
164
179
  # method. This should trigger a save.
180
+ # TODORW:
165
181
  def added(model, index)
166
182
  if model.persistor
167
183
  # Tell the persistor it was added