volt 0.7.23 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bfebb6451854a0cf9d1df466a09f9b22df1b3fe
|
4
|
+
data.tar.gz: 355f2f7edd21dccb2fa9a247c4ee0de355dec951
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c4cea6fb3050b58fa0d3bc4c8194ca125f3e6eac42d74b5ea0028396dcd6ee487b3cfe76d9984d69013b348ebd7c9643a5d261339af5fa6c3d55db558b5fb6e
|
7
|
+
data.tar.gz: 810ec65a951a1d902a102215c6f9d6dd6bdeecc3e85732b48ea6b9db920d840e2310e7390853c6ace5f6c5383ed6ab5385b815f8bb655893a4dd43472f24d6ff
|
data/.travis.yml
CHANGED
@@ -6,4 +6,11 @@ rvm:
|
|
6
6
|
- "2.1.3"
|
7
7
|
# - jruby-19mode # JRuby in 1.9 mode
|
8
8
|
# - rbx
|
9
|
-
script: bundle exec rspec
|
9
|
+
script: bundle exec rspec
|
10
|
+
notifications:
|
11
|
+
webhooks:
|
12
|
+
urls:
|
13
|
+
- https://webhooks.gitter.im/e/046f551739ef8cf19b8c
|
14
|
+
on_success: change # options: [always|never|change] default: always
|
15
|
+
on_failure: always # options: [always|never|change] default: always
|
16
|
+
on_start: false # default: false
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# 0.0.8 - Oct 3, 2014
|
2
|
+
|
3
|
+
- Major change: After a bunch of research and effort, we have decided to change the way the reactive core works. Previously, all objects that maybe changed would be wrapped in a ReactiveValue object that could be updated using ```.cur=``` and accessed using ```.cur``` This had many advantages, but resulted in very complex framework code. It also had a few problems, mainly that reactive value's (sometimes) needed to be unwrapped when passed to code that wasn't aware of reactivity. Our goal is transparent reactivity. Taking infuence from meteor.js, we have switched to a simpler reactive model. See the Readme for details of the new reactive system. The new system has a few advantages. Mainly, you can for the most part write code that is reactive and it will just work.
|
4
|
+
- Radio button support has been added, see README.md
|
5
|
+
- Added docs for select box bindings
|
6
|
+
- Previously attributes passed into controls were accessable as instance variables. Due to the way the new reactive system works, to bind data it needs to be fetched through a method or function call. To make this work, attributes passed in as an object. The object can be accessed with ```data```, so if you have a tag like:
|
7
|
+
```<:nav link="/blog" text="Blog" />```
|
8
|
+
|
9
|
+
Within the template or controller you can access link and text as ```data.link``` and ```data.text```
|
10
|
+
|
11
|
+
```html
|
12
|
+
<:Nav>
|
13
|
+
<li><a href="{data.link}">{data.text}</a></li>
|
14
|
+
```
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
class Nav < ModelController
|
18
|
+
def link_url
|
19
|
+
return data.link
|
20
|
+
end
|
21
|
+
end
|
22
|
+
```
|
data/Gemfile
CHANGED
@@ -32,6 +32,14 @@ gem 'volt-sockjs', require: false, platforms: :mri
|
|
32
32
|
# gem 'racc', platforms: :rbx
|
33
33
|
|
34
34
|
group :development do
|
35
|
+
# For testing the kitchen sink app
|
36
|
+
# Twitter bootstrap
|
37
|
+
gem 'volt-bootstrap'
|
38
|
+
|
39
|
+
# Simple theme for bootstrap, remove to theme yourself.
|
40
|
+
gem 'volt-bootstrap-jumbotron-theme'
|
41
|
+
|
42
|
+
|
35
43
|
# gem 'guard', '2.0.1' # bug in current guard
|
36
44
|
# gem 'guard-rspec'
|
37
45
|
# gem 'opal-rspec', '0.3.0.beta2'#, git: 'https://github.com/adambeynon/opal-rspec.git'
|
data/Guardfile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# A sample Guardfile
|
2
2
|
# More info at https://github.com/guard/guard#readme
|
3
3
|
|
4
|
-
guard 'rspec' do
|
4
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
5
5
|
watch(%r{^spec/.+_spec\.rb$})
|
6
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec
|
6
|
+
watch(%r{^lib/volt/(.+)\.rb$}) { |m| puts "RUN AGAIN" ; "spec/#{m[1]}_spec.rb" }
|
7
7
|
watch('spec/spec_helper.rb') { "spec" }
|
8
8
|
end
|
9
9
|
|
data/Readme.md
CHANGED
@@ -8,20 +8,20 @@
|
|
8
8
|
|
9
9
|
# Volt
|
10
10
|
|
11
|
-
Volt is a Ruby web framework where your ruby code runs on both the server and the client (via [opal](https://github.com/opal/opal)). The DOM automatically
|
11
|
+
Volt is a Ruby web framework where your ruby code runs on both the server and the client (via [opal](https://github.com/opal/opal)). The DOM automatically updates as the user interacts with the page. Page state can be stored in the URL. If the user hits a URL directly, the HTML will first be rendered on the server for faster load times and easier indexing by search engines.
|
12
12
|
|
13
13
|
Instead of syncing data between the client and server via HTTP, Volt uses a persistent connection between the client and server. When data is updated on one client, it is updated in the database and any other listening clients (with almost no setup code needed).
|
14
14
|
|
15
|
-
Pages HTML is written in a handlebars-like template language. Volt uses data flow/reactive programming to automatically and intelligently propagate changes to the DOM (or
|
15
|
+
Pages HTML is written in a handlebars-like template language. Volt uses data flow/reactive programming to automatically and intelligently propagate changes to the DOM (or any other code wanting to know when a value updates). When something in the DOM changes, Volt intelligently updates only the nodes that need to be changed.
|
16
16
|
|
17
17
|
See some demo videos here:
|
18
|
+
** Note: These videos are outdated, new videos coming tomorrow.
|
18
19
|
- [Volt Todos Example](https://www.youtube.com/watch?v=6ZIvs0oKnYs)
|
19
20
|
- [Build a Blog with Volt](https://www.youtube.com/watch?v=c478sMlhx1o)
|
20
21
|
- [Reactive Values in Volt](https://www.youtube.com/watch?v=yZIQ-2irY-Q)
|
21
22
|
|
22
23
|
Check out demo apps:
|
23
24
|
- https://github.com/voltrb/todos3
|
24
|
-
- https://github.com/voltrb/blog
|
25
25
|
- https://github.com/voltrb/contactsdemo
|
26
26
|
|
27
27
|
|
@@ -44,10 +44,8 @@ Volt has the following goals:
|
|
44
44
|
|
45
45
|
Many of the core Volt features are implemented. We still have a bit to go before 1.0, most of it involving models.
|
46
46
|
|
47
|
-
1.
|
48
|
-
2.
|
49
|
-
3. Full managed render loop (for fast rendering)
|
50
|
-
4. Fix N+1 issue with some reactive values (I know how to fix it, just haven't gotten around to doing it)
|
47
|
+
1. Model read/write permissions
|
48
|
+
2. User accounts, user collection, signup/login templates
|
51
49
|
|
52
50
|
# VOLT guide
|
53
51
|
|
@@ -73,8 +71,8 @@ You can access the Volt console with:
|
|
73
71
|
|
74
72
|
1. [Getting Help](#getting-help)
|
75
73
|
2. [Rendering](#rendering)
|
76
|
-
1. [
|
77
|
-
|
74
|
+
1. [States and Computations](#states-and-computations)
|
75
|
+
1. [Computations](#states-and-computations)
|
78
76
|
3. [Views](#views)
|
79
77
|
1. [Bindings](#bindings)
|
80
78
|
1. [Content Binding](#content-binding)
|
@@ -84,9 +82,8 @@ You can access the Volt console with:
|
|
84
82
|
5. [Escaping](#escaping)
|
85
83
|
4. [Models](#models)
|
86
84
|
1. [Provided Collections](#provided-collections)
|
87
|
-
2. [
|
88
|
-
3. [Model
|
89
|
-
4. [Automatic Model Conversion](#automatic-model-conversion)
|
85
|
+
2. [ArrayModel Events](#arraymodel-events)
|
86
|
+
3. [Automatic Model Conversion](#automatic-model-conversion)
|
90
87
|
5. [Controllers](#controllers)
|
91
88
|
6. [Tasks](#tasks)
|
92
89
|
7. [Components](#components)
|
@@ -100,7 +97,8 @@ You can access the Volt console with:
|
|
100
97
|
9. [Routes](#routes)
|
101
98
|
1. [Routes file](#routes-file)
|
102
99
|
10. [Testing](#testing)
|
103
|
-
|
100
|
+
11. [Volt Helpers](#volt-helpers)
|
101
|
+
1. [Logging](#logging)
|
104
102
|
|
105
103
|
# Getting Help
|
106
104
|
|
@@ -109,7 +107,7 @@ Volt is still a work in progress, but early feedback is appreciated. Use the fo
|
|
109
107
|
- **If you need help**: post on [stackoverflow.com](http://www.stackoverflow.com). Be sure to tag your question with `voltrb`.
|
110
108
|
- **If you found a bug**: post on [github issues](https://github.com/voltrb/volt/issues)
|
111
109
|
- **If you have an idea or need a feature**: post on [github issues](https://github.com/voltrb/volt/issues)
|
112
|
-
- **If you want to discuss Volt**:
|
110
|
+
- **If you want to discuss Volt**: [chat on gitter](https://gitter.im/voltrb/volt), someone from the volt team is usually online and happy to help with anything.
|
113
111
|
|
114
112
|
|
115
113
|
# Rendering
|
@@ -119,136 +117,75 @@ When a user interacts with a web page, typically we want to do two things:
|
|
119
117
|
1. Change application state
|
120
118
|
2. Update the DOM
|
121
119
|
|
122
|
-
For example when a user clicks to add a new todo item to a todo list, we might create
|
123
|
-
|
124
|
-
The idea of "reactive programming" has been used to simplify maintaining the DOM. The idea is instead of having event handlers that manage a model (or JavaScript object) and manage the DOM, we have event handlers that manage reactive data models. We describe our DOM layer in a declarative way so that it automatically knows how to render our data models.
|
125
|
-
|
126
|
-
## Reactive Values
|
127
|
-
|
128
|
-
To build bindings, Volt provides the ReactiveValue class. This wraps any object in a reactive interface. To create a ReactiveValue, simply pass the object you want to wrap as the first argument to new.
|
129
|
-
|
130
|
-
```ruby
|
131
|
-
a = ReactiveValue.new("my object")
|
132
|
-
# => @"my object"
|
133
|
-
```
|
134
|
-
|
135
|
-
When `#inspect` is called on a ReactiveValue (like in the console), an '@' is placed in front of the value's inspect string, so you know it's reactive.
|
136
|
-
|
137
|
-
When you call a method on a ReactiveValue, you get back a new reactive value that depends on the previous one. It remembers how it was created and you can call `#cur` on it any time to get its current value, which will be computed based off of the first reactive value. (Keep in mind below that + is a method call, the same as `a.+(b)` in ruby.)
|
120
|
+
For example when a user clicks to add a new todo item to a todo list, we might create an object to represent the todo item, then add an item to the list's DOM. A lot of work needs to be done to make sure that the object and the DOM always stay in sync.
|
138
121
|
|
139
|
-
|
140
|
-
a = ReactiveValue.new(1)
|
141
|
-
a.reactive?
|
142
|
-
# => true
|
122
|
+
The idea of "reactive programming" can be used to simplify maintaining the DOM. Instead of having event handlers that manage a model and manage the DOM, we have event handlers that manage reactive data models. We describe our DOM layer in a declarative way so that it automatically knows how to render our data models.
|
143
123
|
|
144
|
-
|
145
|
-
# => 1
|
124
|
+
## State and Computations
|
146
125
|
|
147
|
-
|
148
|
-
b.reactive?
|
149
|
-
# => true
|
126
|
+
Web applications center around maintaining state. Many events can trigger changes to a state. Page interaction like entering text into form elements, clicking a button, links, scrolling, etc.. can all change the state of the app. In the past, each page interaction event would manually change any state stored on a page.
|
150
127
|
|
151
|
-
|
152
|
-
# => 6
|
128
|
+
To simplify managing application state, all application state is kept in models that can optionally be persisted in different locations. By centralizing the application state, we reduce the amount of complex code needed to update a page. We can then build our page's html declaratively. The relationship to the page's models' are bound using function and method calls.
|
153
129
|
|
154
|
-
|
155
|
-
b.cur
|
156
|
-
# => 7
|
157
|
-
```
|
130
|
+
We want our DOM to automatically update when our model data changes. To make this happen, Volt lets you "watch" any method/proc call and have it get called again when data accessed by the method/proc call changes.
|
158
131
|
|
159
|
-
|
132
|
+
### Computations
|
160
133
|
|
161
|
-
|
134
|
+
Lets take a look at this in practice. We'll use the ```page``` collection as an example. (You'll see more on collections later)
|
162
135
|
|
136
|
+
First, we setup a computation watch. Computations are built by calling .watch! on a Proc. Here we'll use the ruby 1.9 proc shorthand syntax ```-> { ... }``` It will run once, then run again each time the data in page._name changes.
|
163
137
|
```ruby
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
138
|
+
page._name = 'Ryan'
|
139
|
+
-> { puts page._name }.watch!
|
140
|
+
# => Ryan
|
141
|
+
page._name = 'Jimmy'
|
142
|
+
# => Jimmy
|
168
143
|
```
|
169
144
|
|
170
|
-
|
145
|
+
Each time page._name is assigned to a new value, the computation is run again. A re-run of the computation will be triggered when any data accessed in the previous run is changed. This lets us access data through methods and still have watches re-triggered.
|
171
146
|
|
172
147
|
```ruby
|
173
|
-
|
174
|
-
|
175
|
-
b.on('changed') { puts "B changed" }
|
148
|
+
page._first = 'Ryan'
|
149
|
+
page._last = 'Stout'
|
176
150
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
This event flow lets us know when an object has changed, so we can update everything that depended on that object.
|
182
|
-
|
183
|
-
Lastly, we can also pass in other reactive values as arguments to methods on a reactive value. The dependencies will be tracked for both and events will propagate down from both. (Also, note that calling `#cur=` to update the current value triggers a "changed" event.)
|
184
|
-
|
185
|
-
```ruby
|
186
|
-
a = ReactiveValue.new(1)
|
187
|
-
b = ReactiveValue.new(2)
|
188
|
-
c = a + b
|
151
|
+
def lookup_name
|
152
|
+
return "#{page._first} #{page._last}"
|
153
|
+
end
|
189
154
|
|
190
|
-
|
191
|
-
|
192
|
-
|
155
|
+
-> do
|
156
|
+
puts lookup_name
|
157
|
+
end.watch!
|
158
|
+
# => Ryan Stout
|
193
159
|
|
194
|
-
|
195
|
-
# =>
|
196
|
-
# => C changed
|
160
|
+
page._first = 'Jimmy'
|
161
|
+
# => Jimmy Stout
|
197
162
|
|
198
|
-
|
199
|
-
# =>
|
200
|
-
# => C changed
|
163
|
+
page._last = 'Jones'
|
164
|
+
# => Jimmy Jones
|
201
165
|
```
|
202
166
|
|
203
|
-
|
204
|
-
|
205
|
-
There are a few simple things to keep in mind with ReactiveValues. In order to make them mostly compatible with other Ruby objects, two methods do not return another ReactiveValue.
|
206
|
-
|
207
|
-
to_s and inspect
|
208
|
-
|
209
|
-
If you want these to be used reactively, see the section on [with](#with).
|
210
|
-
|
211
|
-
Also, due to a small limitation in ruby, ReactiveValues always are truthy. See the [truthy checks](#truthy-checks-true-false-or-and-and) section on how to check for truth.
|
212
|
-
|
213
|
-
When passing something that may contain reactive values to a JS function, you can call ```#deep_cur``` on any object to get back a copy that will have all reactive values turned into their current value.
|
214
|
-
|
215
|
-
### Current Status
|
216
|
-
|
217
|
-
NOTE: currently ReactiveValues are not complete. At the moment, they do not handle methods that are passed blocks (or procs, lambdas). This is planned, but not complete. At the moment you can use [with](#with) to accomplish similar things.
|
218
|
-
|
219
|
-
### Truthy Checks: .true?, .false?, .or, and .and
|
220
|
-
|
221
|
-
Because a method on a reactive value always returns another reactive value, and because only nil and false are false in ruby, we need a way to check if a ReactiveValue is truthy in our code. The easiest way to do this is by calling .true? on it. It will return a non-wrapped boolean. .nil? and .false? do as you would expect.
|
222
|
-
|
223
|
-
One common place we use a truthy check is in setting up default values with || (logical or) Volt provides a convenient method that does the same thing `#or`, but works with ReactiveValues.
|
224
|
-
|
225
|
-
Instead of
|
167
|
+
When you call .watch! the return value is a Computation object. In the event you no longer want to receive updates, you can call .stop on the computation.
|
226
168
|
|
227
169
|
```ruby
|
228
|
-
|
229
|
-
```
|
170
|
+
page._name = 'Ryan'
|
230
171
|
|
231
|
-
|
172
|
+
comp = -> { puts page._name }.watch!
|
173
|
+
# => Ryan
|
232
174
|
|
233
|
-
|
234
|
-
|
235
|
-
```
|
175
|
+
page._name = 'Jimmy'
|
176
|
+
# => Jimmy
|
236
177
|
|
237
|
-
|
178
|
+
comp.stop
|
238
179
|
|
180
|
+
page._name = 'Jo'
|
181
|
+
# (nothing)
|
182
|
+
```
|
239
183
|
|
240
|
-
|
184
|
+
## Dependencies
|
241
185
|
|
242
|
-
|
186
|
+
TODO: Explain Dependencies
|
243
187
|
|
244
|
-
|
245
|
-
|
246
|
-
```ruby
|
247
|
-
a = ReactiveValue.new(5)
|
248
|
-
b = a.with {|v| v + 10 }
|
249
|
-
b.cur
|
250
|
-
# => 15
|
251
|
-
```
|
188
|
+
As a Volt user, you rarely need to use Comptuations and Dependencies directly. Instead you usually just interact with models and bindings. Computations are used under the hood, and having a full understanding of what's going on is useful, but not required.
|
252
189
|
|
253
190
|
# Views
|
254
191
|
|
@@ -354,7 +291,28 @@ In the example above, if _name changes, the field will update, and if the field
|
|
354
291
|
|
355
292
|
If the value of a checked attribute is true, the checkbox will be shown checked. If it's checked or unchecked, the value will be updated to true or false.
|
356
293
|
|
357
|
-
|
294
|
+
Radio buttons bind to a checked state as well, except instead of setting the value to true or false, they set it to a supplied field value.
|
295
|
+
|
296
|
+
```html
|
297
|
+
<input type="radio" checked="{_radio}" value="one" />
|
298
|
+
<input type="radio" checked="{_radio}" value="two" />
|
299
|
+
```
|
300
|
+
|
301
|
+
When a radio button is checked, whatever checked is bound to is set to the field's value. When the checked binding value is changed, any radio buttons where the binding's value matches the fields value are checked. NOTE: This seems to be the most useful behaviour for radio buttons.
|
302
|
+
|
303
|
+
Select boxes can be bound to a value (while not technically a property, this is another convient behavior we add).
|
304
|
+
|
305
|
+
```html
|
306
|
+
<select value="{_rating}">
|
307
|
+
<option value="1">*</option>
|
308
|
+
<option value="2">**</option>
|
309
|
+
<option value="3">***</option>
|
310
|
+
<option value="4">****</option>
|
311
|
+
<option value="5">*****</option>
|
312
|
+
</select>
|
313
|
+
```
|
314
|
+
|
315
|
+
When the selected option of the select above changes, ```_rating``` is changed to match. When ```_rating``` is changed, the selected value is changed to the first option with a matching value. If no matching values are found, the select box is unselected.
|
358
316
|
|
359
317
|
If you have a controller at app/home/controller/index_controller.rb, and a view at app/home/views/index/index.html, all methods called are called on the controller.
|
360
318
|
|
@@ -406,36 +364,65 @@ You can also append to a model if it's not defined yet. In Volt models, plural
|
|
406
364
|
|
407
365
|
ArrayModels can be appended to and accessed just like regular arrays.
|
408
366
|
|
367
|
+
|
368
|
+
### Nil Models
|
369
|
+
|
370
|
+
As a convience, calling something like ```page._info``` returns what's called a NilModel (assuming it isn't already initialized). NilModels are place holders for future possible Models. NilModels allow us to bind deeply nested values without initializing any intermediate values.
|
371
|
+
|
372
|
+
```ruby
|
373
|
+
page._info
|
374
|
+
# => <Model:70260787225140 nil>
|
375
|
+
|
376
|
+
page._info._name
|
377
|
+
# => <Model:70260795424200 nil>
|
378
|
+
|
379
|
+
page._info._name = 'Ryan'
|
380
|
+
# => <Model:70161625994820 {:_info=><Model:70161633901800 {:_name=>"Ryan"}>}>
|
381
|
+
```
|
382
|
+
|
383
|
+
One gotchya with NilModels is that they are a truthy value (since only nil and false are falsy in ruby). To make things easier, calling ```.nil?``` on a NilModel will return true.
|
384
|
+
|
385
|
+
One common place we use a truthy check is in setting up default values with || (logical or) Volt provides a convenient method that does the same thing `#or`, but works with NilModels.
|
386
|
+
|
387
|
+
Instead of
|
388
|
+
|
389
|
+
```ruby
|
390
|
+
a || b
|
391
|
+
```
|
392
|
+
|
393
|
+
Simply use:
|
394
|
+
|
395
|
+
```ruby
|
396
|
+
a.or(b)
|
397
|
+
```
|
398
|
+
|
399
|
+
`#and` works the same way as &&. #and and #or let you easily deal with default values involving NilModels.
|
400
|
+
|
401
|
+
-- TODO: Document .true? / .false?
|
402
|
+
|
403
|
+
|
409
404
|
## Provided Collections
|
410
405
|
|
411
406
|
Above, I mentioned that Volt comes with many default collection models accessible from a controller. Each stores in a different location.
|
412
407
|
|
413
|
-
| Name
|
414
|
-
|
415
|
-
| page
|
416
|
-
| store
|
417
|
-
|
|
418
|
-
| params
|
419
|
-
| flash
|
420
|
-
| controller| a model for the current controller |
|
408
|
+
| Name | Storage Location |
|
409
|
+
|-------------|---------------------------------------------------------------------------|
|
410
|
+
| page | page provides a temporary store that only lasts for the life of the page. |
|
411
|
+
| store | store syncs the data to the backend database and provides query methods. |
|
412
|
+
| local_store | values will be stored in the local_store |
|
413
|
+
| params | values will be stored in the params and URL. Routes can be setup to change how params are shown in the URL. (See routes for more info) |
|
414
|
+
| flash | any strings assigned will be shown at the top of the page and cleared as the user navigates between pages. |
|
415
|
+
| controller | a model for the current controller |
|
421
416
|
|
422
417
|
**more storage locations are planned**
|
423
418
|
|
424
|
-
##
|
425
|
-
|
426
|
-
Because all models provided by Volt are wrapped in a ReactiveValue, you can register listeners on them and be updated when values change. You can also call methods on their values and get updates when the sources change. Bindings also setup listeners. Models should be the main place you store all data in Volt. While you can use ReactiveValues manually, most of the time you will want to just use something like the controller model.
|
427
|
-
|
428
|
-
## Model Events
|
419
|
+
## ArrayModel Events
|
429
420
|
|
430
|
-
Models trigger events when their data is updated. Currently, models emit
|
421
|
+
Models trigger events when their data is updated. Currently, models emit two events: added and removed. For example:
|
431
422
|
|
432
423
|
```ruby
|
433
424
|
model = Model.new
|
434
425
|
|
435
|
-
model._name.on('changed') { puts 'name changed' }
|
436
|
-
model._name = 'Ryan'
|
437
|
-
# => name changed
|
438
|
-
|
439
426
|
model._items.on('added') { puts 'item added' }
|
440
427
|
model._items << 1
|
441
428
|
# => item added
|
@@ -695,7 +682,6 @@ or
|
|
695
682
|
|
696
683
|
To find the control's views and optional controller, Volt will search the following (in order):
|
697
684
|
|
698
|
-
|
699
685
|
| Section | View File | View Folder | Component |
|
700
686
|
|-----------|--------------|----------------|-------------|
|
701
687
|
| :{name} | | | |
|
@@ -832,6 +818,23 @@ To run Capybara tests, you need to specify a driver. The following drivers are
|
|
832
818
|
|
833
819
|
Chrome is not supported due to [this issue](https://code.google.com/p/chromedriver/issues/detail?id=887#makechanges) with ChromeDriver. Feel free to go [here](https://code.google.com/p/chromedriver/issues/detail?id=887#makechanges) and pester the chromedriver team to fix it.
|
834
820
|
|
821
|
+
# Volt Helpers
|
822
|
+
|
823
|
+
## Logging
|
824
|
+
|
825
|
+
Volt provides a helper for logging. Calling ```Volt.logger``` returns an instance of the ruby logger. See [here](http://www.ruby-doc.org/stdlib-2.1.3/libdoc/logger/rdoc/Logger.html) for more.
|
826
|
+
|
827
|
+
```ruby
|
828
|
+
Volt.logger.info("Some info...")
|
829
|
+
```
|
830
|
+
|
831
|
+
You can change the logger with:
|
832
|
+
|
833
|
+
```ruby
|
834
|
+
Volt.logger = Logger.new
|
835
|
+
```
|
836
|
+
|
837
|
+
|
835
838
|
## Accessing DOM section in a controller
|
836
839
|
|
837
840
|
TODO
|