volt 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3c7f9c10d1c4c9b36bbf686d224d63b7efac606d
4
- data.tar.gz: 3d5734b9bf49bd4bc385442fcafe8fa52a083d6c
3
+ metadata.gz: cc39b7688dcb264420fc550e644030913c5c3a02
4
+ data.tar.gz: 1cc906e44c38dbb1cb76839f128c484107ed11a0
5
5
  SHA512:
6
- metadata.gz: ea67b035043177a2f63d14906b25a9b71e12f6bb2737b471c749947971bc170680d83d61df1a20c7a9b13a009d1bb43c3e5610a71374d79a763c7af7158431a1
7
- data.tar.gz: 9aed66c68f300dc644f38ff84802152f3e2c4cd37780306c2a142247b6d6d71d70a89c49b307117e07b04e89db05165d1f1c86ed7472f28218d80a0078f76608
6
+ metadata.gz: 336d0323272ede308bce021ef3b790271b4c87734697d3344872b566de11a817fb7ae00c3930e51725d3b2b3d98fe302b274f3404005534f229fa8f6b34b2fcd
7
+ data.tar.gz: 62e5f58fb0d95740b833aa2265b556e7e585ec9c8b79603864dbec3c8f1a4dd2b05864ca150c5c38b649985128c9e19980715535ab4438fa383e842903b410ea
@@ -1,3 +1,17 @@
1
+ # 0.8.6 - Oct 5, 2014
2
+
3
+ - Major changes to the templating system (to address common concerns and make things simpler).
4
+ 1. All binding now takes place between {{ and }} instead of { and } (double stash instead of single stash) Escaping is still with a tripple stash {{{ escap{{ed}} }}} => escap{{ed}}
5
+ 2. Bindings can now be (almost) any ruby code. No more #'s at the beginning. Blocks are now closed with {{ end }}
6
+ If's are now: {{ if _something }} ... {{ elsif _other }} .. {{ else }} .. {{ end }}
7
+ Each's are now: {{ _items.each do |item| }} ... {{ end }}
8
+ Template bindings are now: {{ template "path" }} (along with other options)
9
+
10
+ Each should use do notation not brackets. Also, .each is not actually called, the binding is parsed and converted into a EachBinding. Other Eneumerable methods do not work at this time, only each. (more coming soon)
11
+ 3. Bindings in routes now use double stashes as well get '/products/{{ _name }}/info'
12
+ 4. To help clean things up, we reccomend spaces between {{ and }}
13
+
14
+
1
15
  # 0.8.4 - Oct 4, 2014
2
16
 
3
17
  - Added configuration for databases.
data/Readme.md CHANGED
@@ -1,8 +1,8 @@
1
- [![Gem Version](https://badge.fury.io/rb/volt.png)](http://badge.fury.io/rb/volt)
2
- [![Code Climate](https://codeclimate.com/github/voltrb/volt.png)](https://codeclimate.com/github/voltrb/volt)
3
- [![Build Status](https://travis-ci.org/voltrb/volt.png?branch=master)](https://travis-ci.org/voltrb/volt)
1
+ [![Gem Version](https://badge.fury.io/rb/volt.svg)](http://badge.fury.io/rb/volt)
2
+ [![Code Climate](http://img.shields.io/codeclimate/github/voltrb/volt.svg)](https://codeclimate.com/github/voltrb/volt)
3
+ [![Build Status](http://img.shields.io/travis/voltrb/volt/master.svg)](https://travis-ci.org/voltrb/volt)
4
4
  [![Inline docs](http://inch-ci.org/github/voltrb/volt.svg?branch=master)](http://inch-ci.org/github/voltrb/volt)
5
- [![Volt Chat](https://badges.gitter.im/voltrb/volt.png)](https://gitter.im/voltrb/volt)
5
+ [![Volt Chat](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/voltrb/volt)
6
6
 
7
7
  ** For the current status of volt, read: http://voltframework.com/blog
8
8
 
@@ -213,52 +213,52 @@ Sections help you split up different parts of the same content (title and body u
213
213
 
214
214
  ## Bindings
215
215
 
216
- Once you understand the basics of ReactiveValues, we can discuss bindings. In Volt, you code your views in a handlebars like template language. Volt provides several bindings, which handle rendering of something for you. Content bindings are anything inbetween { and }.
216
+ In Volt, you code your views in a handlebars like template language. Volt provides several bindings, which handle rendering of something for you. Content bindings are anything inbetween {{ and }}.
217
217
 
218
218
  ### Content binding
219
219
 
220
220
  The most basic binding is a content binding:
221
221
 
222
222
  ```html
223
- <p>{some_method}<p>
223
+ <p>{{ some_method }}<p>
224
224
  ```
225
225
 
226
- The content binding runs the Ruby code between { and }, then renders the return value. If the returned value is a ReactiveValue, it will update the value updated whenever a 'changed' event is triggered on the reactive value.
226
+ The content binding runs the Ruby code between {{ and }}, then renders the return value. Any time the data a content binding relies on changes, the binding will run again and update the text
227
227
 
228
228
  ### If binding
229
229
 
230
230
  An if binding lets you provide basic flow control.
231
231
 
232
232
  ```html
233
- {#if _some_check?}
233
+ {{ if _some_check? }}
234
234
  <p>render this</p>
235
- {/}
235
+ {{ end }}
236
236
  ```
237
237
 
238
- Blocks are closed with a {/}
238
+ Blocks are closed with a {{ end }}
239
239
 
240
240
  When the if binding is rendered, it will run the ruby code after #if. If the code is true it will render the code below. Again, if the returned value is reactive, it will update as that value changes.
241
241
 
242
242
  If bindings can also have #elsif and #else blocks.
243
243
 
244
244
  ```html
245
- {#if _condition_1?}
245
+ {{ if _condition_1? }}
246
246
  <p>condition 1 true</p>
247
- {#elsif _condition_2?}
247
+ {{ elsif _condition_2? }}
248
248
  <p>condition 2 true</p>
249
- {#else}
249
+ {{ else }}
250
250
  <p>neither true</p>
251
- {/}
251
+ {{ end }}
252
252
  ```
253
253
 
254
254
  ### Each binding
255
255
 
256
- For iteration over objects, the each binding is provided.
256
+ For iteration over objects, you can use .each
257
257
 
258
258
  ```html
259
- {#each _items as item}
260
- <p>{item}</p>
261
- {/}
259
+ {{ _items.each do |item| }}
260
+ <p>{{ item }}</p>
261
+ {{ end }}
262
262
  ```
263
263
 
264
264
  Above, if _items were an array, the block would be rendered for each item, setting 'item' to the value of the array element.
@@ -266,9 +266,9 @@ Above, if _items were an array, the block would be rendered for each item, setti
266
266
  You can also access the position of the item in the array with the #index method.
267
267
 
268
268
  ```html
269
- {#each _items as item}
270
- <p>{index}. {item}</p>
271
- {/}
269
+ {{ each _items as item }}
270
+ <p>{{ index }}. {{ item }}</p>
271
+ {{ end }}
272
272
  ```
273
273
 
274
274
  For the array: ['one', 'two', 'three'] this would print:
@@ -277,7 +277,7 @@ For the array: ['one', 'two', 'three'] this would print:
277
277
  1. two
278
278
  2. three
279
279
 
280
- You can do {index + 1} to correct the zero offset.
280
+ You can do {{ index + 1 }} to correct the zero offset.
281
281
 
282
282
  When items are removed or added to the array, the #each binding automatically and intelligently adds or removes the items from/to the DOM.
283
283
 
@@ -286,19 +286,19 @@ When items are removed or added to the array, the #each binding automatically an
286
286
  Bindings can also be placed inside of attributes.
287
287
 
288
288
  ```html
289
- <p class="{#if _is_cool?}cool{/}">Text</p>
289
+ <p class="{{ if _is_cool? }}cool{{ end }}">Text</p>
290
290
  ```
291
291
 
292
292
  There are some special features provided to make elements work as "two way bindings":
293
293
 
294
294
  ```html
295
- <input type="text" value="{_name}" />
295
+ <input type="text" value="{{ _name }}" />
296
296
  ```
297
297
 
298
298
  In the example above, if _name changes, the field will update, and if the field is updated, _name will be changed:
299
299
 
300
300
  ```html
301
- <input type="checkbox" checked="{_checked}" />
301
+ <input type="checkbox" checked="{{ _checked }}" />
302
302
  ```
303
303
 
304
304
  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.
@@ -306,8 +306,8 @@ If the value of a checked attribute is true, the checkbox will be shown checked.
306
306
  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.
307
307
 
308
308
  ```html
309
- <input type="radio" checked="{_radio}" value="one" />
310
- <input type="radio" checked="{_radio}" value="two" />
309
+ <input type="radio" checked="{{ _radio }}" value="one" />
310
+ <input type="radio" checked="{{ _radio }}" value="two" />
311
311
  ```
312
312
 
313
313
  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.
@@ -315,7 +315,7 @@ When a radio button is checked, whatever checked is bound to is set to the field
315
315
  Select boxes can be bound to a value (while not technically a property, this is another convient behavior we add).
316
316
 
317
317
  ```html
318
- <select value="{_rating}">
318
+ <select value="{{ _rating }}">
319
319
  <option value="1">*</option>
320
320
  <option value="2">**</option>
321
321
  <option value="3">***</option>
@@ -328,12 +328,20 @@ When the selected option of the select above changes, ```_rating``` is changed t
328
328
 
329
329
  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.
330
330
 
331
+ ### Template Bindings
332
+
333
+ All views/*.html files are templates that can be rendered inside of other views using the template binding.
334
+
335
+ ```html
336
+ {{ template "header" }}
337
+ ```
338
+
331
339
  ## Escaping
332
340
 
333
- When you need to use { and } outside of bindings, anything in a triple mustache will be escaped and not processed as a binding:
341
+ When you need to use {{ and }} outside of bindings, anything in a triple mustache will be escaped and not processed as a binding:
334
342
 
335
343
  ```html
336
- {{{ bindings look like: {this} }}}
344
+ {{{ bindings look like: {{this}} }}}
337
345
  ```
338
346
 
339
347
  # Models
@@ -693,6 +701,8 @@ A controller can be any class in Volt, however it is common to have that class i
693
701
  end
694
702
  ```
695
703
 
704
+ When a model is set, any missing methods will be proxied to the model. This lets you bind within the views without prefixing the model object every time. It also lets you change out the current model and have the views update automatically.
705
+
696
706
  In methods, the `#model` method returns the current model.
697
707
 
698
708
  See the [provided collections](#provided-collections) section for a list of the available collection models.
@@ -701,7 +711,7 @@ You can also provide your own object to model.
701
711
 
702
712
  In the example above, any methods not defined on the TodosController will fall through to the provided model. All views in views/{controller_name} will have this controller as the target for any Ruby run in their bindings. This means that calls on self (implicit or with self.) will have the model as their target (after calling through the controller). This lets you add methods to the controller to control how the model is handled, or provide extra methods to the views.
703
713
 
704
- Volt is more similar to an MVVM architecture than an MVC architecture. Instead of the controllers passing data off to the views, the controllers are the context for the views. When using a ModelController, the controller automatically forwards all methods it does not handle to the model. This is convenient since you can set a model in the controller and then access its properties directly with methods in bindings. This lets you do something like ```{_name}``` instead of something like ```{@model._name}```
714
+ Volt is more similar to an MVVM architecture than an MVC architecture. Instead of the controllers passing data off to the views, the controllers are the context for the views. When using a ModelController, the controller automatically forwards all methods it does not handle to the model. This is convenient since you can set a model in the controller and then access its properties directly with methods in bindings. This lets you do something like ```{{ _name }}``` instead of something like ```{{ @model._name }}```
705
715
 
706
716
  Controllers in the app/home component do not need to be namespaced, all other components should namespace controllers like so:
707
717
 
@@ -905,23 +915,40 @@ Once the view file for the control or template is found, it will look for a matc
905
915
 
906
916
  # Control Arguments/Attributes
907
917
 
908
- Like other html tags, controls can be passed attributes. These are then converted into a hash and passed as the first argument to the initialize method on the controller. The standard ModelController's initialize will then assign each key/value in the attributes hash as instance values. This makes it easy to access attributes passed in.
918
+ Like other html tags, controls can be passed attributes. These are then converted into an object that is passed as the first argument to the initialize method on the controller. The standard ModelController's initialize will then assign the object to the attrs property which can be accessed with ```#attrs``` This makes it easy to access attributes passed in.
909
919
 
910
920
  ```html
911
921
 
912
922
  <:Body>
913
923
 
914
924
  <ul>
915
- {#each _todos as todo}
916
- <:todo name="{todo._name}" />
917
- {/}
925
+ {{ _todos.each do |todo| }}
926
+ <:todo name="{{ todo._name }}" />
927
+ {{ end }}
918
928
  </ul>
919
929
 
920
930
  <:Todo>
921
- <li>{@name}</li>
922
-
931
+ <li>{{ attrs.name }}</li>
923
932
  ```
924
933
 
934
+ Instead of passing in individual attributes, you can also pass in a Model object with the "model" attribute and it will be set as the model for the controller.
935
+
936
+ ```html
937
+ <:Body>
938
+ <ul>
939
+ {{ _todos.each do |todo| }}
940
+ <:todo model="{{ todo }}" />
941
+ {{ end }}
942
+ </ul>
943
+
944
+ <:Todo>
945
+ <li>
946
+ {{ _name }} -
947
+ {{ if _complete }}
948
+ Complete
949
+ {{ end }}
950
+ </li>
951
+ ```
925
952
 
926
953
  # Routes
927
954
 
@@ -944,7 +971,7 @@ When the params are changed, the URL will be set to the path for the route whose
944
971
  Route paths can also contain variables similar to bindings:
945
972
 
946
973
  ```ruby
947
- get "/todos/{_index}", _view: 'todos'
974
+ get "/todos/{{ _index }}", _view: 'todos'
948
975
  ```
949
976
 
950
977
  In the case above, if any URL matches /todos/*, (where * is anything but a slash), it will be the active route. ```params._view``` would be set to 'todos', and ```params._index``` would be set to the value in the path.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.5
1
+ 0.8.6
@@ -1,20 +1,20 @@
1
1
  <:Body>
2
- {#if page._reloading}
2
+ {{ if page._reloading }}
3
3
  <div class="notices alert alert-info">Reloading...</div>
4
- {/}
5
- {#if channel.status == :reconnecting}
4
+ {{ end }}
5
+ {{ if channel.status == :reconnecting }}
6
6
  <div class="notices alert alert-info">
7
- Connection Lost... {channel.error}...
8
- {#if channel.reconnect_interval} Reconnecting in {(channel.reconnect_interval / 1000.0).round} sec{/}
7
+ Connection Lost... {{ channel.error }}...
8
+ {{ if channel.reconnect_interval }} Reconnecting in {{ (channel.reconnect_interval / 1000.0).round }} sec{{ end }}
9
9
  </div>
10
- {/}
11
- {#if page._reconnected}
10
+ {{ end }}
11
+ {{ if page._reconnected }}
12
12
  <div class="notices alert alert-success">Reconnected!</div>
13
- {/}
14
- {#if !flash.empty?}
13
+ {{ end }}
14
+ {{ if !flash.empty? }}
15
15
  <div class="notices alert alert-info" e-click="flash.clear">
16
- {#each flash._notices as notice}
17
- <p>{notice}</p>
18
- {/}
16
+ {{ flash._notices.each do |notice| }}
17
+ <p>{{ notice }}</p>
18
+ {{ end }}
19
19
  </div>
20
- {/}
20
+ {{ end }}
@@ -0,0 +1,2 @@
1
+ # Integrating JavaScript
2
+
@@ -157,7 +157,7 @@ class Routes
157
157
 
158
158
  parts.each_with_index do |part, index|
159
159
  if has_binding?(part)
160
- params[part[1..-2].to_sym] = index
160
+ params[part[2...-2].strip.to_sym] = index
161
161
 
162
162
  # Set the part to be '*' (anything matcher)
163
163
  part = '*'
@@ -178,7 +178,7 @@ class Routes
178
178
  if has_binding?(part)
179
179
  # Setup a nil param that can match anything, but gets
180
180
  # assigned into the url
181
- params[part[1..-2].to_sym] = nil
181
+ params[part[2...-2].strip.to_sym] = nil
182
182
  end
183
183
  end
184
184
 
@@ -197,7 +197,7 @@ class Routes
197
197
  url = parts.map do |part|
198
198
  val = if has_binding?(part)
199
199
  # Get the
200
- binding = part[1..-2].to_sym
200
+ binding = part[2...-2].strip.to_sym
201
201
  input_params.delete(binding)
202
202
  else
203
203
  part
@@ -254,7 +254,7 @@ class Routes
254
254
 
255
255
  # Check if a string has a binding in it
256
256
  def has_binding?(string)
257
- string.index('{') && string.index('}')
257
+ string.index('{{') && string.index('}}')
258
258
  end
259
259
 
260
260
  end
@@ -32,8 +32,8 @@ module AttributeScope
32
32
  end
33
33
 
34
34
  def process_attribute(tag_name, attributes, attribute_name, value)
35
- parts = value.split(/(\{[^\}]+\})/).reject(&:blank?)
36
- binding_count = parts.count {|p| p[0] == '{' && p[-1] == '}'}
35
+ parts = value.split(/(\{\{[^\}]+\}\})/).reject(&:blank?)
36
+ binding_count = parts.count {|p| p[0] == '{' && p[1] == '{' && p[-2] == '}' && p[-1] == '}'}
37
37
 
38
38
  # if this attribute has bindings
39
39
  if binding_count > 0
@@ -69,7 +69,7 @@ module AttributeScope
69
69
 
70
70
  # Add an attribute binding on the tag, bind directly to the getter in the binding
71
71
  def add_single_attribute(id, attribute_name, parts)
72
- getter = parts[0][1..-2]
72
+ getter = parts[0][2...-2].strip
73
73
 
74
74
  # if getter.index('@')
75
75
  # raise "Bindings currently do not support instance variables"
@@ -1,18 +1,22 @@
1
1
  class EachScope < ViewScope
2
2
  def initialize(handler, path, content)
3
3
  super(handler, path)
4
- @content, @variable_name = content.strip.split(/ as /)
4
+ # @content, @variable_name = content.strip.split(/ as /)
5
+
6
+ @content, @variable_name = content.split(/.each\s+do\s+\|/)
7
+
8
+ @variable_name = @variable_name.gsub(/\|/, '')
5
9
  end
6
-
10
+
7
11
  def close_scope
8
12
  binding_number = @handler.scope[-2].binding_number
9
13
  @handler.scope[-2].binding_number += 1
10
14
  @path += "/__template/#{binding_number}"
11
-
15
+
12
16
  super
13
-
17
+
14
18
  @handler.html << "<!-- $#{binding_number} --><!-- $/#{binding_number} -->"
15
19
  @handler.scope.last.save_binding(binding_number, "lambda { |__p, __t, __c, __id| EachBinding.new(__p, __t, __c, __id, Proc.new { #{@content} }, #{@variable_name.inspect}, #{@path.inspect}) }")
16
-
20
+
17
21
  end
18
22
  end
@@ -82,9 +82,12 @@ class SandlebarsParser
82
82
  end
83
83
 
84
84
  text(@html[1])
85
- elsif (binding = @html.scan(/\{/))
85
+ elsif (binding = @html.scan(/\{\{/))
86
86
  # We are in text mode and matched the start of a binding
87
87
  start_binding
88
+ elsif (text = @html.scan(/\{/))
89
+ # A single { outside of a binding
90
+ text(text)
88
91
  elsif (text = @html.scan(/(?:[^\<\{]+)/))
89
92
  # matched text up until the next html tag
90
93
  text(text)
@@ -106,16 +109,16 @@ class SandlebarsParser
106
109
  binding = ''
107
110
  open_count = 1
108
111
 
109
- # scan until we reach a { or }
112
+ # scan until we reach a {{ or }}
110
113
  loop do
111
- binding << @html.scan_until(/([\{\}\n]|\Z)/)
114
+ binding << @html.scan_until(/(\{\{|\}\}|\n|\Z)/)
112
115
 
113
116
  match = @html[1]
114
- if match == '}'
117
+ if match == '}}'
115
118
  # close
116
119
  open_count -= 1
117
120
  break if open_count == 0
118
- elsif match == '{'
121
+ elsif match == '{{'
119
122
  # open more
120
123
  open_count += 1
121
124
  elsif match == "\n" || @html.eos?
@@ -127,7 +130,7 @@ class SandlebarsParser
127
130
  end
128
131
  end
129
132
 
130
- binding = binding[0..-2]
133
+ binding = binding[0..-3]
131
134
  @handler.binding(binding) if @handler.respond_to?(:binding)
132
135
  end
133
136
 
@@ -6,7 +6,7 @@ class TextareaScope < ViewScope
6
6
  end
7
7
 
8
8
  def add_binding(content)
9
- @html << "{#{content}}"
9
+ @html << "{{#{content}}}"
10
10
  end
11
11
 
12
12
  def close_scope(pop=true)
@@ -15,7 +15,7 @@ class TextareaScope < ViewScope
15
15
 
16
16
  attributes = @attributes
17
17
 
18
- if @html[/\{[^\}]+\}/]
18
+ if @html[/\{\{[^\}]+\}\}/]
19
19
  # If the html inside the textarea has a binding, process it as
20
20
  # a value attribute.
21
21
  attributes['value'] = @html
@@ -20,33 +20,42 @@ class ViewScope
20
20
  end
21
21
 
22
22
  def add_binding(content)
23
- case content[0]
24
- when '#'
25
- command, *content = content.split(/ /)
26
- content = content.join(' ')
27
-
28
- case command
29
- when '#if'
30
- add_if(content)
31
- when '#elsif'
32
- add_else(content)
33
- when '#else'
34
- if content.blank?
23
+ content = content.strip
24
+ index = content.index(/[ \(]/)
25
+ if index
26
+ first_symbol = content[0...index]
27
+ args = content[index..-1].strip
28
+
29
+ case first_symbol
30
+ when 'if'
31
+ add_if(args)
32
+ when 'elsif'
33
+ add_else(args)
34
+ when 'else'
35
+ if args.blank?
35
36
  add_else(nil)
36
37
  else
37
- raise "#else does not take a conditional #{content} was provided."
38
+ raise "else does not take a conditional, #{content} was provided."
39
+ end
40
+ when 'template'
41
+ add_template(args)
42
+ else
43
+ if content =~ /.each\s+do\s+\|/
44
+ add_each(content)
45
+ else
46
+ add_content_binding(content)
38
47
  end
39
- when '#each'
40
- add_each(content)
41
- when '#template'
42
- add_template(content)
43
48
  end
44
- when '/'
45
- # close binding
46
- close_scope
47
49
  else
48
- # content
49
- add_content_binding(content)
50
+ case content
51
+ when 'end'
52
+ # Close the binding
53
+ close_scope
54
+ when 'else'
55
+ add_else(nil)
56
+ else
57
+ add_content_binding(content)
58
+ end
50
59
  end
51
60
  end
52
61
 
@@ -71,6 +80,9 @@ class ViewScope
71
80
  end
72
81
 
73
82
  def add_template(content)
83
+ # Strip ( and ) from the outsides
84
+ content = content.strip.gsub(/^\(/, '').gsub(/\)$/, '')
85
+
74
86
  @handler.html << "<!-- $#{@binding_number} --><!-- $/#{@binding_number} -->"
75
87
  save_binding(@binding_number, "lambda { |__p, __t, __c, __id| TemplateBinding.new(__p, __t, __c, __id, #{@path.inspect}, Proc.new { [#{content}] }) }")
76
88
 
@@ -100,8 +112,8 @@ class ViewScope
100
112
 
101
113
  data_hash = []
102
114
  attributes.each_pair do |name, value|
103
- parts = value.split(/(\{[^\}]+\})/).reject(&:blank?)
104
- binding_count = parts.count {|p| p[0] == '{' && p[-1] == '}'}
115
+ parts = value.split(/(\{\{[^\}]+\}\})/).reject(&:blank?)
116
+ binding_count = parts.count {|p| p[0] == '{' && p[1] == '{' && p[-2] == '}' && p[-1] == '}'}
105
117
 
106
118
  # if this attribute has bindings
107
119
  if binding_count > 0
@@ -1,6 +1,6 @@
1
1
  # See https://github.com/voltrb/volt#routes for more info on routes
2
2
 
3
- get "/bindings/{_route_test}", _action: 'bindings'
3
+ get "/bindings/{{_route_test}}", _action: 'bindings'
4
4
  get "/bindings", _action: 'bindings'
5
5
  get "/store", _action: 'store'
6
6
 
@@ -4,32 +4,31 @@
4
4
  <:Body>
5
5
  <h1>Bindings</h1>
6
6
 
7
-
8
7
  <h2>Text</h2>
9
8
  <table class="table">
10
9
  <tr>
11
10
  <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>
11
+ <td><input type="text" id="pageName1" value="{{ page._name }}"></td>
12
+ <td><input type="text" id="pageName2" value="{{ page._name }}"></td>
13
+ <td id="pageName3">{{ page._name }}</td>
15
14
  </tr>
16
15
  <tr>
17
16
  <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>
17
+ <td><input type="text" id="paramsName1" value="{{ params._name }}"></td>
18
+ <td><input type="text" id="paramsName2" value="{{ params._name }}"></td>
19
+ <td id="paramsName3">{{ params._name }}</td>
21
20
  </tr>
22
21
  <tr>
23
22
  <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>
23
+ <td><input type="text" id="routesName1" value="{{ params._route_test }}"></td>
24
+ <td><input type="text" id="routesName2" value="{{ params._route_test }}"></td>
25
+ <td id="routesName3">{{ params._route_test }}</td>
27
26
  </tr>
28
27
  <tr>
29
28
  <td>Local Store</td>
30
- <td><input type="text" id="localstoreName1" value="{local_store._name}"></td>
31
- <td><input type="text" id="localstoreName2" value="{local_store._name}"></td>
32
- <td id="localstoreName3">{local_store._name}</td>
29
+ <td><input type="text" id="localstoreName1" value="{{ local_store._name }}"></td>
30
+ <td><input type="text" id="localstoreName2" value="{{ local_store._name }}"></td>
31
+ <td id="localstoreName3">{{ local_store._name }}</td>
33
32
  </tr>
34
33
  </table>
35
34
 
@@ -38,15 +37,15 @@
38
37
  <table class="table">
39
38
  <tr>
40
39
  <td>Page</td>
41
- <td><input type="checkbox" id="pageCheck1" checked="{page._check}" /></td>
42
- <td><input type="checkbox" id="pageCheck2" checked="{page._check}" /></td>
43
- <td id="pageCheck3">{page._check}</td>
40
+ <td><input type="checkbox" id="pageCheck1" checked="{{ page._check }}" /></td>
41
+ <td><input type="checkbox" id="pageCheck2" checked="{{ page._check }}" /></td>
42
+ <td id="pageCheck3">{{ page._check }}</td>
44
43
  </tr>
45
44
  <tr>
46
45
  <td>Params</td>
47
- <td><input type="checkbox" id="paramsCheck1" checked="{params._check}" /></td>
48
- <td><input type="checkbox" id="paramsCheck2" checked="{params._check}" /></td>
49
- <td id="paramsCheck3">{params._check}</td>
46
+ <td><input type="checkbox" id="paramsCheck1" checked="{{ params._check }}" /></td>
47
+ <td><input type="checkbox" id="paramsCheck2" checked="{{ params._check }}" /></td>
48
+ <td id="paramsCheck3">{{ params._check }}</td>
50
49
  </tr>
51
50
  </table>
52
51
 
@@ -55,14 +54,14 @@
55
54
  <table class="table">
56
55
  <tr>
57
56
  <td>Page</td>
58
- <td><input type="radio" id="pageRadio1" checked="{page._radio}" value="one" /></td>
59
- <td><input type="radio" id="pageRadio2" checked="{page._radio}" value="two" /></td>
60
- <td id="pageRadio3">{page._radio}</td>
57
+ <td><input type="radio" id="pageRadio1" checked="{{ page._radio }}" value="one" /></td>
58
+ <td><input type="radio" id="pageRadio2" checked="{{ page._radio }}" value="two" /></td>
59
+ <td id="pageRadio3">{{ page._radio }}</td>
61
60
  </tr>
62
61
  <tr>
63
62
  <td></td>
64
- <td><input type="radio" checked="{page._radio}" value="one" /></td>
65
- <td><input type="radio" checked="{page._radio}" value="two" /></td>
63
+ <td><input type="radio" checked="{{ page._radio }}" value="one" /></td>
64
+ <td><input type="radio" checked="{{ page._radio }}" value="two" /></td>
66
65
  <td></td>
67
66
  </tr>
68
67
  </table>
@@ -72,16 +71,16 @@
72
71
  <tr>
73
72
  <td>Page</td>
74
73
  <td>
75
- <select id="pageSelect1" value="{page._select}">
74
+ <select id="pageSelect1" value="{{ page._select }}">
76
75
  <option value="one">One</option>
77
76
  <option value="two">Two</option>
78
77
  <option value="three">Three</option>
79
78
  </select>
80
79
  </td>
81
80
  <td>
82
- <input type="text" id="pageSelect2" value="{page._select}" />
81
+ <input type="text" id="pageSelect2" value="{{ page._select }}" />
83
82
  </td>
84
- <td id="pageSelect3">{page._select}</td>
83
+ <td id="pageSelect3">{{ page._select }}</td>
85
84
  </tr>
86
85
  </table>
87
86
 
@@ -90,9 +89,33 @@
90
89
  <table class="table">
91
90
  <tr>
92
91
  <td>Page</td>
93
- <td><textarea id="textareaName1">{page._textarea_name}</textarea></td>
94
- <td><textarea id="textareaName2">{page._textarea_name}</textarea></td>
95
- <td id="textareaName3">{page._textarea_name}</td>
92
+ <td><textarea id="textareaName1">{{ page._textarea_name }}</textarea></td>
93
+ <td><textarea id="textareaName2">{{ page._textarea_name }}</textarea></td>
94
+ <td id="textareaName3">{{ page._textarea_name }}</td>
95
+ </tr>
96
+ </table>
97
+
98
+ <h2>URL</h2>
99
+ <table class="table">
100
+ <tr>
101
+ <td>Path</td>
102
+ <td id="urlPath">{{ url.path }}</td>
103
+ </tr>
104
+ <tr>
105
+ <td>Query</td>
106
+ <td id="urlPath">{{ url.query }}</td>
107
+ <td><input type="text" value="{{ url.query }}" /></td>
108
+ </tr>
109
+ <tr>
110
+ <td>Fragment</td>
111
+ <td id="urlPath">{{ url.fragment }}</td>
112
+ <td><input type="text" value="{{ url.fragment }}" /></td>
96
113
  </tr>
97
114
  </table>
98
115
 
116
+
117
+ <h2>Content</h2>
118
+
119
+ <p id="escapeContent">{{{this is {{escaped}}}}}</p>
120
+
121
+
@@ -1,5 +1,5 @@
1
1
  <:Title>
2
- {#template main_path, "title", {controller_group: 'main'}} - KitchenSink
2
+ {{ template main_path, "title", {controller_group: 'main'} }} - KitchenSink
3
3
 
4
4
  <:Body>
5
5
  <div class="container">
@@ -14,7 +14,7 @@
14
14
 
15
15
  <:volt:notices />
16
16
 
17
- {#template main_path, 'body', {controller_group: 'main'}}
17
+ {{ template main_path, 'body', {controller_group: 'main'} }}
18
18
 
19
19
  <div class="footer">
20
20
  <p>&copy; Company 2014</p>
@@ -23,7 +23,7 @@
23
23
  </div>
24
24
 
25
25
  <:Nav>
26
- <li class="{#if url.path.split('/')[1] == attrs.href.split('/')[1]}active{/}">
27
- <a href="{attrs.href}">{attrs.text}</a>
26
+ <li class="{{ if url.path.split('/')[1] == attrs.href.split('/')[1] }}active{{ end }}">
27
+ <a href="{{ attrs.href }}">{{ attrs.text }}</a>
28
28
  </li>
29
29
 
@@ -192,5 +192,15 @@ if ENV['BROWSER']
192
192
  end
193
193
  end
194
194
  end
195
+
196
+ describe "content escaping" do
197
+ it 'should escape in a tripple stash' do
198
+ visit '/'
199
+
200
+ click_link 'Bindings'
201
+
202
+ expect(find('#escapeContent')).to have_content('this is {{escaped}}')
203
+ end
204
+ end
195
205
  end
196
206
  end
@@ -19,8 +19,8 @@ describe Routes do
19
19
 
20
20
  it "should setup indiect routes" do
21
21
  routes do
22
- get '/blog/{_id}/edit', _view: 'blog/edit'
23
- get '/blog/{_id}', _view: 'blog/show'
22
+ get '/blog/{{ _id }}/edit', _view: 'blog/edit'
23
+ get '/blog/{{ _id }}', _view: 'blog/show'
24
24
  end
25
25
 
26
26
  indirect_routes = @routes.instance_variable_get(:@indirect_routes)
@@ -41,11 +41,11 @@ describe Routes do
41
41
  it "should match routes" do
42
42
  routes do
43
43
  get "/blog", _view: 'blog'
44
- get '/blog/{_id}', _view: 'blog/show'
45
- get '/blog/{_id}/draft', _view: 'blog/draft', _action: 'draft'
46
- get '/blog/{_id}/edit', _view: 'blog/edit'
47
- get '/blog/tags/{_tag}', _view: 'blog/tag'
48
- get '/login/{_name}/user/{_id}', _view: 'login', _action: 'user'
44
+ get '/blog/{{ _id }}', _view: 'blog/show'
45
+ get '/blog/{{ _id }}/draft', _view: 'blog/draft', _action: 'draft'
46
+ get '/blog/{{ _id }}/edit', _view: 'blog/edit'
47
+ get '/blog/tags/{{ _tag }}', _view: 'blog/tag'
48
+ get '/login/{{ _name }}/user/{{ _id }}', _view: 'login', _action: 'user'
49
49
  end
50
50
 
51
51
  params = @routes.url_to_params('/blog')
@@ -74,10 +74,10 @@ describe Routes do
74
74
  it "should setup param matchers" do
75
75
  routes do
76
76
  get "/blog", _view: 'blog'
77
- get '/blog/{_id}', _view: 'blog/show'
78
- get '/blog/{_id}/edit', _view: 'blog/edit'
79
- get '/blog/tags/{_tag}', _view: 'blog/tag'
80
- get '/login/{_name}/user/{_id}', _view: 'login', _action: 'user'
77
+ get '/blog/{{ _id }}', _view: 'blog/show'
78
+ get '/blog/{{ _id }}/edit', _view: 'blog/edit'
79
+ get '/blog/tags/{{ _tag }}', _view: 'blog/tag'
80
+ get '/login/{{ _name }}/user/{{ _id }}', _view: 'login', _action: 'user'
81
81
  end
82
82
 
83
83
  param_matches = @routes.instance_variable_get(:@param_matches)
@@ -94,10 +94,10 @@ describe Routes do
94
94
  it "should go from params to url" do
95
95
  routes do
96
96
  get "/blog", _view: 'blog'
97
- get '/blog/{_id}', _view: 'blog/show'
98
- get '/blog/{_id}/edit', _view: 'blog/edit'
99
- get '/blog/tags/{_tag}', _view: 'blog/tag'
100
- get '/login/{_name}/user/{_id}', _view: 'login', _action: 'user'
97
+ get '/blog/{{ _id }}', _view: 'blog/show'
98
+ get '/blog/{{ _id }}/edit', _view: 'blog/edit'
99
+ get '/blog/tags/{{ _tag }}', _view: 'blog/tag'
100
+ get '/login/{{ _name }}/user/{{ _id }}', _view: 'login', _action: 'user'
101
101
  end
102
102
 
103
103
  url, params = @routes.params_to_url({_view: 'blog/show', _id: '55'})
@@ -162,7 +162,7 @@ describe Routes do
162
162
 
163
163
  routes do
164
164
  get '/', _controller: 'index'
165
- get '/blog/{_id}', _controller: 'blog'
165
+ get '/blog/{{ _id }}', _controller: 'blog'
166
166
  end
167
167
 
168
168
  params = @routes.url_to_params('/blog/20')
@@ -1,5 +1,6 @@
1
1
  if RUBY_PLATFORM == 'opal'
2
2
  else
3
+ require 'spec_helper'
3
4
  require 'benchmark'
4
5
  require 'volt/server/html_parser/sandlebars_parser'
5
6
 
@@ -103,21 +104,21 @@ describe SandlebarsParser do
103
104
  end
104
105
 
105
106
  it "should raise an exception on an unclosed binding at the end of the document" do
106
- html = "<p>testing with {nested"
107
+ html = "<p>testing with {{nested"
107
108
 
108
109
  handler = HTMLHandler.new
109
110
  expect { SandlebarsParser.new(html, handler) }.to raise_error(HTMLParseError)
110
111
  end
111
112
 
112
113
  it "should raise an exception on an unclosed binding" do
113
- html = "<p>testing with {nested </p>\n<p>ok</p>"
114
+ html = "<p>testing with {{nested </p>\n<p>ok</p>"
114
115
 
115
116
  handler = HTMLHandler.new
116
117
  expect { SandlebarsParser.new(html, handler) }.to raise_error(HTMLParseError)
117
118
  end
118
119
 
119
120
  it "should report the line number" do
120
- html = "\n\n<p>some paragraph</p>\n\n<p>testing with {nested </p>\n<p>ok</p>"
121
+ html = "\n\n<p>some paragraph</p>\n\n<p>testing with {{nested </p>\n<p>ok</p>"
121
122
 
122
123
  handler = HTMLHandler.new
123
124
  expect { SandlebarsParser.new(html, handler) }.to raise_error(HTMLParseError, "unclosed binding: {nested </p> on line: 5")
@@ -5,7 +5,7 @@ require 'volt/server/html_parser/view_parser'
5
5
 
6
6
  describe ViewParser do
7
7
  it "should parse content bindings" do
8
- html = "<p>Some {content} binding, {name}</p>"
8
+ html = "<p>Some {{ content }} binding, {{ name }}</p>"
9
9
 
10
10
  view = ViewParser.new(html, "main/main/main")
11
11
 
@@ -24,13 +24,13 @@ describe ViewParser do
24
24
  html = <<-END
25
25
  <p>
26
26
  Some
27
- {#if showing == :text}
27
+ {{ if showing == :text }}
28
28
  text
29
- {#elsif showing == :button}
29
+ {{ elsif showing == :button }}
30
30
  <button>Button</button>
31
- {#else}
31
+ {{ else }}
32
32
  <a href="">link</a>
33
- {/}
33
+ {{ end }}
34
34
  </p>
35
35
  END
36
36
 
@@ -63,13 +63,13 @@ describe ViewParser do
63
63
  html = <<-END
64
64
  <p>
65
65
  Some
66
- {#if showing == :text}
67
- {#if sub_item}
66
+ {{ if showing == :text }}
67
+ {{ if sub_item }}
68
68
  sub item text
69
- {/}
70
- {#else}
69
+ {{ end }}
70
+ {{ else }}
71
71
  other
72
- {/}
72
+ {{ end }}
73
73
  </p>
74
74
  END
75
75
 
@@ -105,9 +105,9 @@ describe ViewParser do
105
105
  it "should parse each bindings" do
106
106
  html = <<-END
107
107
  <div class="main">
108
- {#each _items as item}
109
- <p>{item}</p>
110
- {/}
108
+ {{ _items.each do |item| }}
109
+ <p>{{ item }}</p>
110
+ {{ end }}
111
111
  </div>
112
112
  END
113
113
 
@@ -137,7 +137,7 @@ describe ViewParser do
137
137
 
138
138
  it "should parse a single attribute binding" do
139
139
  html = <<-END
140
- <div class="{main_class}">
140
+ <div class="{{ main_class }}">
141
141
  </div>
142
142
  END
143
143
 
@@ -148,7 +148,7 @@ describe ViewParser do
148
148
 
149
149
  it "should parse multiple attribute bindings in a single attribute" do
150
150
  html = <<-END
151
- <div class="start {main_class} {awesome_class} string">
151
+ <div class="start {{ main_class }} {{ awesome_class }} string">
152
152
  </div>
153
153
  END
154
154
 
@@ -179,7 +179,7 @@ describe ViewParser do
179
179
 
180
180
  it "should parse a template" do
181
181
  html = <<-END
182
- {#template "/home/temp/path"}
182
+ {{ template "/home/temp/path" }}
183
183
  END
184
184
 
185
185
  view = ViewParser.new(html, "main/main/main")
@@ -259,7 +259,7 @@ describe ViewParser do
259
259
 
260
260
  it "should setup bindings for textarea values" do
261
261
  html = <<-END
262
- <textarea name="cool">{awesome}</textarea>
262
+ <textarea name="cool">{{ awesome }}</textarea>
263
263
  END
264
264
 
265
265
  view = ViewParser.new(html, "main/main/main")
@@ -1,5 +1,5 @@
1
1
  <:Title>
2
- {#template main_path, "title", {controller_group: 'main'}}
2
+ {{ template main_path, "title", {controller_group: 'main'} }}
3
3
 
4
4
  <:Body>
5
5
  <div class="container">
@@ -13,7 +13,7 @@
13
13
 
14
14
  <:volt:notices />
15
15
 
16
- {#template main_path, 'body', {controller_group: 'main'}}
16
+ {{ template main_path, 'body', {controller_group: 'main'} }}
17
17
 
18
18
  <div class="footer">
19
19
  <p>&copy; Company 2014</p>
@@ -22,7 +22,7 @@
22
22
  </div>
23
23
 
24
24
  <:Nav>
25
- <li class="{#if url.path.split('/')[1] == attrs.href.split('/')[1]}active{/}">
26
- <a href="{attrs.href}">{attrs.text}</a>
25
+ <li class="{{ if url.path.split('/')[1] == attrs.href.split('/')[1] }}active{{ end }}">
26
+ <a href="{{ attrs.href }}">{{ attrs.text }}</a>
27
27
  </li>
28
28
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: volt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.5
4
+ version: 0.8.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Stout
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-05 00:00:00.000000000 Z
11
+ date: 2014-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -368,6 +368,7 @@ files:
368
368
  - bin/volt
369
369
  - docs/FAQ.md
370
370
  - docs/GETTING_STARTED.md
371
+ - docs/JAVASCRIPT_COMPONENTS.md
371
372
  - docs/WHY.md
372
373
  - docs/volt-logo.jpg
373
374
  - lib/volt.rb