volt 0.9.6 → 0.9.7.pre2

Sign up to get free protection for your applications and to get access to all the features.
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