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
@@ -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