volt 0.9.2 → 0.9.3.pre1

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/CONTRIBUTING.md +4 -0
  4. data/Gemfile +3 -0
  5. data/app/volt/assets/js/volt_js_polyfills.js +0 -1
  6. data/app/volt/assets/js/volt_watch.js +217 -0
  7. data/app/volt/models/user.rb +7 -2
  8. data/app/volt/tasks/query_tasks.rb +6 -0
  9. data/lib/volt/boot.rb +1 -1
  10. data/lib/volt/cli/generate.rb +1 -1
  11. data/lib/volt/config.rb +12 -2
  12. data/lib/volt/controllers/model_controller.rb +1 -1
  13. data/lib/volt/data_stores/base_adaptor_client.rb +34 -0
  14. data/lib/volt/data_stores/{base.rb → base_adaptor_server.rb} +1 -1
  15. data/lib/volt/data_stores/data_store.rb +23 -7
  16. data/lib/volt/models/array_model.rb +3 -2
  17. data/lib/volt/models/model.rb +29 -91
  18. data/lib/volt/models/{dirty.rb → model_helpers/dirty.rb} +0 -0
  19. data/lib/volt/models/{listener_tracker.rb → model_helpers/listener_tracker.rb} +0 -0
  20. data/lib/volt/models/model_helpers/model_change_helpers.rb +76 -0
  21. data/lib/volt/models/{model_helpers.rb → model_helpers/model_helpers.rb} +0 -0
  22. data/lib/volt/models/persistors/array_store.rb +2 -23
  23. data/lib/volt/models/persistors/query/normalizer.rb +0 -44
  24. data/{templates/project/lib/.empty_directory → lib/volt/models/validations/errors.rb} +0 -0
  25. data/lib/volt/models/{validations.rb → validations/validations.rb} +80 -26
  26. data/lib/volt/page/bindings/attribute_binding.rb +17 -3
  27. data/lib/volt/page/page.rb +1 -0
  28. data/lib/volt/reactive/eventable.rb +1 -0
  29. data/lib/volt/server.rb +2 -1
  30. data/lib/volt/server/component_templates.rb +66 -16
  31. data/lib/volt/server/forking_server.rb +16 -14
  32. data/lib/volt/server/html_parser/sandlebars_parser.rb +2 -0
  33. data/lib/volt/server/html_parser/view_scope.rb +2 -0
  34. data/lib/volt/server/rack/component_paths.rb +4 -2
  35. data/lib/volt/server/rack/opal_files.rb +4 -2
  36. data/lib/volt/server/socket_connection_handler.rb +5 -1
  37. data/lib/volt/server/template_handlers/handlers.rb +0 -0
  38. data/lib/volt/spec/setup.rb +23 -8
  39. data/lib/volt/tasks/dispatcher.rb +4 -0
  40. data/lib/volt/utils/promise_patch.rb +3 -0
  41. data/lib/volt/version.rb +1 -1
  42. data/spec/apps/kitchen_sink/Gemfile +5 -0
  43. data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
  44. data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +10 -0
  45. data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +20 -0
  46. data/spec/apps/kitchen_sink/app/main/views/main/form.html +73 -0
  47. data/spec/apps/kitchen_sink/app/main/views/main/main.html +1 -0
  48. data/spec/integration/bindings_spec.rb +33 -0
  49. data/spec/integration/user_spec.rb +51 -21
  50. data/spec/models/associations_spec.rb +8 -0
  51. data/spec/models/model_spec.rb +7 -0
  52. data/spec/models/user_spec.rb +20 -0
  53. data/spec/models/validations_spec.rb +2 -1
  54. data/spec/models/validators/block_validations_spec.rb +53 -0
  55. data/spec/page/bindings/template_binding/view_lookup_for_path_spec.rb +10 -0
  56. data/spec/page/path_string_renderer_spec.rb +6 -0
  57. data/spec/reactive/eventable_spec.rb +24 -6
  58. data/spec/server/component_templates_spec.rb +21 -0
  59. data/spec/server/html_parser/sandlebars_parser_spec.rb +12 -13
  60. data/spec/server/html_parser/view_parser_spec.rb +3 -0
  61. data/spec/server/rack/asset_files_spec.rb +2 -2
  62. data/spec/server/rack/http_resource_spec.rb +10 -0
  63. data/spec/tasks/dispatcher_spec.rb +5 -0
  64. data/spec/tasks/user_tasks_spec.rb +59 -0
  65. data/spec/utils/task_argument_filtererer_spec.rb +6 -0
  66. data/templates/newgem/app/newgem/config/initializers/boot.rb +10 -0
  67. data/templates/newgem/lib/newgem.rb.tt +13 -0
  68. data/templates/project/Gemfile.tt +3 -0
  69. data/templates/project/app/main/lib/.empty_directory +0 -0
  70. data/volt.gemspec +3 -1
  71. metadata +24 -25
  72. data/lib/volt/data_stores/mongo_driver.rb +0 -69
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c57d60611600de9f132243981453e12dd14d7d2b
4
- data.tar.gz: e14a1bbead84d93c8cd03bcac1bdaf54d315d2ff
3
+ metadata.gz: d6e09afcd5fa1abe6f17a9c2912bc79cf4cf74aa
4
+ data.tar.gz: f0ee7b0085bddf48461122bfccec1b21b06b2e3e
5
5
  SHA512:
6
- metadata.gz: 4fc5686a5121b45d4186acd8c59e0b46e45ad9796752a1bc0b915234fe864cb90bc8f6ad58954e4f757516a744e07cfe3da20d22e7283b49c12aab7bf59b12f6
7
- data.tar.gz: 5b1b6ac243e17387a564b42be1341d378282883766a7e3002f21faa2396bd6c2006b53333ad39936194d5c84ba6ca29fb34c9dd63043f241251d5727481691b7
6
+ metadata.gz: ed02ac1418ee8f8ed50a67331dfb58eeabf933a55ecb60a2cb05052245164e851331fea5a5de8977a1fbfa31859bedea4dcaf8117b28258559c0954c5ff3f9e3
7
+ data.tar.gz: 7069f1ac08014813da1501c252fed11031c248b479d7b7323ff49a69b17cdc5dc54e793f48b48b199a6e23fd56178ff6684b47151640ab321af3fd0cfcfe5d71
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.9.3.pre1
4
+ ### Added
5
+ - Added validations block for conditional validation runs
6
+
7
+ ### Changed
8
+ - All logic associated with mongo has been moved into the volt-mongo gem. If you are migrating from a previous version, be sure to add ```gem 'volt-mongo'``` to the Gemfile.
9
+
3
10
  ## 0.9.2
4
11
  ### Changed
5
12
  - We released 0.9.1 with a bug for destroy (doh!). Specs added and bug fixed.
data/CONTRIBUTING.md CHANGED
@@ -41,6 +41,10 @@ If not installed, you can install from the source or use Homebrew:
41
41
  brew upgrade && brew install phantomjs
42
42
  ```
43
43
 
44
+ #### Caveat
45
+
46
+ You need 2.0 for MutationObserver API support, so until this issue https://github.com/teampoltergeist/poltergeist/issues/574 is resolved that poltergeist will support phantomjs 2.0, the test for attribute binding has to be in a real browser.
47
+
44
48
  #### Bundle Install and Test
45
49
 
46
50
  Ensure that you can build the project and run tests.
data/Gemfile CHANGED
@@ -2,6 +2,9 @@ source 'http://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ # volt-mongo gem for testing
6
+ gem 'volt-mongo'
7
+
5
8
  group :development do
6
9
  # For testing the kitchen sink app
7
10
  # Twitter bootstrap
@@ -10,7 +10,6 @@ if (!Function.prototype.bind) {
10
10
  };
11
11
  }
12
12
 
13
-
14
13
  // setImmediate
15
14
  (function (global, undefined) {
16
15
  "use strict";
@@ -0,0 +1,217 @@
1
+ /*
2
+ * Watch Event Listener
3
+ *
4
+ * @author Darcy Clarke
5
+ * Modified by Penn Su
6
+ *
7
+ * Copyright (c) 2014 Darcy Clarke
8
+ * Dual licensed under the MIT and GPL licenses.
9
+ *
10
+ * Usage:
11
+ * watch(element, 'width height', function(){
12
+ * console.log(this.style.width, this.style.height);
13
+ * });
14
+ */
15
+
16
+ (function (window) {
17
+
18
+ var toArray;
19
+ var eqlArrays;
20
+
21
+ // http://jsfiddle.net/moagrius/YxzfV/
22
+ Array.prototype.multisplice = function(){
23
+ var args = Array.apply(null, arguments);
24
+ args.sort(function(a,b){
25
+ return a - b;
26
+ });
27
+ for(var i = 0; i < args.length; i++){
28
+ var index = args[i] - i;
29
+ this.splice(index, 1);
30
+ }
31
+ }
32
+
33
+ // Object to Array
34
+ toArray = function (obj) {
35
+
36
+ var arr = [];
37
+
38
+ for (var i = obj.length >>> 0; i--;) {
39
+ arr[i] = obj[i];
40
+ }
41
+
42
+ return arr;
43
+
44
+ };
45
+
46
+ eqlArrays = function (a, b) {
47
+ a.length == b.length && a.every(function (e, i) { e === b[i] });
48
+ }
49
+
50
+ var _watch = function (elements, props, options, callback){
51
+
52
+ // Setup
53
+ var self = this;
54
+ var check;
55
+
56
+ // Check if we should fire callback
57
+ check = function (e) {
58
+
59
+ var self = this;
60
+
61
+ for (var i = 0; i < self.watching.length; i++) {
62
+
63
+ var data = self.watching[i];
64
+ var changed = true;
65
+ var temp;
66
+
67
+ // Iterate through properties
68
+ for (var j = 0; j < data.props.length; j++) {
69
+ temp = self.attributes[data.props[j]] || self.style[data.props[j]];
70
+ if (data.vals[j] != temp) {
71
+ data.vals[j] = temp;
72
+ data.changed[j] = true;
73
+ }
74
+ }
75
+
76
+ // Check changed attributes
77
+ for (var k = 0; k < data.props.length; k++) {
78
+ if (!data.changed[k]) {
79
+ changed = false;
80
+ break;
81
+ }
82
+ }
83
+
84
+ // Run callback if property has changed
85
+ if (changed && data.callback) {
86
+ data.callback.apply(self, e);
87
+ }
88
+
89
+ };
90
+
91
+ };
92
+
93
+ // Elements from node list to array
94
+ elements = toArray(elements);
95
+
96
+ // Type check options
97
+ if (typeof(options) == 'function') {
98
+ callback = options;
99
+ options = {};
100
+ }
101
+
102
+ // Type check callback
103
+ if (typeof(callback) != 'function') {
104
+ callback = function(){};
105
+ }
106
+
107
+ // Set throttle
108
+ options.throttle = options.throttle || 10;
109
+
110
+ // Iterate over elements
111
+ for (var i = 0; i < elements.length; i++) {
112
+
113
+ var element = elements[i];
114
+ var data = {
115
+ props: props.split(' '),
116
+ vals: [],
117
+ changed: [],
118
+ callback: callback
119
+ };
120
+
121
+ // Grab each property's initial value
122
+ for (var j = 0; j < data.props.length; j++) {
123
+ data.vals[j] = element.attributes[data.props[j]] || element.style[data.props[j]];
124
+ data.changed[j] = false;
125
+ }
126
+
127
+ // Set watch array
128
+ if (!element.watching) {
129
+ element.watching = [];
130
+ }
131
+
132
+ // Store data in watch array
133
+ element.watching.push(data);
134
+
135
+ // Create new Mutation Observer
136
+ var observer = new MutationObserver(function (mutations) {
137
+ console.log(mutations);
138
+ for (var k = 0; k < mutations.length; k++) {
139
+ check.call(mutations[k].target, mutations[k]);
140
+ }
141
+ });
142
+
143
+ // Set observer array
144
+ if (!element.observers) {
145
+ element.observers = [];
146
+ }
147
+
148
+ // Store element observer
149
+ element.observers.push(observer);
150
+
151
+ // Start observing
152
+ observer.observe(element, { subtree: false, attributes: true });
153
+
154
+ }
155
+
156
+ // Return elements to enable chaining
157
+ return self;
158
+
159
+ };
160
+
161
+ var _unwatch = function (elements, props){
162
+
163
+ // Setup
164
+ var self = this;
165
+
166
+ // Elements from node list to array
167
+ elements = toArray(elements);
168
+
169
+ // Iterate over elements
170
+ for (var i = 0; i < elements.length; i++) {
171
+
172
+ var element = elements[i];
173
+ var indexes = []
174
+
175
+ if (element.watching) {
176
+ for (var j = 0; j < element.watching.length; j++) {
177
+
178
+ var data = element.watching[j];
179
+ if (eqlArrays(data.props, props.split(' '))) {
180
+ indexes.push(j);
181
+ }
182
+
183
+ }
184
+
185
+ element.watching.multisplice.apply(element.watching, indexes);
186
+ }
187
+
188
+ }
189
+
190
+ // Return elements to enable chaining
191
+ return self;
192
+
193
+ };
194
+
195
+ // Expose watch to window
196
+ window.watch = function () {
197
+ return _watch.apply(arguments[0], arguments);
198
+ };
199
+
200
+ window.unwatch = function () {
201
+ return _unwatch.apply(arguments[0], arguments);
202
+ };
203
+
204
+ // Expose watch to jQuery
205
+ (function ($) {
206
+ $.fn.watch = function () {
207
+ Array.prototype.unshift.call(arguments, this);
208
+ return _watch.apply(this, arguments);
209
+ };
210
+
211
+ $.fn.unwatch = function () {
212
+ Array.prototype.unshift.call(arguments, this);
213
+ return _unwatch.apply(this, arguments);
214
+ };
215
+ })(jQuery);
216
+
217
+ })(window);
@@ -23,8 +23,13 @@ module Volt
23
23
  end
24
24
 
25
25
  if RUBY_PLATFORM == 'opal'
26
- # Don't validate on the server
27
- validate :password, length: 8
26
+ validations do
27
+ # Only validate password when it has changed
28
+ if changed?(:password)
29
+ # Don't validate on the server
30
+ validate :password, length: 8
31
+ end
32
+ end
28
33
  end
29
34
 
30
35
  def password=(val)
@@ -16,6 +16,12 @@ class QueryTasks < Volt::Task
16
16
  self.class.live_query_pool
17
17
  end
18
18
 
19
+ def self.reset!
20
+ @@channel_live_queries = {}
21
+ @@live_query_pool = nil
22
+ live_query_pool
23
+ end
24
+
19
25
  def add_listener(collection, query)
20
26
  live_query = @@live_query_pool.lookup(collection, query)
21
27
  track_channel_in_live_query(live_query)
data/lib/volt/boot.rb CHANGED
@@ -2,7 +2,7 @@ unless RUBY_PLATFORM == 'opal'
2
2
  # An option to skip requiring.
3
3
  unless ENV['SKIP_BUNDLER_REQUIRE']
4
4
  # Require in gems
5
- Bundler.require((ENV['VOLT_ENV'] || ENV['RACK_ENV'] || :development).to_sym)
5
+ Bundler.require(:default, (ENV['VOLT_ENV'] || ENV['RACK_ENV'] || :development).to_sym)
6
6
  end
7
7
  end
8
8
 
@@ -74,7 +74,7 @@ class Generate < Thor
74
74
  method_option :name, type: :string, banner: 'The name of the task.'
75
75
  method_option :component, type: :string, default: 'main', banner: 'The component the task should be created in.', required: false
76
76
  def task(name, component = 'main')
77
- name = name.underscore.gsub(/_tasks$/, '').singularize + '_tasks'
77
+ name = name.underscore.gsub(/_tasks$/, '').singularize + '_task'
78
78
  output_file = Dir.pwd + "/app/#{component}/tasks/#{name}.rb"
79
79
  spec_file = Dir.pwd + "/spec/app/#{component}/tasks/#{name}_spec.rb"
80
80
  template('task/task.rb.tt', output_file, task_name: name.camelize.singularize)
data/lib/volt/config.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # Config lets a user set global config options for Volt.
2
- # The hash is setup on the server, then passed to the client on initial page render.
2
+ # The hash is setup on the server, then the settings under .public are passed
3
+ # to the client on initial page render. Volt.configure can be called multiple
4
+ # times and settings will be added to the existing configuration.
3
5
  if RUBY_PLATFORM == 'opal'
4
6
  require 'ostruct'
5
7
 
@@ -82,8 +84,16 @@ else
82
84
  alias_method :config, :configuration
83
85
  end
84
86
 
87
+ inst = self
85
88
  configuration_defaults do |c|
86
- c.from_h(Volt.defaults)
89
+ current_config = inst.instance_variable_get(:@configuration)
90
+ if current_config
91
+ # Default to the existing config, so we can extend
92
+ c.from_h(current_config.to_h)
93
+ else
94
+ # First call
95
+ c.from_h(Volt.defaults)
96
+ end
87
97
  end
88
98
  end
89
99
  end
@@ -190,7 +190,7 @@ module Volt
190
190
  def require_login(message = 'You must login to access this area.')
191
191
  unless Volt.current_user_id
192
192
  flash._notices << message
193
- go '/login'
193
+ redirect_to '/login'
194
194
 
195
195
  stop_chain
196
196
  end
@@ -0,0 +1,34 @@
1
+ module Volt
2
+ class DataStore
3
+ class BaseAdaptorClient
4
+ # normalize_query should take all parts of the query and return a
5
+ # "normalized" version, so that two queries that are eseitnally the same
6
+ # except for things like order are the same.
7
+ #
8
+ # Typically this means sorting parts of the query so that two queries
9
+ # which do the same things are the same, so they can be uniquely
10
+ # identified.
11
+ #
12
+ # The default implementation does no normalizing. This works, but results
13
+ # in more queries being sent to the backend.
14
+ def self.normalize_query(query)
15
+ query
16
+ end
17
+
18
+ # A class method that takes an array of method names we want to provide
19
+ # on the ArrayModel class. (These are typically query/sort/order/etc...
20
+ # methods). This adds a proxy method to the store persistor for all
21
+ # passed in method names, and then sets up a default tracking method
22
+ # on the ArrayStore persistor.
23
+ def self.data_store_methods(*method_names)
24
+ Volt::ArrayModel.proxy_to_persistor(*method_names)
25
+
26
+ method_names.each do |method_name|
27
+ Volt::Persistors::ArrayStore.send(:define_method, method_name) do |*args|
28
+ add_query_part(method_name, *args)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,6 +1,6 @@
1
1
  module Volt
2
2
  class DataStore
3
- class Base
3
+ class BaseAdaptorServer
4
4
  end
5
5
  end
6
6
  end
@@ -1,20 +1,36 @@
1
- require 'volt/data_stores/mongo_driver'
1
+ require 'volt/data_stores/base_adaptor_server'
2
2
 
3
3
  module Volt
4
4
  class DataStore
5
5
  def self.fetch
6
6
  # Cache the driver
7
- return @driver if @driver
7
+ return @adaptor if @adaptor
8
8
 
9
9
  database_name = Volt.config.db_driver
10
- driver_name = database_name.camelize + 'Driver'
10
+ adaptor_name = database_name.camelize + 'AdaptorServer'
11
11
 
12
- begin
13
- driver = const_get(driver_name)
14
- @driver = MongoDriver.new
15
- rescue NameError => e
12
+ root = Volt::DataStore
13
+ if root.const_defined?(adaptor_name)
14
+ adaptor_name = root.const_get(adaptor_name)
15
+ @adaptor = adaptor_name.new
16
+ else
16
17
  raise "#{database_name} is not a supported database"
17
18
  end
19
+
20
+ @adaptor
21
+ end
22
+
23
+ def self.adaptor_client
24
+ # Load the client adaptor
25
+ @adaptor_client ||= begin
26
+ ds_name = Volt.config.public.datastore_name
27
+ unless ds_name
28
+ raise "No data store configured, please include volt-mongo or " +
29
+ "another similar gem."
30
+ end
31
+ adaptor_class_name = ds_name.capitalize + "AdaptorClient"
32
+ Volt::DataStore.const_get(adaptor_class_name)
33
+ end
18
34
  end
19
35
  end
20
36
  end