volt 0.8.14 → 0.8.15

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,62 +1,62 @@
1
- # Contains all of the methods on a model that make it behave like a hash.
2
- # Moving this into a module cleans up the main Model class for things that
3
- # make it behave like a model.
4
- module ModelHashBehaviour
1
+ module Volt
2
+ # Contains all of the methods on a model that make it behave like a hash.
3
+ # Moving this into a module cleans up the main Model class for things that
4
+ # make it behave like a model.
5
+ module ModelHashBehaviour
5
6
 
6
- def delete(name)
7
- name = name.to_sym
7
+ def delete(name)
8
+ name = name.to_sym
8
9
 
9
- value = attributes.delete(name)
10
- @deps.delete(name)
10
+ value = attributes.delete(name)
11
+ @deps.delete(name)
11
12
 
12
- @persistor.removed(name) if @persistor
13
+ @persistor.removed(name) if @persistor
13
14
 
14
- return value
15
- end
16
-
17
- def nil?
18
- attributes.nil?
19
- end
15
+ value
16
+ end
20
17
 
21
- def empty?
22
- !attributes || attributes.size == 0
23
- end
18
+ def nil?
19
+ attributes.nil?
20
+ end
24
21
 
25
- def false?
26
- attributes.false?
27
- end
22
+ def empty?
23
+ !attributes || attributes.size == 0
24
+ end
28
25
 
29
- def true?
30
- attributes.true?
31
- end
26
+ def false?
27
+ attributes.false?
28
+ end
32
29
 
33
- def clear
34
- attributes.each_pair do |key,value|
35
- @deps.changed!(key)
30
+ def true?
31
+ attributes.true?
36
32
  end
37
33
 
38
- attributes.clear
34
+ def clear
35
+ attributes.each_pair do |key, value|
36
+ @deps.changed!(key)
37
+ end
39
38
 
40
- @persistor.removed(nil) if @persistor
41
- end
39
+ attributes.clear
42
40
 
43
- def each_with_object(*args, &block)
44
- return (@attributes || {}).each_with_object(*args, &block)
45
- end
41
+ @persistor.removed(nil) if @persistor
42
+ end
46
43
 
44
+ def each_with_object(*args, &block)
45
+ (@attributes || {}).each_with_object(*args, &block)
46
+ end
47
47
 
48
- # Convert the model to a hash all of the way down.
49
- def to_h
50
- hash = {}
51
- if empty?
52
- return nil
53
- else
54
- attributes.each_pair do |key, value|
55
- hash[key] = deep_unwrap(value)
56
- end
57
48
 
58
- return hash
49
+ # Convert the model to a hash all of the way down.
50
+ def to_h
51
+ if empty?
52
+ nil
53
+ else
54
+ hash = {}
55
+ attributes.each_pair do |key, value|
56
+ hash[key] = deep_unwrap(value)
57
+ end
58
+ hash
59
+ end
59
60
  end
60
61
  end
61
-
62
62
  end
@@ -1,47 +1,49 @@
1
- # A place for things shared between an ArrayModel and a Model
2
- module ModelHelpers
3
- def deep_unwrap(value)
4
- if value.is_a?(Model)
5
- value = value.to_h
6
- elsif value.is_a?(ArrayModel)
7
- value = value.to_a
1
+ module Volt
2
+ # A place for things shared between an ArrayModel and a Model
3
+ module ModelHelpers
4
+ def deep_unwrap(value)
5
+ if value.is_a?(Model)
6
+ value.to_h
7
+ elsif value.is_a?(ArrayModel)
8
+ value.to_a
9
+ else
10
+ value
11
+ end
8
12
  end
9
13
 
10
- return value
11
- end
12
-
13
- # Pass to the persisotr
14
- def event_added(event, first, first_for_event)
15
- @persistor.event_added(event, first, first_for_event) if @persistor
16
- end
14
+ # Pass to the persisotr
15
+ def event_added(event, first, first_for_event)
16
+ @persistor.event_added(event, first, first_for_event) if @persistor
17
+ end
17
18
 
18
- # Pass to the persistor
19
- def event_removed(event, last, last_for_event)
20
- @persistor.event_removed(event, last, last_for_event) if @persistor
21
- end
19
+ # Pass to the persistor
20
+ def event_removed(event, last, last_for_event)
21
+ @persistor.event_removed(event, last, last_for_event) if @persistor
22
+ end
22
23
 
23
- # Gets the class for a model at the specified path.
24
- def class_at_path(path)
25
- if path
26
- begin
27
- # remove the _ and then singularize
28
- if path.last == :[]
29
- index = -2
30
- else
31
- index = -1
32
- end
24
+ # Gets the class for a model at the specified path.
25
+ def class_at_path(path)
26
+ if path
27
+ begin
28
+ # remove the _ and then singularize
29
+ if path.last == :[]
30
+ index = -2
31
+ else
32
+ index = -1
33
+ end
33
34
 
34
- klass_name = path[index].singularize.camelize
35
+ klass_name = path[index].singularize.camelize
35
36
 
36
- klass = $page.model_classes[klass_name] || Model
37
- rescue NameError => e
38
- # Ignore exception, just means the model isn't defined
37
+ klass = $page.model_classes[klass_name] || Model
38
+ rescue NameError => e
39
+ # Ignore exception, just means the model isn't defined
40
+ klass = Model
41
+ end
42
+ else
39
43
  klass = Model
40
44
  end
41
- else
42
- klass = Model
43
- end
44
45
 
45
- return klass
46
+ klass
47
+ end
46
48
  end
47
49
  end
@@ -1,22 +1,21 @@
1
- # All models have a state that has to do with it being loaded, in process of
2
- # being loaded, or not yet loading.
3
- module ModelState
4
-
5
- def state
6
- if @persistor && @persistor.respond_to?(:state)
7
- @persistor.state
8
- else
9
- @state || :loaded
1
+ module Volt
2
+ # All models have a state that has to do with it being loaded, in process of
3
+ # being loaded, or not yet loading.
4
+ module ModelState
5
+ def state
6
+ if @persistor && @persistor.respond_to?(:state)
7
+ @persistor.state
8
+ else
9
+ @state || :loaded
10
+ end
10
11
  end
11
- end
12
12
 
13
- def change_state_to(state)
14
- @state = state
15
- end
13
+ def change_state_to(state)
14
+ @state = state
15
+ end
16
16
 
17
- def loaded?
18
- self.state == :loaded
17
+ def loaded?
18
+ self.state == :loaded
19
+ end
19
20
  end
20
-
21
-
22
21
  end
@@ -1,31 +1,32 @@
1
- module ModelWrapper
2
- # For cretain values, we wrap them to make the behave as a
3
- # model.
4
- def wrap_value(value, lookup)
5
- if value.is_a?(Array)
6
- value = new_array_model(value, @options.merge(parent: self, path: path + lookup))
7
- elsif value.is_a?(Hash)
8
- value = new_model(value, @options.merge(parent: self, path: path + lookup))
1
+ module Volt
2
+ module ModelWrapper
3
+ # For cretain values, we wrap them to make the behave as a
4
+ # model.
5
+ def wrap_value(value, lookup)
6
+ if value.is_a?(Array)
7
+ new_array_model(value, @options.merge(parent: self, path: path + lookup))
8
+ elsif value.is_a?(Hash)
9
+ new_model(value, @options.merge(parent: self, path: path + lookup))
10
+ else
11
+ value
12
+ end
9
13
  end
10
14
 
11
- return value
12
- end
13
-
14
- def wrap_values(values, lookup=[])
15
- if values.is_a?(Array)
16
- # Coming from an array
17
- values = values.map {|v| wrap_value(v,lookup + [:[]]) }
18
- elsif values.is_a?(Hash)
19
- pairs = values.map do |k,v|
20
- # TODO: We should be able to move wrapping into the method_missing on model
21
- path = lookup + [k.to_sym]
15
+ def wrap_values(values, lookup=[])
16
+ if values.is_a?(Array)
17
+ # Coming from an array
18
+ values.map { |v| wrap_value(v, lookup + [:[]]) }
19
+ elsif values.is_a?(Hash)
20
+ pairs = values.map do |k, v|
21
+ # TODO: We should be able to move wrapping into the method_missing on model
22
+ path = lookup + [k.to_sym]
22
23
 
23
- [k, wrap_value(v,path)]
24
+ [k, wrap_value(v, path)]
25
+ end
26
+ Hash[pairs]
27
+ else
28
+ values
24
29
  end
25
-
26
- values = Hash[pairs]
27
30
  end
28
-
29
- return values
30
31
  end
31
32
  end
@@ -2,203 +2,205 @@ require 'volt/models/persistors/store'
2
2
  require 'volt/models/persistors/query/query_listener_pool'
3
3
  require 'volt/models/persistors/store_state'
4
4
 
5
- module Persistors
6
- class ArrayStore < Store
7
- include StoreState
5
+ module Volt
6
+ module Persistors
7
+ class ArrayStore < Store
8
+ include StoreState
8
9
 
9
- @@query_pool = QueryListenerPool.new
10
+ @@query_pool = QueryListenerPool.new
10
11
 
11
- attr_reader :model
12
+ attr_reader :model
12
13
 
13
- def self.query_pool
14
- @@query_pool
15
- end
14
+ def self.query_pool
15
+ @@query_pool
16
+ end
16
17
 
17
- def initialize(model, tasks=nil)
18
- super
18
+ def initialize(model, tasks=nil)
19
+ super
19
20
 
20
- @query = @model.options[:query]
21
- end
21
+ @query = @model.options[:query]
22
+ end
22
23
 
23
- def event_added(event, first, first_for_event)
24
- # First event, we load the data.
25
- if first
26
- @has_events = true
27
- load_data
24
+ def event_added(event, first, first_for_event)
25
+ # First event, we load the data.
26
+ if first
27
+ @has_events = true
28
+ load_data
29
+ end
28
30
  end
29
- end
30
31
 
31
- def event_removed(event, last, last_for_event)
32
- # Remove listener where there are no more events on this model
33
- if last
34
- @has_events = false
35
- stop_listening
32
+ def event_removed(event, last, last_for_event)
33
+ # Remove listener where there are no more events on this model
34
+ if last
35
+ @has_events = false
36
+ stop_listening
37
+ end
36
38
  end
37
- end
38
39
 
39
- # Called when an event is removed and we no longer want to keep in
40
- # sync with the database.
41
- def stop_listening(stop_watching_query=true)
42
- return if @has_events
43
- return if @fetch_promises && @fetch_promises.size > 0
40
+ # Called when an event is removed and we no longer want to keep in
41
+ # sync with the database.
42
+ def stop_listening(stop_watching_query=true)
43
+ return if @has_events
44
+ return if @fetch_promises && @fetch_promises.size > 0
44
45
 
45
- @query_computation.stop if @query_computation && stop_watching_query
46
+ @query_computation.stop if @query_computation && stop_watching_query
46
47
 
47
- if @query_listener
48
- @query_listener.remove_store(self)
49
- @query_listener = nil
50
- end
48
+ if @query_listener
49
+ @query_listener.remove_store(self)
50
+ @query_listener = nil
51
+ end
51
52
 
52
- @state = :dirty
53
- end
53
+ @state = :dirty
54
+ end
54
55
 
55
- # Called the first time data is requested from this collection
56
- def load_data
57
- # Don't load data from any queried
58
- if @state == :not_loaded || @state == :dirty
59
- # puts "Load Data at #{@model.path.inspect} - query: #{@query.inspect} on #{self.inspect}"
60
- change_state_to :loading
56
+ # Called the first time data is requested from this collection
57
+ def load_data
58
+ # Don't load data from any queried
59
+ if @state == :not_loaded || @state == :dirty
60
+ # puts "Load Data at #{@model.path.inspect} - query: #{@query.inspect} on #{self.inspect}"
61
+ change_state_to :loading
61
62
 
62
- if @query.is_a?(Proc)
63
- @query_computation = -> do
64
- stop_listening(false)
63
+ if @query.is_a?(Proc)
64
+ @query_computation = -> do
65
+ stop_listening(false)
65
66
 
66
- change_state_to :loading
67
+ change_state_to :loading
67
68
 
68
- new_query = @query.call
69
+ new_query = @query.call
69
70
 
70
- run_query(@model, @query.call)
71
- end.watch!
72
- else
73
- run_query(@model, @query)
71
+ run_query(@model, @query.call)
72
+ end.watch!
73
+ else
74
+ run_query(@model, @query)
75
+ end
74
76
  end
75
77
  end
76
- end
77
78
 
78
- # Clear out the models data, since we're not listening anymore.
79
- def unload_data
80
- change_state_to :not_loaded
81
- @model.clear
82
- end
79
+ # Clear out the models data, since we're not listening anymore.
80
+ def unload_data
81
+ change_state_to :not_loaded
82
+ @model.clear
83
+ end
83
84
 
84
- def run_query(model, query={})
85
- @model.clear
85
+ def run_query(model, query={})
86
+ @model.clear
86
87
 
87
- collection = model.path.last
88
- # Scope to the parent
89
- if model.path.size > 1
90
- parent = model.parent
88
+ collection = model.path.last
89
+ # Scope to the parent
90
+ if model.path.size > 1
91
+ parent = model.parent
91
92
 
92
- parent.persistor.ensure_setup if parent.persistor
93
+ parent.persistor.ensure_setup if parent.persistor
93
94
 
94
- if parent && (attrs = parent.attributes) && attrs[:_id].true?
95
- query[:"#{model.path[-3].singularize}_id"] = attrs[:_id]
95
+ if parent && (attrs = parent.attributes) && attrs[:_id].true?
96
+ query[:"#{model.path[-3].singularize}_id"] = attrs[:_id]
97
+ end
96
98
  end
97
- end
98
99
 
99
- @query_listener = @@query_pool.lookup(collection, query) do
100
- # Create if it does not exist
101
- QueryListener.new(@@query_pool, @tasks, collection, query)
102
- end
100
+ @query_listener = @@query_pool.lookup(collection, query) do
101
+ # Create if it does not exist
102
+ QueryListener.new(@@query_pool, @tasks, collection, query)
103
+ end
103
104
 
104
- @query_listener.add_store(self)
105
- end
105
+ @query_listener.add_store(self)
106
+ end
106
107
 
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"
108
+ # Find can take either a query object, or a block that returns a query object. Use
109
+ # the block style if you need reactive updating queries
110
+ def find(query=nil, &block)
111
+ # Set a default query if there is no block
112
+ if block
113
+ if query
114
+ raise "Query should not be passed in to a find if a block is specified"
115
+ end
116
+ query = block
117
+ else
118
+ query ||= {}
114
119
  end
115
- query = block
116
- else
117
- query ||= {}
120
+
121
+ return Cursor.new([], @model.options.merge(:query => query))
118
122
  end
119
123
 
120
- return Cursor.new([], @model.options.merge(:query => query))
121
- end
124
+ # Returns a promise that is resolved/rejected when the query is complete. Any
125
+ # passed block will be passed to the promises then. Then will be passed the model.
126
+ def then(&block)
127
+ promise = Promise.new
122
128
 
123
- # Returns a promise that is resolved/rejected when the query is complete. Any
124
- # passed block will be passed to the promises then. Then will be passed the model.
125
- def then(&block)
126
- promise = Promise.new
129
+ promise = promise.then(&block) if block
127
130
 
128
- promise = promise.then(&block) if block
131
+ if @state == :loaded
132
+ promise.resolve(@model)
133
+ else
134
+ @fetch_promises ||= []
135
+ @fetch_promises << promise
129
136
 
130
- if @state == :loaded
131
- promise.resolve(@model)
132
- else
133
- @fetch_promises ||= []
134
- @fetch_promises << promise
137
+ load_data
138
+ end
135
139
 
136
- load_data
140
+ return promise
137
141
  end
138
142
 
139
- return promise
140
- end
143
+ # Called from backend
144
+ def add(index, data)
145
+ $loading_models = true
141
146
 
142
- # Called from backend
143
- def add(index, data)
144
- $loading_models = true
147
+ data_id = data[:_id]
145
148
 
146
- data_id = data[:_id]
149
+ # Don't add if the model is already in the ArrayModel
150
+ if !@model.array.find { |v| v._id == data_id }
151
+ # Find the existing model, or create one
152
+ new_model = @@identity_map.find(data_id) do
153
+ new_options = @model.options.merge(path: @model.path + [:[]], parent: @model)
154
+ @model.new_model(data, new_options, :loaded)
155
+ end
147
156
 
148
- # Don't add if the model is already in the ArrayModel
149
- if !@model.array.find {|v| v._id == data_id }
150
- # Find the existing model, or create one
151
- new_model = @@identity_map.find(data_id) do
152
- new_options = @model.options.merge(path: @model.path + [:[]], parent: @model)
153
- @model.new_model(data, new_options, :loaded)
157
+ @model.insert(index, new_model)
154
158
  end
155
159
 
156
- @model.insert(index, new_model)
160
+ $loading_models = false
157
161
  end
158
162
 
159
- $loading_models = false
160
- end
161
-
162
- def remove(ids)
163
- $loading_models = true
164
- ids.each do |id|
165
- # TODO: optimize this delete so we don't need to loop
166
- @model.each_with_index do |model, index|
167
- if model._id == id
168
- del = @model.delete_at(index)
169
- break
163
+ def remove(ids)
164
+ $loading_models = true
165
+ ids.each do |id|
166
+ # TODO: optimize this delete so we don't need to loop
167
+ @model.each_with_index do |model, index|
168
+ if model._id == id
169
+ del = @model.delete_at(index)
170
+ break
171
+ end
170
172
  end
171
173
  end
172
- end
173
174
 
174
- $loading_models = false
175
- end
176
-
177
- def channel_name
178
- @model.path[-1]
179
- end
175
+ $loading_models = false
176
+ end
180
177
 
181
- # When a model is added to this collection, we call its "changed"
182
- # method. This should trigger a save.
183
- def added(model, index)
184
- if model.persistor
185
- # Tell the persistor it was added
186
- model.persistor.add_to_collection
178
+ def channel_name
179
+ @model.path[-1]
187
180
  end
188
- end
189
181
 
190
- def removed(model)
191
- if model.persistor
192
- # Tell the persistor it was removed
193
- model.persistor.remove_from_collection
182
+ # When a model is added to this collection, we call its "changed"
183
+ # method. This should trigger a save.
184
+ def added(model, index)
185
+ if model.persistor
186
+ # Tell the persistor it was added
187
+ model.persistor.add_to_collection
188
+ end
194
189
  end
195
190
 
196
- if defined?($loading_models) && $loading_models
197
- return
198
- else
199
- StoreTasks.delete(channel_name, model.attributes[:_id])
191
+ def removed(model)
192
+ if model.persistor
193
+ # Tell the persistor it was removed
194
+ model.persistor.remove_from_collection
195
+ end
196
+
197
+ if defined?($loading_models) && $loading_models
198
+ return
199
+ else
200
+ StoreTasks.delete(channel_name, model.attributes[:_id])
201
+ end
200
202
  end
201
- end
202
203
 
204
+ end
203
205
  end
204
206
  end