volt 0.7.23 → 0.8.0
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/.travis.yml +8 -1
- data/CHANGELOG.md +22 -0
- data/Gemfile +8 -0
- data/Guardfile +2 -2
- data/Readme.md +139 -136
- data/VERSION +1 -1
- data/app/volt/assets/js/setImmediate.js +175 -0
- data/app/volt/tasks/live_query/data_store.rb +0 -2
- data/app/volt/tasks/live_query/live_query.rb +4 -4
- data/docs/GETTING_STARTED.md +24 -3
- data/docs/WHY.md +1 -22
- data/lib/volt.rb +20 -1
- data/lib/volt/console.rb +20 -0
- data/lib/volt/controllers/model_controller.rb +25 -11
- data/lib/volt/extra_core/object.rb +2 -14
- data/lib/volt/extra_core/string.rb +4 -0
- data/lib/volt/models.rb +0 -1
- data/lib/volt/models/array_model.rb +8 -16
- data/lib/volt/models/cursor.rb +1 -1
- data/lib/volt/models/model.rb +40 -60
- data/lib/volt/models/model_hash_behaviour.rb +10 -24
- data/lib/volt/models/model_helpers.rb +2 -2
- data/lib/volt/models/model_state.rb +1 -1
- data/lib/volt/models/model_wrapper.rb +4 -4
- data/lib/volt/models/persistors/array_store.rb +44 -28
- data/lib/volt/models/persistors/base.rb +1 -1
- data/lib/volt/models/persistors/model_store.rb +1 -1
- data/lib/volt/models/persistors/params.rb +5 -1
- data/lib/volt/models/persistors/query/query_listener.rb +2 -0
- data/lib/volt/models/persistors/store.rb +3 -2
- data/lib/volt/models/persistors/store_state.rb +7 -2
- data/lib/volt/models/url.rb +35 -29
- data/lib/volt/models/validations.rb +7 -17
- data/lib/volt/page/bindings/attribute_binding.rb +57 -39
- data/lib/volt/page/bindings/base_binding.rb +0 -14
- data/lib/volt/page/bindings/content_binding.rb +15 -18
- data/lib/volt/page/bindings/each_binding.rb +67 -34
- data/lib/volt/page/bindings/if_binding.rb +15 -12
- data/lib/volt/page/bindings/template_binding.rb +77 -59
- data/lib/volt/page/bindings/template_binding/grouped_controllers.rb +19 -4
- data/lib/volt/page/channel.rb +22 -38
- data/lib/volt/page/channel_stub.rb +3 -6
- data/lib/volt/page/page.rb +24 -26
- data/lib/volt/page/string_template_renderer.rb +46 -0
- data/lib/volt/page/sub_context.rb +7 -1
- data/lib/volt/page/targets/binding_document/component_node.rb +11 -9
- data/lib/volt/page/tasks.rb +3 -2
- data/lib/volt/page/url_tracker.rb +4 -3
- data/lib/volt/reactive/computation.rb +131 -0
- data/lib/volt/reactive/dependency.rb +71 -0
- data/lib/volt/reactive/eventable.rb +82 -0
- data/lib/volt/reactive/hash_dependency.rb +36 -0
- data/lib/volt/{controllers → reactive}/reactive_accessors.rb +8 -11
- data/lib/volt/reactive/reactive_array.rb +100 -193
- data/lib/volt/reactive/reactive_hash.rb +49 -0
- data/lib/volt/server/html_parser/attribute_scope.rb +24 -4
- data/lib/volt/server/html_parser/if_view_scope.rb +15 -15
- data/lib/volt/server/html_parser/view_scope.rb +31 -1
- data/spec/apps/kitchen_sink/Gemfile +4 -8
- data/spec/apps/kitchen_sink/app/main/config/dependencies.rb +8 -0
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +8 -1
- data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +8 -0
- data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +73 -0
- data/spec/apps/kitchen_sink/app/main/views/main/index.html +6 -1
- data/spec/apps/kitchen_sink/app/main/views/main/main.html +26 -6
- data/spec/apps/kitchen_sink/app/main/views/main/store.html +6 -0
- data/spec/controllers/reactive_accessors_spec.rb +13 -15
- data/spec/integration/bindings_spec.rb +159 -0
- data/spec/integration/templates_spec.rb +15 -0
- data/spec/models/model_spec.rb +130 -228
- data/spec/reactive/computation_spec.rb +63 -0
- data/spec/reactive/dependency_spec.rb +5 -0
- data/spec/reactive/eventable_spec.rb +48 -0
- data/spec/reactive/reactive_array_spec.rb +97 -0
- data/spec/router/routes_spec.rb +26 -27
- data/spec/server/html_parser/view_parser_spec.rb +3 -21
- data/spec/server/rack/asset_files_spec.rb +1 -1
- data/templates/project/app/main/views/main/main.html +2 -2
- metadata +29 -41
- data/lib/volt/extra_core/time.rb +0 -16
- data/lib/volt/page/draw_cycle.rb +0 -31
- data/lib/volt/page/memory_test.rb +0 -26
- data/lib/volt/page/reactive_template.rb +0 -32
- data/lib/volt/reactive/array_extensions.rb +0 -12
- data/lib/volt/reactive/destructive_methods.rb +0 -19
- data/lib/volt/reactive/event_chain.rb +0 -125
- data/lib/volt/reactive/events.rb +0 -216
- data/lib/volt/reactive/object_tracking.rb +0 -14
- data/lib/volt/reactive/reactive_block.rb +0 -88
- data/lib/volt/reactive/reactive_generator.rb +0 -44
- data/lib/volt/reactive/reactive_tags.rb +0 -71
- data/lib/volt/reactive/reactive_value.rb +0 -427
- data/lib/volt/reactive/string_extensions.rb +0 -31
- data/spec/integration/test_integration_spec.rb +0 -14
- data/spec/models/event_chain_spec.rb +0 -150
- data/spec/models/model_buffers_spec.rb +0 -9
- data/spec/models/old_model_spec.rb +0 -67
- data/spec/models/reactive_array_spec.rb +0 -364
- data/spec/models/reactive_block_spec.rb +0 -13
- data/spec/models/reactive_call_times_spec.rb +0 -28
- data/spec/models/reactive_generator_spec.rb +0 -58
- data/spec/models/reactive_tags_spec.rb +0 -35
- data/spec/models/reactive_value_spec.rb +0 -370
- data/spec/models/store_spec.rb +0 -16
- data/spec/models/string_extensions_spec.rb +0 -57
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'volt/reactive/hash_dependency'
|
|
2
|
+
|
|
3
|
+
class ReactiveHash
|
|
4
|
+
def initialize(values={})
|
|
5
|
+
@hash = values
|
|
6
|
+
@deps = HashDependency.new
|
|
7
|
+
@all_deps = Dependency.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def ==(val)
|
|
11
|
+
@all_deps.depend
|
|
12
|
+
@hash == val
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# TODO: We should finish off this class for reactivity
|
|
16
|
+
def method_missing(method_name, *args, &block)
|
|
17
|
+
@all_deps.depend
|
|
18
|
+
|
|
19
|
+
return @hash.send(method_name, *args, &block)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def [](key)
|
|
23
|
+
@deps.depend(key)
|
|
24
|
+
|
|
25
|
+
return @hash[key]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def []=(key, value)
|
|
29
|
+
@deps.changed!(key)
|
|
30
|
+
@all_deps.changed!
|
|
31
|
+
|
|
32
|
+
@hash[key] = value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def delete(key)
|
|
36
|
+
@deps.delete(key)
|
|
37
|
+
@hash.delete(key)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def clear
|
|
41
|
+
@hash.each_pair do |key,_|
|
|
42
|
+
delete(key)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def inspect
|
|
47
|
+
"#<ReactiveHash #{@hash.inspect}>"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -53,11 +53,31 @@ module AttributeScope
|
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
# TODO: We should use a real parser for this
|
|
57
|
+
def getter_to_setter(getter)
|
|
58
|
+
getter = getter.strip
|
|
59
|
+
|
|
60
|
+
# Convert a getter into a setter
|
|
61
|
+
if getter.index('.') || getter.index('@')
|
|
62
|
+
prefix = ''
|
|
63
|
+
else
|
|
64
|
+
prefix = 'self.'
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
return "#{prefix}#{getter}=(val)"
|
|
68
|
+
end
|
|
69
|
+
|
|
56
70
|
# Add an attribute binding on the tag, bind directly to the getter in the binding
|
|
57
71
|
def add_single_attribute(id, attribute_name, parts)
|
|
58
72
|
getter = parts[0][1..-2]
|
|
59
73
|
|
|
60
|
-
|
|
74
|
+
# if getter.index('@')
|
|
75
|
+
# raise "Bindings currently do not support instance variables"
|
|
76
|
+
# end
|
|
77
|
+
|
|
78
|
+
setter = getter_to_setter(getter)
|
|
79
|
+
|
|
80
|
+
save_binding(id, "lambda { |__p, __t, __c, __id| AttributeBinding.new(__p, __t, __c, __id, #{attribute_name.inspect}, Proc.new { #{getter} }, Proc.new { |val| #{setter} }) }")
|
|
61
81
|
end
|
|
62
82
|
|
|
63
83
|
|
|
@@ -74,12 +94,12 @@ module AttributeScope
|
|
|
74
94
|
end
|
|
75
95
|
end
|
|
76
96
|
|
|
77
|
-
|
|
97
|
+
string_template_renderer_path = add_string_template_renderer(content)
|
|
78
98
|
|
|
79
|
-
save_binding(id, "lambda { |__p, __t, __c, __id| AttributeBinding.new(__p, __t, __c, __id, #{attribute_name.inspect}, Proc.new {
|
|
99
|
+
save_binding(id, "lambda { |__p, __t, __c, __id| AttributeBinding.new(__p, __t, __c, __id, #{attribute_name.inspect}, Proc.new { StringTemplateRender.new(__p, __c, #{string_template_renderer_path.inspect}) }) }")
|
|
80
100
|
end
|
|
81
101
|
|
|
82
|
-
def
|
|
102
|
+
def add_string_template_renderer(content)
|
|
83
103
|
path = @path + "/_rv#{@binding_number}"
|
|
84
104
|
new_handler = ViewHandler.new(path, false)
|
|
85
105
|
@binding_number += 1
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
class IfViewScope < ViewScope
|
|
2
2
|
def initialize(handler, path, content)
|
|
3
3
|
super(handler, path)
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
@original_path = @path
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
@last_content = content
|
|
8
8
|
@branches = []
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
# We haven't added the if yet
|
|
11
11
|
@if_binding_number = @handler.last.binding_number
|
|
12
12
|
@handler.last.binding_number += 1
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
@path_number = 0
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
new_path
|
|
17
17
|
end
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
def new_path
|
|
20
20
|
@path = @original_path + "/__if#{@path_number}"
|
|
21
21
|
@path_number += 1
|
|
@@ -27,26 +27,26 @@ class IfViewScope < ViewScope
|
|
|
27
27
|
close_scope(false)
|
|
28
28
|
|
|
29
29
|
@last_content = content
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
# Clear existing
|
|
32
32
|
@html = ''
|
|
33
33
|
@bindings = {}
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
# Close scope removes us, so lets add it back.
|
|
36
36
|
@handler.scope << self
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
@binding_number = 0
|
|
39
39
|
|
|
40
40
|
# Generate a new template path for this section.
|
|
41
41
|
new_path
|
|
42
42
|
end
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
def close_scope(final=true)
|
|
45
|
-
@branches << [@last_content, path]
|
|
45
|
+
@branches << [@last_content, path]
|
|
46
46
|
|
|
47
47
|
super()
|
|
48
48
|
|
|
49
|
-
if final
|
|
49
|
+
if final
|
|
50
50
|
# Add the binding to the parent
|
|
51
51
|
branches = @branches.map do |branch|
|
|
52
52
|
content = branch[0]
|
|
@@ -55,16 +55,16 @@ class IfViewScope < ViewScope
|
|
|
55
55
|
else
|
|
56
56
|
content = "Proc.new { #{branch[0]} }"
|
|
57
57
|
end
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
"[#{content}, #{branch[1].inspect}]"
|
|
60
60
|
end.join(', ')
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
new_scope = @handler.last
|
|
63
63
|
|
|
64
64
|
# variables are captured for branches, so we must prefix them so they don't conflict.
|
|
65
65
|
# page, target, context, id
|
|
66
66
|
new_scope.save_binding(@if_binding_number, "lambda { |__p, __t, __c, __id| IfBinding.new(__p, __t, __c, __id, [#{branches}]) }")
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
new_scope.html << "<!-- $#{@if_binding_number} --><!-- $/#{@if_binding_number} -->"
|
|
69
69
|
end
|
|
70
70
|
end
|
|
@@ -77,6 +77,22 @@ class ViewScope
|
|
|
77
77
|
@binding_number += 1
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
+
# Returns ruby code to fetch the parent. (by removing the last fetch)
|
|
81
|
+
# TODO: Probably want to do this with AST transforms with the parser/unparser gems
|
|
82
|
+
def parent_fetcher(getter)
|
|
83
|
+
parent = getter.strip.gsub(/[.][^.]+$/, '')
|
|
84
|
+
|
|
85
|
+
if parent.blank? || !getter.index('.')
|
|
86
|
+
parent = 'self'
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
return parent
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def last_method_name(getter)
|
|
93
|
+
return getter.strip[/[^.]+$/]
|
|
94
|
+
end
|
|
95
|
+
|
|
80
96
|
def add_component(tag_name, attributes, unary)
|
|
81
97
|
component_name = tag_name[1..-1].gsub(':', '/')
|
|
82
98
|
|
|
@@ -93,7 +109,21 @@ class ViewScope
|
|
|
93
109
|
# Multiple bindings
|
|
94
110
|
elsif parts.size == 1 && binding_count == 1
|
|
95
111
|
# A single binding
|
|
96
|
-
|
|
112
|
+
getter = value[1..-2]
|
|
113
|
+
data_hash << "#{name.inspect} => Proc.new { #{getter} }"
|
|
114
|
+
|
|
115
|
+
setter = getter_to_setter(getter)
|
|
116
|
+
data_hash << "#{(name + "=").inspect} => Proc.new { |val| #{setter} }"
|
|
117
|
+
|
|
118
|
+
# Add an _parent fetcher. Useful for things like volt-fields to get the parent model.
|
|
119
|
+
parent = parent_fetcher(getter)
|
|
120
|
+
|
|
121
|
+
# TODO: This adds some overhead, perhaps there is a way to compute this dynamically on the
|
|
122
|
+
# front-end.
|
|
123
|
+
data_hash << "#{(name + "_parent").inspect} => Proc.new { #{parent} }"
|
|
124
|
+
|
|
125
|
+
# Add a _last_method property. This is useful
|
|
126
|
+
data_hash << "#{(name + "_last_method").inspect} => #{last_method_name(getter).inspect}"
|
|
97
127
|
end
|
|
98
128
|
else
|
|
99
129
|
# String
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
source 'https://rubygems.org'
|
|
2
2
|
|
|
3
|
-
gem 'volt', path: '
|
|
4
|
-
|
|
3
|
+
gem 'volt', path: '../../../'
|
|
5
4
|
|
|
6
5
|
# The following gem's are optional for themeing
|
|
7
6
|
|
|
@@ -12,12 +11,10 @@ gem 'volt-bootstrap'
|
|
|
12
11
|
gem 'volt-bootstrap-jumbotron-theme'
|
|
13
12
|
|
|
14
13
|
|
|
15
|
-
gem 'volt-fields', path: '/Users/ryanstout/Sites/volt/apps/volt-fields'
|
|
16
|
-
|
|
17
14
|
# Server for MRI
|
|
18
15
|
platform :mri do
|
|
19
16
|
gem 'thin', '~> 1.6.0'
|
|
20
|
-
gem 'bson_ext'
|
|
17
|
+
gem 'bson_ext', '~> 1.9.0'
|
|
21
18
|
end
|
|
22
19
|
|
|
23
20
|
# Server for jruby
|
|
@@ -25,8 +22,7 @@ platform :jruby do
|
|
|
25
22
|
gem 'jubilee'
|
|
26
23
|
end
|
|
27
24
|
|
|
25
|
+
|
|
28
26
|
#---------------------
|
|
29
27
|
# Needed at the moment
|
|
30
|
-
gem '
|
|
31
|
-
gem 'opal-jquery', :git => 'https://github.com/opal/opal-jquery.git'
|
|
32
|
-
gem 'sockjs', git: 'https://github.com/kacperk/sockjs-ruby.git', require: false, platforms: :mri
|
|
28
|
+
gem 'volt-sockjs', require: false, platforms: :mri
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
# See https://github.com/voltrb/volt#routes for more info on routes
|
|
2
|
+
|
|
3
|
+
get "/bindings/{_route_test}", _action: 'bindings'
|
|
4
|
+
get "/bindings", _action: 'bindings'
|
|
5
|
+
get "/store", _action: 'store'
|
|
6
|
+
|
|
7
|
+
# The main route, this should be last. It will match any params not previously matched.
|
|
8
|
+
get '/', {}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
class MainController < ModelController
|
|
2
2
|
model :page
|
|
3
|
+
|
|
4
|
+
private
|
|
5
|
+
# the main template contains a #template binding that shows another
|
|
6
|
+
# template. This is the path to that template. It may change based
|
|
7
|
+
# on the params._controller and params._action values.
|
|
8
|
+
def main_path
|
|
9
|
+
params._controller.or('main') + "/" + params._action.or('index')
|
|
10
|
+
end
|
|
3
11
|
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<:Title>
|
|
2
|
+
Bindings
|
|
3
|
+
|
|
4
|
+
<:Body>
|
|
5
|
+
<h1>Bindings</h1>
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
<h2>Text</h2>
|
|
9
|
+
<table class="table">
|
|
10
|
+
<tr>
|
|
11
|
+
<td>Page</td>
|
|
12
|
+
<td><input type="text" id="pageName1" value="{page._name}"></td>
|
|
13
|
+
<td><input type="text" id="pageName2" value="{page._name}"></td>
|
|
14
|
+
<td id="pageName3">{page._name}</td>
|
|
15
|
+
</tr>
|
|
16
|
+
<tr>
|
|
17
|
+
<td>Params</td>
|
|
18
|
+
<td><input type="text" id="paramsName1" value="{params._name}"></td>
|
|
19
|
+
<td><input type="text" id="paramsName2" value="{params._name}"></td>
|
|
20
|
+
<td id="paramsName3">{params._name}</td>
|
|
21
|
+
</tr>
|
|
22
|
+
<tr>
|
|
23
|
+
<td>Routes</td>
|
|
24
|
+
<td><input type="text" id="routesName1" value="{params._route_test}"></td>
|
|
25
|
+
<td><input type="text" id="routesName2" value="{params._route_test}"></td>
|
|
26
|
+
<td id="routesName3">{params._route_test}</td>
|
|
27
|
+
</tr>
|
|
28
|
+
</table>
|
|
29
|
+
|
|
30
|
+
<h2>Checkbox</h2>
|
|
31
|
+
|
|
32
|
+
<table class="table">
|
|
33
|
+
<tr>
|
|
34
|
+
<td>Page</td>
|
|
35
|
+
<td><input type="checkbox" id="pageCheck1" checked="{page._check}" /></td>
|
|
36
|
+
<td><input type="checkbox" id="pageCheck2" checked="{page._check}" /></td>
|
|
37
|
+
<td id="pageCheck3">{page._check}</td>
|
|
38
|
+
</tr>
|
|
39
|
+
<tr>
|
|
40
|
+
<td>Params</td>
|
|
41
|
+
<td><input type="checkbox" id="paramsCheck1" checked="{params._check}" /></td>
|
|
42
|
+
<td><input type="checkbox" id="paramsCheck2" checked="{params._check}" /></td>
|
|
43
|
+
<td id="paramsCheck3">{params._check}</td>
|
|
44
|
+
</tr>
|
|
45
|
+
</table>
|
|
46
|
+
|
|
47
|
+
<h2>Radio</h2>
|
|
48
|
+
|
|
49
|
+
<table class="table">
|
|
50
|
+
<tr>
|
|
51
|
+
<td>Page</td>
|
|
52
|
+
<td><input type="radio" id="pageRadio1" checked="{page._radio}" value="one" /></td>
|
|
53
|
+
<td><input type="radio" id="pageRadio2" checked="{page._radio}" value="two" /></td>
|
|
54
|
+
<td id="pageRadio3">{page._radio}</td>
|
|
55
|
+
</tr>
|
|
56
|
+
<tr>
|
|
57
|
+
<td></td>
|
|
58
|
+
<td><input type="radio" checked="{page._radio}" value="one" /></td>
|
|
59
|
+
<td><input type="radio" checked="{page._radio}" value="two" /></td>
|
|
60
|
+
<td></td>
|
|
61
|
+
</tr>
|
|
62
|
+
</table>
|
|
63
|
+
|
|
64
|
+
<h2>Textarea</h2>
|
|
65
|
+
<table class="table">
|
|
66
|
+
<tr>
|
|
67
|
+
<td>Page</td>
|
|
68
|
+
<td><textarea id="textareaName1">{page._textarea_name}</textarea></td>
|
|
69
|
+
<td><textarea id="textareaName2">{page._textarea_name}</textarea></td>
|
|
70
|
+
<td id="textareaName3">{page._textarea_name}</td>
|
|
71
|
+
</tr>
|
|
72
|
+
</table>
|
|
73
|
+
|
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
<:Title>
|
|
2
|
-
|
|
2
|
+
{#template main_path, "title", {controller_group: 'main'}} - KitchenSink
|
|
3
3
|
|
|
4
4
|
<:Body>
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
<div class="container">
|
|
6
|
+
<div class="header">
|
|
7
|
+
<ul class="nav nav-pills pull-right">
|
|
8
|
+
<:nav href="/" text="Home" />
|
|
9
|
+
<:nav href="/bindings" text="Bindings" />
|
|
10
|
+
<:nav href="/store" text="Store" />
|
|
11
|
+
</ul>
|
|
12
|
+
<h3 class="text-muted">Project name</h3>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<:volt:notices />
|
|
16
|
+
|
|
17
|
+
{#template main_path, 'body', {controller_group: 'main'}}
|
|
18
|
+
|
|
19
|
+
<div class="footer">
|
|
20
|
+
<p>© Company 2014</p>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<:Nav>
|
|
26
|
+
<li class="{#if url.path.split('/')[1] == attrs.href.split('/')[1]}active{/}">
|
|
27
|
+
<a href="{attrs.href}">{attrs.text}</a>
|
|
28
|
+
</li>
|
|
29
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
|
-
require 'volt/
|
|
2
|
+
require 'volt/reactive/reactive_accessors'
|
|
3
3
|
|
|
4
4
|
class TestReactiveAccessors
|
|
5
5
|
include ReactiveAccessors
|
|
@@ -8,12 +8,6 @@ class TestReactiveAccessors
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
describe ReactiveAccessors do
|
|
11
|
-
it "should return the same reactive value after each read" do
|
|
12
|
-
inst = TestReactiveAccessors.new
|
|
13
|
-
|
|
14
|
-
expect(inst._name.reactive_manager.object_id).to eq(inst._name.reactive_manager.object_id)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
11
|
it "should assign a reactive value" do
|
|
18
12
|
inst = TestReactiveAccessors.new
|
|
19
13
|
|
|
@@ -24,19 +18,23 @@ describe ReactiveAccessors do
|
|
|
24
18
|
it "should start nil" do
|
|
25
19
|
inst = TestReactiveAccessors.new
|
|
26
20
|
|
|
27
|
-
expect(inst._name
|
|
21
|
+
expect(inst._name).to eq(nil)
|
|
28
22
|
end
|
|
29
23
|
|
|
30
|
-
it
|
|
24
|
+
it 'should trigger changed when assigning a new value' do
|
|
31
25
|
inst = TestReactiveAccessors.new
|
|
26
|
+
values = []
|
|
32
27
|
|
|
33
|
-
inst._name
|
|
34
|
-
rv1_id = inst._name.reactive_manager.object_id
|
|
28
|
+
-> { values << inst._name }.watch!
|
|
35
29
|
|
|
36
|
-
|
|
37
|
-
rv2_id = inst._name.reactive_manager.object_id
|
|
30
|
+
expect(values).to eq([nil])
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
inst._name = 'Ryan'
|
|
33
|
+
Computation.flush!
|
|
34
|
+
expect(values).to eq([nil,'Ryan'])
|
|
41
35
|
|
|
36
|
+
inst._name = 'Stout'
|
|
37
|
+
Computation.flush!
|
|
38
|
+
expect(values).to eq([nil,'Ryan','Stout'])
|
|
39
|
+
end
|
|
42
40
|
end
|