volt 0.7.23 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +8 -1
  3. data/CHANGELOG.md +22 -0
  4. data/Gemfile +8 -0
  5. data/Guardfile +2 -2
  6. data/Readme.md +139 -136
  7. data/VERSION +1 -1
  8. data/app/volt/assets/js/setImmediate.js +175 -0
  9. data/app/volt/tasks/live_query/data_store.rb +0 -2
  10. data/app/volt/tasks/live_query/live_query.rb +4 -4
  11. data/docs/GETTING_STARTED.md +24 -3
  12. data/docs/WHY.md +1 -22
  13. data/lib/volt.rb +20 -1
  14. data/lib/volt/console.rb +20 -0
  15. data/lib/volt/controllers/model_controller.rb +25 -11
  16. data/lib/volt/extra_core/object.rb +2 -14
  17. data/lib/volt/extra_core/string.rb +4 -0
  18. data/lib/volt/models.rb +0 -1
  19. data/lib/volt/models/array_model.rb +8 -16
  20. data/lib/volt/models/cursor.rb +1 -1
  21. data/lib/volt/models/model.rb +40 -60
  22. data/lib/volt/models/model_hash_behaviour.rb +10 -24
  23. data/lib/volt/models/model_helpers.rb +2 -2
  24. data/lib/volt/models/model_state.rb +1 -1
  25. data/lib/volt/models/model_wrapper.rb +4 -4
  26. data/lib/volt/models/persistors/array_store.rb +44 -28
  27. data/lib/volt/models/persistors/base.rb +1 -1
  28. data/lib/volt/models/persistors/model_store.rb +1 -1
  29. data/lib/volt/models/persistors/params.rb +5 -1
  30. data/lib/volt/models/persistors/query/query_listener.rb +2 -0
  31. data/lib/volt/models/persistors/store.rb +3 -2
  32. data/lib/volt/models/persistors/store_state.rb +7 -2
  33. data/lib/volt/models/url.rb +35 -29
  34. data/lib/volt/models/validations.rb +7 -17
  35. data/lib/volt/page/bindings/attribute_binding.rb +57 -39
  36. data/lib/volt/page/bindings/base_binding.rb +0 -14
  37. data/lib/volt/page/bindings/content_binding.rb +15 -18
  38. data/lib/volt/page/bindings/each_binding.rb +67 -34
  39. data/lib/volt/page/bindings/if_binding.rb +15 -12
  40. data/lib/volt/page/bindings/template_binding.rb +77 -59
  41. data/lib/volt/page/bindings/template_binding/grouped_controllers.rb +19 -4
  42. data/lib/volt/page/channel.rb +22 -38
  43. data/lib/volt/page/channel_stub.rb +3 -6
  44. data/lib/volt/page/page.rb +24 -26
  45. data/lib/volt/page/string_template_renderer.rb +46 -0
  46. data/lib/volt/page/sub_context.rb +7 -1
  47. data/lib/volt/page/targets/binding_document/component_node.rb +11 -9
  48. data/lib/volt/page/tasks.rb +3 -2
  49. data/lib/volt/page/url_tracker.rb +4 -3
  50. data/lib/volt/reactive/computation.rb +131 -0
  51. data/lib/volt/reactive/dependency.rb +71 -0
  52. data/lib/volt/reactive/eventable.rb +82 -0
  53. data/lib/volt/reactive/hash_dependency.rb +36 -0
  54. data/lib/volt/{controllers → reactive}/reactive_accessors.rb +8 -11
  55. data/lib/volt/reactive/reactive_array.rb +100 -193
  56. data/lib/volt/reactive/reactive_hash.rb +49 -0
  57. data/lib/volt/server/html_parser/attribute_scope.rb +24 -4
  58. data/lib/volt/server/html_parser/if_view_scope.rb +15 -15
  59. data/lib/volt/server/html_parser/view_scope.rb +31 -1
  60. data/spec/apps/kitchen_sink/Gemfile +4 -8
  61. data/spec/apps/kitchen_sink/app/main/config/dependencies.rb +8 -0
  62. data/spec/apps/kitchen_sink/app/main/config/routes.rb +8 -1
  63. data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +8 -0
  64. data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +73 -0
  65. data/spec/apps/kitchen_sink/app/main/views/main/index.html +6 -1
  66. data/spec/apps/kitchen_sink/app/main/views/main/main.html +26 -6
  67. data/spec/apps/kitchen_sink/app/main/views/main/store.html +6 -0
  68. data/spec/controllers/reactive_accessors_spec.rb +13 -15
  69. data/spec/integration/bindings_spec.rb +159 -0
  70. data/spec/integration/templates_spec.rb +15 -0
  71. data/spec/models/model_spec.rb +130 -228
  72. data/spec/reactive/computation_spec.rb +63 -0
  73. data/spec/reactive/dependency_spec.rb +5 -0
  74. data/spec/reactive/eventable_spec.rb +48 -0
  75. data/spec/reactive/reactive_array_spec.rb +97 -0
  76. data/spec/router/routes_spec.rb +26 -27
  77. data/spec/server/html_parser/view_parser_spec.rb +3 -21
  78. data/spec/server/rack/asset_files_spec.rb +1 -1
  79. data/templates/project/app/main/views/main/main.html +2 -2
  80. metadata +29 -41
  81. data/lib/volt/extra_core/time.rb +0 -16
  82. data/lib/volt/page/draw_cycle.rb +0 -31
  83. data/lib/volt/page/memory_test.rb +0 -26
  84. data/lib/volt/page/reactive_template.rb +0 -32
  85. data/lib/volt/reactive/array_extensions.rb +0 -12
  86. data/lib/volt/reactive/destructive_methods.rb +0 -19
  87. data/lib/volt/reactive/event_chain.rb +0 -125
  88. data/lib/volt/reactive/events.rb +0 -216
  89. data/lib/volt/reactive/object_tracking.rb +0 -14
  90. data/lib/volt/reactive/reactive_block.rb +0 -88
  91. data/lib/volt/reactive/reactive_generator.rb +0 -44
  92. data/lib/volt/reactive/reactive_tags.rb +0 -71
  93. data/lib/volt/reactive/reactive_value.rb +0 -427
  94. data/lib/volt/reactive/string_extensions.rb +0 -31
  95. data/spec/integration/test_integration_spec.rb +0 -14
  96. data/spec/models/event_chain_spec.rb +0 -150
  97. data/spec/models/model_buffers_spec.rb +0 -9
  98. data/spec/models/old_model_spec.rb +0 -67
  99. data/spec/models/reactive_array_spec.rb +0 -364
  100. data/spec/models/reactive_block_spec.rb +0 -13
  101. data/spec/models/reactive_call_times_spec.rb +0 -28
  102. data/spec/models/reactive_generator_spec.rb +0 -58
  103. data/spec/models/reactive_tags_spec.rb +0 -35
  104. data/spec/models/reactive_value_spec.rb +0 -370
  105. data/spec/models/store_spec.rb +0 -16
  106. data/spec/models/string_extensions_spec.rb +0 -57
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d7bb8c103737c0830c53f7d6fea45e1881fe6f98
4
- data.tar.gz: 15e470a4a5617ab6905f447bf59926354b9ab2d1
3
+ metadata.gz: 9bfebb6451854a0cf9d1df466a09f9b22df1b3fe
4
+ data.tar.gz: 355f2f7edd21dccb2fa9a247c4ee0de355dec951
5
5
  SHA512:
6
- metadata.gz: 78a090d11f527006c79ee66a851e18106193d730d2d4cfaaaa1856737c198f1e27a73ea38fc540b6b1c3e91239fce6fc6eb60dab3bb66e61277f91e82d3cbde4
7
- data.tar.gz: 6e9eda4f1e09a74af9b05983dac7babbf4603f6387f57d18545541f23eeb6195eee79ebc1a05f7c736022988ac2422a93d9a6209067c3ad17c7e77fb16d727dc
6
+ metadata.gz: 2c4cea6fb3050b58fa0d3bc4c8194ca125f3e6eac42d74b5ea0028396dcd6ee487b3cfe76d9984d69013b348ebd7c9643a5d261339af5fa6c3d55db558b5fb6e
7
+ data.tar.gz: 810ec65a951a1d902a102215c6f9d6dd6bdeecc3e85732b48ea6b9db920d840e2310e7390853c6ace5f6c5383ed6ab5385b815f8bb655893a4dd43472f24d6ff
@@ -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
@@ -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/lib/#{m[1]}_spec.rb" }
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 update 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.
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 anything 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.
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. Reactive model queries
48
- 2. Reactive Enumerators with Blocks (.map .count, etc…)
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. [Reactive Values](#reactive-values)
77
- 1. [ReactiveValue Gotchas](#reactivevalue-gotchas)
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. [Reactive Models](#reactive-models)
88
- 3. [Model Events](#model-events)
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**: use #voltrb on freenode.
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 a JavaScript 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 JavaScript object and the DOM always stay in sync.
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
- ```ruby
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
- a.cur
145
- # => 1
124
+ ## State and Computations
146
125
 
147
- b = a + 5
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
- b.cur
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
- a.cur = 2
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
- This provides the backbone for reactive programming. We setup computation/flow graphs instead of doing an actual calculation. Calling `#cur` (or `#inspect`, `#to_s`, etc..) runs the computation and returns the current value at that time, based on all of its dependencies.
132
+ ### Computations
160
133
 
161
- ReactiveValues also let you setup listeners and trigger events:
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
- a = ReactiveValue.new(0)
165
- a.on('changed') { puts "A changed" }
166
- a.trigger!('changed')
167
- # => A Changed
138
+ page._name = 'Ryan'
139
+ -> { puts page._name }.watch!
140
+ # => Ryan
141
+ page._name = 'Jimmy'
142
+ # => Jimmy
168
143
  ```
169
144
 
170
- These events propagate to any reactive values created off of a reactive value:
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
- a = ReactiveValue.new(1)
174
- b = a + 5
175
- b.on('changed') { puts "B changed" }
148
+ page._first = 'Ryan'
149
+ page._last = 'Stout'
176
150
 
177
- a.trigger!('changed')
178
- # => B changed
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
- a.on('changed') { puts "A changed" }
191
- b.on('changed') { puts "B changed" }
192
- c.on('changed') { puts "C changed" }
155
+ -> do
156
+ puts lookup_name
157
+ end.watch!
158
+ # => Ryan Stout
193
159
 
194
- a.cur = 3
195
- # => A changed
196
- # => C changed
160
+ page._first = 'Jimmy'
161
+ # => Jimmy Stout
197
162
 
198
- b.cur = 5
199
- # => B changed
200
- # => C changed
163
+ page._last = 'Jones'
164
+ # => Jimmy Jones
201
165
  ```
202
166
 
203
- ### ReactiveValue Gotchas
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
- a || b
229
- ```
170
+ page._name = 'Ryan'
230
171
 
231
- Simply use:
172
+ comp = -> { puts page._name }.watch!
173
+ # => Ryan
232
174
 
233
- ```ruby
234
- a.or(b)
235
- ```
175
+ page._name = 'Jimmy'
176
+ # => Jimmy
236
177
 
237
- `#and` works the same way as &&. #and and #or let you maintain the reactivity all of the way through.
178
+ comp.stop
238
179
 
180
+ page._name = 'Jo'
181
+ # (nothing)
182
+ ```
239
183
 
240
- ### With
184
+ ## Dependencies
241
185
 
242
- Normally when you want to have a value that depends on another value, but transforms it somehow, you simply call your transform method on the ReactiveValue. However sometimes the transform is not directly on the ReactiveValues object.
186
+ TODO: Explain Dependencies
243
187
 
244
- You can call `#with` on any ReactiveValue. `#with` will return a new ReactiveValue that depends on the current ReactiveValue. `#with` takes a block, the first argument to the block will be the cur value of the ReactiveValue you called `#with` on. Any additional arguments to `#with` will be passed in after the first one. If you pass another ReactiveValue as an argument to `#with`, the returned ReactiveValue will depend on the argument ReactiveValue as well, and the block will receive the arguments cur value.
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
- -- TODO: select boxes
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 | Storage Location |
414
- |-----------|---------------------------------------------------------------------------|
415
- | page | page provides a temporary store that only lasts for the life of the page. |
416
- | store | store syncs the data to the backend database and provides query methods. |
417
- | session | values will be stored in a session cookie. |
418
- | 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) |
419
- | flash | any strings assigned will be shown at the top of the page and cleared as the user navigates between pages. |
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
- ## Reactive Models
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 three events: changed, added, and removed. For example:
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