volt 0.9.6 → 0.9.7.pre2

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/CHANGELOG.md +26 -0
  4. data/Gemfile +6 -1
  5. data/README.md +2 -0
  6. data/Rakefile +1 -0
  7. data/app/volt/models/active_volt_instance.rb +8 -6
  8. data/app/volt/models/user.rb +11 -2
  9. data/app/volt/models/volt_app_property.rb +8 -0
  10. data/app/volt/tasks/query_tasks.rb +23 -31
  11. data/app/volt/tasks/store_tasks.rb +2 -2
  12. data/app/volt/tasks/volt_admin_tasks.rb +24 -0
  13. data/docs/UPGRADE_GUIDE.md +6 -0
  14. data/lib/volt.rb +19 -12
  15. data/lib/volt/boot.rb +1 -0
  16. data/lib/volt/cli.rb +19 -8
  17. data/lib/volt/cli/console.rb +0 -1
  18. data/lib/volt/cli/generators.rb +14 -3
  19. data/lib/volt/cli/migrate.rb +26 -0
  20. data/lib/volt/config.rb +17 -4
  21. data/lib/volt/controllers/http_controller.rb +12 -0
  22. data/lib/volt/data_stores/base_adaptor_client.rb +2 -2
  23. data/lib/volt/data_stores/base_adaptor_server.rb +2 -0
  24. data/lib/volt/data_stores/data_store.rb +20 -14
  25. data/lib/volt/extra_core/class.rb +28 -14
  26. data/lib/volt/extra_core/hash.rb +5 -0
  27. data/lib/volt/extra_core/string.rb +3 -1
  28. data/lib/volt/helpers/time.rb +9 -43
  29. data/lib/volt/helpers/time/calculations.rb +204 -0
  30. data/lib/volt/helpers/time/distance.rb +63 -0
  31. data/lib/volt/helpers/time/duration.rb +71 -0
  32. data/lib/volt/helpers/time/local_calculations.rb +49 -0
  33. data/lib/volt/helpers/time/local_volt_time.rb +23 -0
  34. data/lib/volt/helpers/time/numeric.rb +59 -0
  35. data/lib/volt/helpers/time/volt_time.rb +170 -0
  36. data/lib/volt/models.rb +5 -0
  37. data/lib/volt/models/array_model.rb +33 -6
  38. data/lib/volt/models/associations.rb +146 -23
  39. data/lib/volt/models/buffer.rb +38 -41
  40. data/lib/volt/models/cursor.rb +15 -0
  41. data/lib/volt/models/errors.rb +11 -0
  42. data/lib/volt/models/field_helpers.rb +108 -68
  43. data/lib/volt/models/helpers/array_model.rb +4 -0
  44. data/lib/volt/models/helpers/base.rb +8 -1
  45. data/lib/volt/models/helpers/change_helpers.rb +31 -12
  46. data/lib/volt/models/helpers/defaults.rb +15 -0
  47. data/lib/volt/models/location.rb +20 -6
  48. data/lib/volt/models/migrations/migration.rb +23 -0
  49. data/lib/volt/models/migrations/migration_runner.rb +146 -0
  50. data/lib/volt/models/model.rb +38 -1
  51. data/lib/volt/models/permissions.rb +8 -1
  52. data/lib/volt/models/persistors/array_store.rb +87 -8
  53. data/lib/volt/models/persistors/base.rb +19 -0
  54. data/lib/volt/models/persistors/model_store.rb +1 -1
  55. data/lib/volt/models/persistors/page.rb +4 -1
  56. data/lib/volt/models/persistors/query/query_identifier.rb +102 -0
  57. data/lib/volt/models/persistors/query/query_listener.rb +57 -12
  58. data/lib/volt/models/root_models/root_models.rb +19 -0
  59. data/lib/volt/models/url.rb +11 -2
  60. data/lib/volt/models/validations/validations.rb +5 -2
  61. data/lib/volt/models/validators/type_validator.rb +11 -0
  62. data/lib/volt/models/validators/unique_validator.rb +2 -2
  63. data/lib/volt/page/bindings/attribute_binding.rb +23 -1
  64. data/lib/volt/page/targets/attribute_section.rb +7 -0
  65. data/lib/volt/page/targets/binding_document/component_node.rb +44 -18
  66. data/lib/volt/page/targets/binding_document/tag_node.rb +41 -0
  67. data/lib/volt/page/tasks.rb +16 -8
  68. data/lib/volt/queries/live_query.rb +109 -0
  69. data/lib/volt/queries/live_query_pool.rb +58 -0
  70. data/lib/volt/queries/live_subquery.rb +0 -0
  71. data/lib/volt/queries/query_association_splitter.rb +31 -0
  72. data/lib/volt/queries/query_diff.rb +100 -0
  73. data/lib/volt/queries/query_runner.rb +110 -0
  74. data/lib/volt/queries/query_subscription.rb +80 -0
  75. data/lib/volt/queries/query_subscription_pool.rb +37 -0
  76. data/lib/volt/reactive/eventable.rb +8 -0
  77. data/lib/volt/reactive/reactive_array.rb +0 -4
  78. data/lib/volt/router/routes.rb +81 -31
  79. data/lib/volt/server/message_bus/base_message_bus.rb +9 -3
  80. data/lib/volt/server/message_bus/peer_to_peer.rb +6 -6
  81. data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +1 -1
  82. data/lib/volt/server/middleware/default_middleware_stack.rb +12 -8
  83. data/lib/volt/server/rack/component_paths.rb +31 -4
  84. data/lib/volt/server/rack/http_content_types.rb +62 -0
  85. data/lib/volt/server/rack/http_resource.rb +1 -1
  86. data/lib/volt/server/rack/index_files.rb +8 -1
  87. data/lib/volt/server/rack/opal_files.rb +16 -1
  88. data/lib/volt/server/rack/sprockets_helpers_setup.rb +32 -1
  89. data/lib/volt/server/socket_connection_handler.rb +16 -7
  90. data/lib/volt/server/template_handlers/sprockets_component_handler.rb +5 -3
  91. data/lib/volt/spec/capybara.rb +4 -3
  92. data/lib/volt/spec/setup.rb +5 -0
  93. data/lib/volt/tasks/dispatcher.rb +3 -1
  94. data/lib/volt/utils/data_transformer.rb +4 -4
  95. data/lib/volt/utils/ejson.rb +19 -6
  96. data/lib/volt/utils/promise_extensions.rb +1 -1
  97. data/lib/volt/utils/time_opal_patch.rb +749 -0
  98. data/lib/volt/utils/time_patch.rb +11 -4
  99. data/lib/volt/version.rb +1 -1
  100. data/lib/volt/volt/app.rb +19 -11
  101. data/lib/volt/volt/properties.rb +24 -0
  102. data/lib/volt/volt/server_setup/app.rb +30 -7
  103. data/lib/volt/volt/users.rb +15 -3
  104. data/spec/apps/kitchen_sink/Gemfile +5 -1
  105. data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
  106. data/spec/apps/kitchen_sink/app/main/controllers/save_controller.rb +1 -1
  107. data/spec/apps/kitchen_sink/app/main/controllers/server/simple_http_controller.rb +4 -0
  108. data/spec/apps/kitchen_sink/app/main/controllers/todos_controller.rb +4 -2
  109. data/spec/apps/kitchen_sink/app/main/models/post.rb +0 -1
  110. data/spec/apps/kitchen_sink/app/main/models/todo.rb +4 -0
  111. data/spec/apps/kitchen_sink/app/main/views/mailers/reset_password.html +10 -0
  112. data/spec/apps/kitchen_sink/app/main/views/todos/index.html +2 -0
  113. data/spec/apps/kitchen_sink/config/app.rb +2 -0
  114. data/spec/apps/migrations/config/db/migrations/1445111704_migration1.rb +7 -0
  115. data/spec/apps/migrations/config/db/migrations/1445113517_migration2.rb +7 -0
  116. data/spec/apps/migrations/config/db/migrations/1445115200_migration3.rb +7 -0
  117. data/spec/extra_core/class_spec.rb +10 -0
  118. data/spec/helpers/distance_spec.rb +35 -0
  119. data/spec/helpers/duration_spec.rb +160 -0
  120. data/spec/helpers/volt_time_spec.rb +275 -0
  121. data/spec/integration/callbacks_spec.rb +2 -1
  122. data/spec/integration/http_endpoints_spec.rb +4 -0
  123. data/spec/integration/save_spec.rb +1 -1
  124. data/spec/integration/todos_spec.rb +7 -5
  125. data/spec/models/array_model_spec.rb +17 -3
  126. data/spec/models/associations_spec.rb +48 -1
  127. data/spec/models/field_helpers_spec.rb +7 -3
  128. data/spec/models/migrations/migration_runner_spec.rb +69 -0
  129. data/spec/models/model_spec.rb +42 -8
  130. data/spec/models/permissions_spec.rb +20 -8
  131. data/spec/models/persistors/array_store_spec.rb +18 -0
  132. data/spec/models/persistors/page_spec.rb +15 -10
  133. data/spec/models/persistors/store_spec.rb +13 -3
  134. data/spec/models/url_spec.rb +4 -3
  135. data/spec/models/user_spec.rb +6 -3
  136. data/spec/models/user_validation_spec.rb +3 -3
  137. data/spec/models/validations_spec.rb +4 -0
  138. data/spec/models/validators/block_validations_spec.rb +9 -5
  139. data/spec/models/validators/email_validator_spec.rb +2 -0
  140. data/spec/models/validators/lifecycle_callbacks_spec.rb +86 -0
  141. data/spec/models/validators/unique_validator_spec.rb +1 -0
  142. data/spec/page/path_string_renderer_spec.rb +5 -0
  143. data/spec/queries/live_query_spec.rb +16 -0
  144. data/spec/queries/query_association_splitter_spec.rb +14 -0
  145. data/spec/queries/query_diff_spec.rb +132 -0
  146. data/spec/queries/query_identifier_spec.rb +98 -0
  147. data/spec/queries/query_runner_spec.rb +63 -0
  148. data/spec/queries/query_tracker_spec.rb +141 -0
  149. data/spec/router/routes_spec.rb +52 -21
  150. data/spec/server/middleware/rack_content_types_spec.rb +78 -0
  151. data/spec/server/rack/asset_files_spec.rb +38 -30
  152. data/spec/spec_helper.rb +8 -0
  153. data/spec/utils/ejson_spec.rb +9 -8
  154. data/spec/utils/ejson_volt_time_spec.rb +65 -0
  155. data/templates/migration/migration.rb.tt +9 -0
  156. data/templates/newgem/gitignore.tt +1 -0
  157. data/templates/project/Gemfile.tt +19 -2
  158. data/templates/project/README.md.tt +6 -1
  159. data/templates/project/app/main/config/dependencies.rb +6 -0
  160. data/templates/project/config/app.rb.tt +18 -4
  161. data/volt.gemspec +2 -2
  162. metadata +73 -16
  163. data/app/volt/tasks/live_query/live_query_pool.rb +0 -48
  164. data/app/volt/tasks/live_query/query_tracker.rb +0 -92
  165. data/spec/tasks/live_query_spec.rb +0 -18
  166. data/spec/tasks/query_tasks.rb +0 -7
  167. data/spec/tasks/query_tracker_spec.rb +0 -145
@@ -1,48 +0,0 @@
1
- require_relative 'live_query'
2
- require 'volt/utils/generic_pool'
3
-
4
- # LiveQueryPool runs on the server and keeps track of all outstanding
5
- # queries.
6
-
7
- class LiveQueryPool < Volt::GenericPool
8
- def initialize(data_store, volt_app)
9
- @data_store = data_store
10
- @volt_app = volt_app
11
- super()
12
- end
13
-
14
- def lookup(collection, query)
15
- # collection = collection.to_sym
16
- query = normalize_query(query)
17
-
18
- super(collection, query)
19
- end
20
-
21
- def updated_collection(collection, skip_channel, from_message_bus=false)
22
- # collection = collection.to_sym
23
- lookup_all(collection).each do |live_query|
24
- live_query.run(skip_channel)
25
- end
26
-
27
- msg_bus = @volt_app.message_bus
28
- if !from_message_bus && collection != 'active_volt_instances' && msg_bus
29
- msg_bus.publish('volt_collection_update', collection)
30
- end
31
- end
32
-
33
- private
34
-
35
- # Creates the live query if it doesn't exist, and stores it so it
36
- # can be found later.
37
- def create(collection, query = {})
38
- # collection = collection.to_sym
39
- # If not already setup, create a new one for this collection/query
40
- LiveQuery.new(self, @data_store, collection, query)
41
- end
42
-
43
- def normalize_query(query)
44
- # TODO: add something to sort query properties so the queries are
45
- # always compared the same.
46
- query
47
- end
48
- end
@@ -1,92 +0,0 @@
1
- # The query tracker runs queries and then tracks the changes
2
- # that take place.
3
- class QueryTracker
4
- attr_accessor :results
5
-
6
- def initialize(live_query, data_store)
7
- @live_query = live_query
8
- @data_store = data_store
9
-
10
- # Stores the list of id's currently associated with this query
11
- @current_ids = []
12
- @results = []
13
- @results_hash = {}
14
- end
15
-
16
- # Runs the query, stores the results and updates the current_ids
17
- def run(skip_channel = nil)
18
- @previous_results = @results
19
- @previous_results_hash = @results_hash
20
- @previous_ids = @current_ids
21
-
22
- # Run the query again
23
- @results = @data_store.query(@live_query.collection, @live_query.query)
24
-
25
- # Update the current_ids
26
- @current_ids = @results.map { |r| r[:id] }
27
- @results_hash = Hash[@results.map { |r| [r[:id], r] }]
28
-
29
- process_changes(skip_channel)
30
- end
31
-
32
- # Looks at the changes in the last run and sends out notices
33
- # all changes.
34
- def process_changes(skip_channel)
35
- return unless @previous_ids
36
-
37
- detect_removed(skip_channel)
38
- detect_added_and_moved(skip_channel)
39
- detect_changed(skip_channel)
40
- end
41
-
42
- def detect_removed(skip_channel)
43
- # Removed models
44
- removed_ids = @previous_ids - @current_ids
45
- if removed_ids.size > 0
46
- @live_query.notify_removed(removed_ids, skip_channel)
47
- end
48
-
49
- # Update @previous_ids to relect the removed
50
- @previous_ids &= @current_ids
51
- end
52
-
53
- # Loop through the new list, tracking in the old, notifies of any that
54
- # have been added or moved.
55
- def detect_added_and_moved(skip_channel)
56
- previous_index = 0
57
- @current_ids.each_with_index do |id, index|
58
- if (cur_previous = @previous_ids[previous_index]) && cur_previous == id
59
- # Same in both previous and new
60
- previous_index += 1
61
- next
62
- end
63
-
64
- # We have an item that didn't match the current position's previous
65
- # TODO: make a hash so we don't have to do include?
66
- if @previous_ids.include?(id)
67
- # The location from the previous has changed, move to correct location.
68
-
69
- # Remove from previous_ids, as it will be moved and we will be past it.
70
- @previous_ids.delete(id)
71
- @live_query.notify_moved(id, index, skip_channel)
72
- else
73
- # TODO: Faster lookup
74
- data = @results_hash[id]
75
- @live_query.notify_added(index, data, skip_channel)
76
- end
77
- end
78
- end
79
-
80
- # Finds all items in the previous results that have new values, and alerts
81
- # of changes.
82
- def detect_changed(skip_channel)
83
- not_added_or_removed = @previous_ids & @current_ids
84
-
85
- not_added_or_removed.each do |id|
86
- if @previous_results_hash[id] != (data = @results_hash[id])
87
- # Data hash changed
88
- @live_query.notify_changed(id, data, skip_channel)
89
- end
90
- end
91
- end
92
- end
@@ -1,18 +0,0 @@
1
- if RUBY_PLATFORM != 'opal'
2
- describe 'LiveQuery' do
3
- before do
4
- load File.join(File.dirname(__FILE__), '../../app/volt/tasks/live_query/live_query.rb')
5
- end
6
-
7
- it 'should run a query' do
8
- pool = double('volt/pool')
9
- data_store = double('volt/data store')
10
-
11
- expect(data_store).to receive(:query).with('_items', {}).and_return([
12
- { 'id' => 0, '_name' => 'one' }
13
- ])
14
-
15
- live_query = LiveQuery.new(pool, data_store, '_items', {})
16
- end
17
- end
18
- end
@@ -1,7 +0,0 @@
1
- if RUBY_PLATFORM != 'opal'
2
- describe 'Volt::QueryTasks' do
3
- before do
4
- load File.join(File.dirname(__FILE__), '../../app/volt/tasks/query_tasks.rb')
5
- end
6
- end
7
- end
@@ -1,145 +0,0 @@
1
- if RUBY_PLATFORM != 'opal'
2
- describe 'LiveQuery' do
3
- before do
4
- load File.join(File.dirname(__FILE__), '../../app/volt/tasks/live_query/live_query.rb')
5
- end
6
-
7
- # LiveQueryStub behaves as the front-end would with the changes to a
8
- # live query. Instead of passing changes to the models to the front
9
- # end, the changes are applied locally, then can be checked to see if
10
- # the correct transitions have taken place.
11
- class LiveQueryStub
12
- attr_reader :collection, :query, :items
13
- def initialize
14
- @collection = '_items'
15
- @query = {}
16
- @items = []
17
- end
18
-
19
- def notify_removed(ids, skip_channel)
20
- # Remove the id's that need to be removed
21
- @items.reject! { |item| ids.include?(item[:id]) }
22
- end
23
-
24
- def notify_added(index, data, skip_channel)
25
- @items.insert(index, data)
26
- end
27
-
28
- def notify_moved(id, index, skip_channel)
29
- item = @items.find { |item| item[:id] == id }
30
- @items.delete(item)
31
-
32
- @items.insert(index, item)
33
- end
34
-
35
- def notify_changed(id, data, skip_channel)
36
- item = @items.find { |item| item[:id] == id }
37
- idx = @items.index(item)
38
- @items.delete(item)
39
- @items.insert(idx, data)
40
- end
41
- end
42
-
43
- before do
44
- # Setup a live query stub
45
- @live_query = LiveQueryStub.new
46
- data_store = double('volt/data store')
47
-
48
- # return an empty collection
49
- @items = []
50
- expect(data_store).to receive(:query).at_least(:once) { @items.dup }
51
-
52
- @query_tracker = QueryTracker.new(@live_query, data_store)
53
- @query_tracker.run
54
- end
55
-
56
- it 'should add items' do
57
- @items = [
58
- { id: 1, name: 'one' }
59
- ]
60
-
61
- expect(@live_query.items).to eq([])
62
-
63
- @query_tracker.run
64
-
65
- expect(@live_query.items).to eq(@items)
66
- end
67
-
68
- it 'should remove items' do
69
- @items = [
70
- { id: 1, name: 'one' },
71
- { id: 2, name: 'two' }
72
- ]
73
- @query_tracker.run
74
- expect(@live_query.items).to eq(@items)
75
-
76
- @items = [
77
- { id: 2, name: 'two' }
78
- ]
79
- @query_tracker.run
80
- expect(@live_query.items).to eq(@items)
81
- end
82
-
83
- it 'should move items' do
84
- @items = [
85
- { id: 1, name: 'one' },
86
- { id: 2, name: 'two' },
87
- { id: 3, name: 'three' }
88
- ]
89
- @query_tracker.run
90
- expect(@live_query.items).to eq(@items)
91
-
92
- @items = [
93
- { id: 2, name: 'two' },
94
- { id: 3, name: 'three' },
95
- { id: 1, name: 'one' }
96
- ]
97
- @query_tracker.run
98
- expect(@live_query.items).to eq(@items)
99
- end
100
-
101
- it 'should handle complex transforms' do
102
- @items = [
103
- { id: 1, name: 'one' },
104
- { id: 2, name: 'two' },
105
- { id: 3, name: 'three' },
106
- { id: 4, name: 'four' },
107
- { id: 5, name: 'five' }
108
- ]
109
- @query_tracker.run
110
- expect(@live_query.items).to eq(@items)
111
-
112
- @items = [
113
- { id: 7, name: 'seven' },
114
- { id: 4, name: 'four' },
115
- { id: 1, name: 'one' },
116
- { id: 5, name: 'five' },
117
- { id: 3, name: 'three' },
118
- { id: 6, name: 'five' }
119
- ]
120
- @query_tracker.run
121
- expect(@live_query.items).to eq(@items)
122
- end
123
-
124
- it 'should notify data hash has changed' do
125
- @items = [
126
- { id: 1, name: 'one' },
127
- { id: 2, name: 'two' },
128
- { id: 3, name: 'three' },
129
- { id: 4, name: 'four' },
130
- { id: 5, name: 'five' }
131
- ]
132
- @query_tracker.run
133
- @items = [
134
- { id: 1, name: 'some' },
135
- { id: 2, name: 'values' },
136
- { id: 3, name: 'have' },
137
- { id: 4, name: 'changed' },
138
- { id: 5, name: 'other' }
139
- ]
140
- expect(@live_query.items).to_not eq(@items)
141
- @query_tracker.run
142
- expect(@live_query.items).to eq(@items)
143
- end
144
- end
145
- end