volt 0.9.5.pre4 → 0.9.5.pre5
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 +10 -0
- data/README.md +13 -5
- data/app/volt/assets/css/{notices.css.scss → notices.scss} +0 -0
- data/app/volt/models/active_volt_instance.rb +1 -1
- data/app/volt/tasks/live_query/live_query.rb +11 -3
- data/app/volt/tasks/store_tasks.rb +14 -17
- data/lib/volt/cli.rb +22 -0
- data/lib/volt/cli/asset_compile.rb +63 -63
- data/lib/volt/cli/base_index_renderer.rb +26 -0
- data/lib/volt/cli/generate.rb +1 -1
- data/lib/volt/config.rb +1 -0
- data/lib/volt/controllers/model_controller.rb +37 -1
- data/lib/volt/extra_core/array.rb +22 -0
- data/lib/volt/models/array_model.rb +7 -1
- data/lib/volt/models/errors.rb +1 -1
- data/lib/volt/models/field_helpers.rb +36 -21
- data/lib/volt/models/model.rb +16 -0
- data/lib/volt/models/validations/validations.rb +21 -6
- data/lib/volt/models/validators/type_validator.rb +35 -3
- data/lib/volt/page/bindings/content_binding.rb +1 -1
- data/lib/volt/page/bindings/event_binding.rb +40 -16
- data/lib/volt/page/document_events.rb +8 -6
- data/lib/volt/reactive/reactive_array.rb +18 -1
- data/lib/volt/server/forking_server.rb +7 -1
- data/lib/volt/server/html_parser/attribute_scope.rb +26 -0
- data/lib/volt/server/html_parser/component_view_scope.rb +30 -22
- data/lib/volt/server/middleware/default_middleware_stack.rb +6 -1
- data/lib/volt/server/rack/asset_files.rb +5 -3
- data/lib/volt/server/rack/opal_files.rb +35 -23
- data/lib/volt/server/rack/sprockets_helpers_setup.rb +71 -0
- data/lib/volt/server/template_handlers/view_processor.rb +1 -2
- data/lib/volt/utils/promise_extensions.rb +1 -1
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +0 -2
- data/lib/volt/volt/client_setup/browser.rb +11 -0
- data/spec/apps/kitchen_sink/Gemfile +37 -14
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +3 -0
- data/spec/apps/kitchen_sink/app/main/controllers/events_controller.rb +26 -0
- data/spec/apps/kitchen_sink/app/main/views/events/index.html +30 -0
- data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +3 -0
- data/spec/apps/kitchen_sink/app/main/views/main/yield.html +1 -6
- data/spec/apps/kitchen_sink/app/main/views/{yield-component → yield_component}/index.html +0 -0
- data/spec/extra_core/array_spec.rb +26 -0
- data/spec/integration/bindings_spec.rb +9 -0
- data/spec/integration/event_spec.rb +19 -0
- data/spec/models/array_model_spec.rb +13 -0
- data/spec/models/field_helpers_spec.rb +2 -2
- data/spec/models/validations_spec.rb +31 -0
- data/spec/models/validators/type_validator_spec.rb +47 -1
- data/spec/reactive/reactive_array_spec.rb +46 -0
- data/spec/server/forking_server_spec.rb +27 -0
- data/spec/server/html_parser/view_scope_spec.rb +44 -0
- data/spec/server/rack/asset_files_spec.rb +2 -2
- data/templates/project/Gemfile.tt +8 -0
- data/templates/project/config/app.rb.tt +2 -1
- data/volt.gemspec +1 -1
- metadata +31 -5
@@ -13,6 +13,9 @@ client '/html_safe', action: 'html_safe'
|
|
13
13
|
client '/missing', action: 'missing'
|
14
14
|
client '/require_test', action: 'require_test'
|
15
15
|
|
16
|
+
# Events
|
17
|
+
client '/events', component: 'main', controller: 'events', action: 'index'
|
18
|
+
|
16
19
|
# Signup/login routes
|
17
20
|
client '/signup', component: 'user_templates', controller: 'signup'
|
18
21
|
client '/login', component: 'user_templates', controller: 'login'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Main
|
2
|
+
class EventsController < Volt::ModelController
|
3
|
+
reactive_accessor :ran_some_event
|
4
|
+
reactive_accessor :ran_other_event
|
5
|
+
|
6
|
+
def trig_some_event
|
7
|
+
trigger('some_event', 'yes')
|
8
|
+
end
|
9
|
+
|
10
|
+
def some_event(passes_args, event)
|
11
|
+
if passes_args == 'yes' && event.is_a?(Volt::JSEvent)
|
12
|
+
self.ran_some_event = true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def trig_other_event
|
17
|
+
trigger('other_event', 'yes')
|
18
|
+
end
|
19
|
+
|
20
|
+
def other_event(passes_args)
|
21
|
+
if passes_args == 'yes'
|
22
|
+
self.ran_other_event = true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<:Title>
|
2
|
+
Events
|
3
|
+
|
4
|
+
<:Body>
|
5
|
+
<h1>Events</h1>
|
6
|
+
|
7
|
+
<div e-some_event="some_event">
|
8
|
+
<:some-event-button />
|
9
|
+
</div>
|
10
|
+
|
11
|
+
|
12
|
+
<:other-event-button e-other-event="other_event" />
|
13
|
+
|
14
|
+
|
15
|
+
{{ if ran_some_event }}
|
16
|
+
ran some_event
|
17
|
+
{{ end }}
|
18
|
+
|
19
|
+
{{ if ran_other_event }}
|
20
|
+
ran other_event
|
21
|
+
{{ end }}
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
<:SomeEventButton>
|
27
|
+
<button e-click="trig_some_event">Run Some Event</button>
|
28
|
+
|
29
|
+
<:OtherEventButton>
|
30
|
+
<button e-click="trig_other_event">Run Other Event</button>
|
@@ -6,13 +6,8 @@
|
|
6
6
|
|
7
7
|
<:yield-component>This is my {{ content_string }}</:yield-component>
|
8
8
|
|
9
|
-
<:
|
9
|
+
<:YieldTest>
|
10
10
|
<h1>Yield Section</h1>
|
11
11
|
|
12
12
|
<p>{{ yield }}</p>
|
13
13
|
<p>{{ yield }}</p>
|
14
|
-
|
15
|
-
|
16
|
-
{{ if Volt.current_user }}
|
17
|
-
Email: {{ Volt.current_user._email }}
|
18
|
-
{{ end }}
|
File without changes
|
@@ -7,4 +7,30 @@ describe Array do
|
|
7
7
|
expect([1, 2, 3].sum).to eq(6)
|
8
8
|
end
|
9
9
|
end
|
10
|
+
|
11
|
+
describe "#to_sentence" do
|
12
|
+
it 'should return an empty string' do
|
13
|
+
expect([].to_sentence).to eq('')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should return a single entry' do
|
17
|
+
expect([1].to_sentence).to eq('1')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should combine an array into a string with a conjunection and commas' do
|
21
|
+
expect([1,2,3].to_sentence).to eq('1, 2, and 3')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should allow you to build an incorrect sentence' do
|
25
|
+
expect([1,2,3].to_sentence(oxford: false)).to eq('1, 2 and 3')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'let you change the conjunction' do
|
29
|
+
expect([1,2,3].to_sentence(conjunction: 'or')).to eq('1, 2, or 3')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'let you change the comma' do
|
33
|
+
expect([1,2,3].to_sentence(comma: '!')).to eq('1! 2! and 3')
|
34
|
+
end
|
35
|
+
end
|
10
36
|
end
|
@@ -243,6 +243,15 @@ describe 'bindings test', type: :feature, sauce: true do
|
|
243
243
|
end
|
244
244
|
end
|
245
245
|
|
246
|
+
describe 'raw' do
|
247
|
+
it 'should print the raw version, and work with promises' do
|
248
|
+
visit '/bindings'
|
249
|
+
|
250
|
+
expect(page).to have_content("some \ncode")
|
251
|
+
expect(page).to have_content("some \nother code")
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
246
255
|
# NOTE: For some reason this spec fails randomly (capybara issue I think)
|
247
256
|
# describe "events" do
|
248
257
|
# it 'should handle focus and blur' do
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'events and bubbling', type: :feature, sauce: true do
|
4
|
+
it 'should bubble events through the dom' do
|
5
|
+
visit '/events'
|
6
|
+
|
7
|
+
click_button 'Run Some Event'
|
8
|
+
|
9
|
+
expect(page).to have_content('ran some_event')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should let you specify an e- handler on components' do
|
13
|
+
visit '/events'
|
14
|
+
|
15
|
+
click_button 'Run Other Event'
|
16
|
+
|
17
|
+
expect(page).to have_content('ran other_event')
|
18
|
+
end
|
19
|
+
end
|
@@ -28,6 +28,7 @@ describe Volt::ArrayModel do
|
|
28
28
|
expect(array_model.index(2)).to eq(1)
|
29
29
|
end
|
30
30
|
|
31
|
+
|
31
32
|
it 'should flatten' do
|
32
33
|
array = Volt::ArrayModel.new([])
|
33
34
|
|
@@ -37,4 +38,16 @@ describe Volt::ArrayModel do
|
|
37
38
|
expect(array.flatten.size).to eq(6)
|
38
39
|
expect(array.to_a.flatten.size).to eq(6)
|
39
40
|
end
|
41
|
+
|
42
|
+
unless RUBY_PLATFORM == 'opal'
|
43
|
+
it 'should return a promise for store on .length, .size, and .count' do
|
44
|
+
store._items << {name: 'One'}
|
45
|
+
|
46
|
+
[:size, :count, :length].each do |method_name|
|
47
|
+
val = store._items.send(method_name)
|
48
|
+
expect(val.class).to eq(Promise)
|
49
|
+
expect(val.sync).to eq(1)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
40
53
|
end
|
@@ -26,7 +26,7 @@ describe 'field helpers' do
|
|
26
26
|
|
27
27
|
it 'should raise an error when an invalid cast type is provided' do
|
28
28
|
expect do
|
29
|
-
ExampleModelWithField2.field :awesome,
|
29
|
+
ExampleModelWithField2.field :awesome, Range
|
30
30
|
end.to raise_error(FieldHelpers::InvalidFieldClass)
|
31
31
|
end
|
32
32
|
|
@@ -47,6 +47,6 @@ describe 'field helpers' do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'should track the fields on the model class' do
|
50
|
-
expect(ExampleModelWithField.fields_data).to eq({:name=>[nil, {}], :value=>[Numeric, {}]})
|
50
|
+
expect(ExampleModelWithField.fields_data).to eq({:name=>[nil, {}], :value=>[[Numeric, NilClass], {}]})
|
51
51
|
end
|
52
52
|
end
|
@@ -165,4 +165,35 @@ describe Volt::Model do
|
|
165
165
|
expect(model._name).to eq('Jimmy')
|
166
166
|
end
|
167
167
|
|
168
|
+
describe 'custom validations' do
|
169
|
+
let(:model) { test_model_with_custom_validation.new }
|
170
|
+
let(:test_model_with_custom_validation) do
|
171
|
+
Class.new(Volt::Model) do
|
172
|
+
validations do
|
173
|
+
validate :something, presence: true
|
174
|
+
validate do
|
175
|
+
if _name.present?
|
176
|
+
{}
|
177
|
+
else
|
178
|
+
{name: ['must be present']}
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should return errors for all failed validations' do
|
186
|
+
model.validate!
|
187
|
+
expect(model.errors).to eq(
|
188
|
+
name: ['must be present'],
|
189
|
+
something: ['must be specified']
|
190
|
+
)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'should not return errors for all passing custom validations' do
|
194
|
+
model._name = 'something'
|
195
|
+
model.validate!
|
196
|
+
expect(model.errors).to eq({something: ["must be specified"]})
|
197
|
+
end
|
198
|
+
end
|
168
199
|
end
|
@@ -20,7 +20,7 @@ describe Volt::TypeValidator do
|
|
20
20
|
describe 'when count is a string' do
|
21
21
|
let(:count) { 'Cats' }
|
22
22
|
it do
|
23
|
-
expect(subject).to eq({count: ['must be
|
23
|
+
expect(subject).to eq({count: ['must be a number']})
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -41,6 +41,52 @@ describe Volt::TypeValidator do
|
|
41
41
|
expect(subject).to eq(count: ['must be a number'])
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
# Fails on opal because no True/False class
|
46
|
+
# describe 'when passing in multiple types' do
|
47
|
+
# let(:options) do
|
48
|
+
# { types: [TrueClass, FalseClass] }
|
49
|
+
# end
|
50
|
+
# let(:count) { 'a string' }
|
51
|
+
|
52
|
+
# it do
|
53
|
+
# expect(subject).to eq({count: ['must be true or false']})
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
|
57
|
+
describe 'when passing in Volt::Boolean' do
|
58
|
+
let(:options) do
|
59
|
+
{ type: Volt::Boolean }
|
60
|
+
end
|
61
|
+
let(:count) { 'a string' }
|
62
|
+
|
63
|
+
it do
|
64
|
+
expect(subject).to eq({count: ['must be true or false']})
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'when passing in multiple types' do
|
69
|
+
let(:options) do
|
70
|
+
{ types: [String, Float] }
|
71
|
+
end
|
72
|
+
let(:count) { 1..1 }
|
73
|
+
|
74
|
+
it do
|
75
|
+
expect(subject).to eq({count: ['must be a String or a number']})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'when passing in multiple types with nil' do
|
80
|
+
let(:options) do
|
81
|
+
{ types: [String, Float, NilClass] }
|
82
|
+
end
|
83
|
+
let(:count) { 1..1 }
|
84
|
+
|
85
|
+
it do
|
86
|
+
expect(subject).to eq({count: ['must be a String or a number']})
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
44
90
|
end
|
45
91
|
end
|
46
92
|
end
|
@@ -38,6 +38,52 @@ describe Volt::ReactiveArray do
|
|
38
38
|
expect(values).to eq([nil, 4])
|
39
39
|
end
|
40
40
|
|
41
|
+
describe ".last" do
|
42
|
+
let(:array) { Volt::ReactiveArray.new([1,2,3]) }
|
43
|
+
|
44
|
+
it 'should trigger changed on .last when appending or inserting' do
|
45
|
+
values = []
|
46
|
+
-> { values << array.last }.watch!
|
47
|
+
|
48
|
+
expect(values).to eq([3])
|
49
|
+
|
50
|
+
array << 4
|
51
|
+
Volt::Computation.flush!
|
52
|
+
expect(values).to eq([3,4])
|
53
|
+
|
54
|
+
array.insert(1,2)
|
55
|
+
Volt::Computation.flush!
|
56
|
+
expect(values).to eq([3,4,4])
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should trigger changed on .last when the last value is changed' do
|
60
|
+
values = []
|
61
|
+
-> { values << array.last }.watch!
|
62
|
+
expect(values).to eq([3])
|
63
|
+
|
64
|
+
array[2] = 5
|
65
|
+
Volt::Computation.flush!
|
66
|
+
expect(values).to eq([3,5])
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should not trigger changed on .last when a value other than last changes' do
|
70
|
+
values = []
|
71
|
+
-> { values << array.last }.watch!
|
72
|
+
expect(values).to eq([3])
|
73
|
+
|
74
|
+
array[1] = 20
|
75
|
+
expect(values).to eq([3])
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should not raise an error on a negative lookup on an empty array' do
|
79
|
+
array = Volt::ArrayModel.new([])
|
80
|
+
|
81
|
+
expect do
|
82
|
+
array[-1]
|
83
|
+
end.not_to raise_error
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
41
87
|
it 'should trigger changes for each cell after index after insert' do
|
42
88
|
a = Volt::ReactiveArray.new([1, 2, 3])
|
43
89
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
unless RUBY_PLATFORM == 'opal'
|
3
|
+
require 'volt/server'
|
4
|
+
|
5
|
+
describe Volt::ForkingServer do
|
6
|
+
it 'should set polling an an option when using POLL_FS env' do
|
7
|
+
ENV['POLL_FS'] = 'true'
|
8
|
+
forking_server = Volt::ForkingServer.allocate
|
9
|
+
|
10
|
+
# Lots of stubs, since we're working with the FS
|
11
|
+
listener = double('listener')
|
12
|
+
expect(listener).to receive(:start)
|
13
|
+
expect(listener).to receive(:stop)
|
14
|
+
expect(Listen).to receive(:to).with('/app/', {force_polling: true}).and_return(listener)
|
15
|
+
expect(forking_server).to receive(:sync_mod_time)
|
16
|
+
|
17
|
+
server = double('server')
|
18
|
+
expect(server).to receive(:app_path).and_return('/app')
|
19
|
+
forking_server.instance_variable_set(:@server, server)
|
20
|
+
|
21
|
+
forking_server.start_change_listener
|
22
|
+
ENV.delete('POLL_FS')
|
23
|
+
|
24
|
+
forking_server.stop_change_listener
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Volt::ViewScope do
|
4
|
+
describe "methodize strings" do
|
5
|
+
def methodize(str)
|
6
|
+
Volt::ViewScope.methodize_string(str)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should methodize a method without args' do
|
10
|
+
code = methodize('something')
|
11
|
+
expect(code).to eq('method(:something)')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should methodize a method without args2' do
|
15
|
+
code = methodize('something?')
|
16
|
+
expect(code).to eq('method(:something?)')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should methodize a method wit args1' do
|
20
|
+
code = methodize('set_something(true)')
|
21
|
+
expect(code).to eq('set_something(true)')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should not methodize a method call with args' do
|
25
|
+
code = methodize('something(item1, item2)')
|
26
|
+
expect(code).to eq('something(item1, item2)')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should not methodize on assignment' do
|
30
|
+
code = methodize('params._something = 5')
|
31
|
+
expect(code).to eq('params._something = 5')
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should not methodize on hash lookup' do
|
35
|
+
code = methodize('hash[:something]')
|
36
|
+
expect(code).to eq('hash[:something]')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should not methodize on instance variables' do
|
40
|
+
code = methodize('@something.call')
|
41
|
+
expect(code).to eq('@something.call')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -21,7 +21,7 @@ if RUBY_PLATFORM != 'opal'
|
|
21
21
|
context "when the component's dependencies.rb does not contain .disable_auto_import" do
|
22
22
|
it 'should list all JS files' do
|
23
23
|
main = Volt::AssetFiles.new('main', @component_paths)
|
24
|
-
expect(main.javascript(volt_app)).to eq([
|
24
|
+
expect(main.javascript(volt_app).reject{|v| v[0] != :src }).to eq([
|
25
25
|
[:src, '/assets/js/jquery-2.0.3.js'],
|
26
26
|
[:src, '/assets/js/volt_js_polyfills.js'],
|
27
27
|
[:src, '/assets/js/volt_watch.js'],
|
@@ -38,7 +38,7 @@ if RUBY_PLATFORM != 'opal'
|
|
38
38
|
context "when the component's dependencies.rb contains .disable_auto_import" do
|
39
39
|
it 'should list only the files included via the css_file helpers' do
|
40
40
|
disabled_auto = Volt::AssetFiles.new('disable_auto', @component_paths)
|
41
|
-
expect(disabled_auto.javascript(volt_app)).to eq([
|
41
|
+
expect(disabled_auto.javascript(volt_app).reject{|v| v[0] != :src }).to eq([
|
42
42
|
[:src, '/assets/js/jquery-2.0.3.js'],
|
43
43
|
[:src, '/assets/js/volt_js_polyfills.js'],
|
44
44
|
[:src, '/assets/js/volt_watch.js'],
|