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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTING.md +4 -0
- data/Gemfile +3 -0
- data/app/volt/assets/js/volt_js_polyfills.js +0 -1
- data/app/volt/assets/js/volt_watch.js +217 -0
- data/app/volt/models/user.rb +7 -2
- data/app/volt/tasks/query_tasks.rb +6 -0
- data/lib/volt/boot.rb +1 -1
- data/lib/volt/cli/generate.rb +1 -1
- data/lib/volt/config.rb +12 -2
- data/lib/volt/controllers/model_controller.rb +1 -1
- data/lib/volt/data_stores/base_adaptor_client.rb +34 -0
- data/lib/volt/data_stores/{base.rb → base_adaptor_server.rb} +1 -1
- data/lib/volt/data_stores/data_store.rb +23 -7
- data/lib/volt/models/array_model.rb +3 -2
- data/lib/volt/models/model.rb +29 -91
- data/lib/volt/models/{dirty.rb → model_helpers/dirty.rb} +0 -0
- data/lib/volt/models/{listener_tracker.rb → model_helpers/listener_tracker.rb} +0 -0
- data/lib/volt/models/model_helpers/model_change_helpers.rb +76 -0
- data/lib/volt/models/{model_helpers.rb → model_helpers/model_helpers.rb} +0 -0
- data/lib/volt/models/persistors/array_store.rb +2 -23
- data/lib/volt/models/persistors/query/normalizer.rb +0 -44
- data/{templates/project/lib/.empty_directory → lib/volt/models/validations/errors.rb} +0 -0
- data/lib/volt/models/{validations.rb → validations/validations.rb} +80 -26
- data/lib/volt/page/bindings/attribute_binding.rb +17 -3
- data/lib/volt/page/page.rb +1 -0
- data/lib/volt/reactive/eventable.rb +1 -0
- data/lib/volt/server.rb +2 -1
- data/lib/volt/server/component_templates.rb +66 -16
- data/lib/volt/server/forking_server.rb +16 -14
- data/lib/volt/server/html_parser/sandlebars_parser.rb +2 -0
- data/lib/volt/server/html_parser/view_scope.rb +2 -0
- data/lib/volt/server/rack/component_paths.rb +4 -2
- data/lib/volt/server/rack/opal_files.rb +4 -2
- data/lib/volt/server/socket_connection_handler.rb +5 -1
- data/lib/volt/server/template_handlers/handlers.rb +0 -0
- data/lib/volt/spec/setup.rb +23 -8
- data/lib/volt/tasks/dispatcher.rb +4 -0
- data/lib/volt/utils/promise_patch.rb +3 -0
- data/lib/volt/version.rb +1 -1
- data/spec/apps/kitchen_sink/Gemfile +5 -0
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
- data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +10 -0
- data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +20 -0
- data/spec/apps/kitchen_sink/app/main/views/main/form.html +73 -0
- data/spec/apps/kitchen_sink/app/main/views/main/main.html +1 -0
- data/spec/integration/bindings_spec.rb +33 -0
- data/spec/integration/user_spec.rb +51 -21
- data/spec/models/associations_spec.rb +8 -0
- data/spec/models/model_spec.rb +7 -0
- data/spec/models/user_spec.rb +20 -0
- data/spec/models/validations_spec.rb +2 -1
- data/spec/models/validators/block_validations_spec.rb +53 -0
- data/spec/page/bindings/template_binding/view_lookup_for_path_spec.rb +10 -0
- data/spec/page/path_string_renderer_spec.rb +6 -0
- data/spec/reactive/eventable_spec.rb +24 -6
- data/spec/server/component_templates_spec.rb +21 -0
- data/spec/server/html_parser/sandlebars_parser_spec.rb +12 -13
- data/spec/server/html_parser/view_parser_spec.rb +3 -0
- data/spec/server/rack/asset_files_spec.rb +2 -2
- data/spec/server/rack/http_resource_spec.rb +10 -0
- data/spec/tasks/dispatcher_spec.rb +5 -0
- data/spec/tasks/user_tasks_spec.rb +59 -0
- data/spec/utils/task_argument_filtererer_spec.rb +6 -0
- data/templates/newgem/app/newgem/config/initializers/boot.rb +10 -0
- data/templates/newgem/lib/newgem.rb.tt +13 -0
- data/templates/project/Gemfile.tt +3 -0
- data/templates/project/app/main/lib/.empty_directory +0 -0
- data/volt.gemspec +3 -1
- metadata +24 -25
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6e09afcd5fa1abe6f17a9c2912bc79cf4cf74aa
|
4
|
+
data.tar.gz: f0ee7b0085bddf48461122bfccec1b21b06b2e3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
@@ -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);
|
data/app/volt/models/user.rb
CHANGED
@@ -23,8 +23,13 @@ module Volt
|
|
23
23
|
end
|
24
24
|
|
25
25
|
if RUBY_PLATFORM == 'opal'
|
26
|
-
|
27
|
-
|
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
|
|
data/lib/volt/cli/generate.rb
CHANGED
@@ -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 + '
|
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
|
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
|
-
|
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
|
@@ -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,20 +1,36 @@
|
|
1
|
-
require 'volt/data_stores/
|
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 @
|
7
|
+
return @adaptor if @adaptor
|
8
8
|
|
9
9
|
database_name = Volt.config.db_driver
|
10
|
-
|
10
|
+
adaptor_name = database_name.camelize + 'AdaptorServer'
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|