flavour_saver 0.3.7 → 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +30 -0
- data/lib/flavour_saver/helpers.rb +4 -1
- data/lib/flavour_saver/lexer.rb +8 -0
- data/lib/flavour_saver/parser.rb +7 -2
- data/lib/flavour_saver/runtime.rb +1 -1
- data/lib/flavour_saver/version.rb +1 -1
- data/spec/acceptance/handlebars_qunit_spec.rb +22 -0
- data/spec/acceptance/subexpression_spec.rb +38 -0
- data/spec/lib/flavour_saver/lexer_spec.rb +24 -0
- data/spec/lib/flavour_saver/parser_spec.rb +33 -0
- data/spec/lib/flavour_saver/runtime_spec.rb +11 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0965ce577ba5f5e0e84097ff444c306b053ba899
|
4
|
+
data.tar.gz: f92b0741008a767ef778841404397eabf41620f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11472cf0bc62d973eb98cf1e1c6c1275aa1c37b55ac52f43776104cb5629308ad5d2676887fc760657fa794a560e0f2bd8e826ddb338557772254fca4e6ef10a
|
7
|
+
data.tar.gz: 6e238d05a52deafb8309454977ca86d4a6c2f09171baff67a814bac81a005cfb97511e95bd8b0feec0ea0e47c47e9c1a15fee75d68966ddc902946d9de00ba19
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -74,6 +74,7 @@ Currently supported:
|
|
74
74
|
- Inverse blocks
|
75
75
|
- Partials
|
76
76
|
- Raw content (`{{{{raw}}}} not parsed or validated {{{{/raw}}}}`)
|
77
|
+
- Subexpressions (`{{sum 1 (sum 1 1)}}` returns `3`)
|
77
78
|
|
78
79
|
## Helpers
|
79
80
|
|
@@ -248,6 +249,35 @@ Which could be used like so:
|
|
248
249
|
{{/isFemale}}
|
249
250
|
```
|
250
251
|
|
252
|
+
### Subexpressions
|
253
|
+
|
254
|
+
You can use a subexpression as any value for a helper, and it will be executed before it is ran. You can also nest them, and use them in assignment of variables.
|
255
|
+
|
256
|
+
Below are some examples, utilizing a "sum" helper than adds together two numbers.
|
257
|
+
|
258
|
+
```
|
259
|
+
{{sum (sum 5 10) (sum 2 (sum 1 4))}}
|
260
|
+
#=> 22
|
261
|
+
|
262
|
+
{{#if (sum 1 2) > 2}}its more{{/if}}
|
263
|
+
#=> its more
|
264
|
+
|
265
|
+
{{#student_heights size=(sum boys girls)}}
|
266
|
+
```
|
267
|
+
|
268
|
+
### Raw Content
|
269
|
+
|
270
|
+
Sometimes you don't want a section of content to be evaluted as handlebars, such as when you want to display it in a page that renders with handlebars. FlavourSaver offers a `raw` helper, that will allow you to pass anything through wrapped in those elements, and it will not be evaluated.
|
271
|
+
|
272
|
+
```
|
273
|
+
{{{{raw}}}}
|
274
|
+
{{if} this tries to parse, it will break on syntax
|
275
|
+
{{{{/raw}}}}
|
276
|
+
=> {{if} this tries to parse, it will break on syntax
|
277
|
+
```
|
278
|
+
|
279
|
+
Its important to note that while this looks like a block helper, it is not in practice. This is why you must omit the use of a `#` when writing it.
|
280
|
+
|
251
281
|
### Using Partials
|
252
282
|
|
253
283
|
Handlebars allows you to register a partial either as a function or a string template with
|
@@ -11,7 +11,10 @@ module FlavourSaver
|
|
11
11
|
r = []
|
12
12
|
count = 0
|
13
13
|
collection.each do |element|
|
14
|
-
r << yield.contents(element,
|
14
|
+
r << yield.contents(element,
|
15
|
+
'index' => count,
|
16
|
+
'last' => count == collection.size - 1,
|
17
|
+
'first' => count == 0)
|
15
18
|
count += 1
|
16
19
|
end
|
17
20
|
yield.rendered!
|
data/lib/flavour_saver/lexer.rb
CHANGED
data/lib/flavour_saver/parser.rb
CHANGED
@@ -86,6 +86,10 @@ module FlavourSaver
|
|
86
86
|
clause('EXPRST expression_contents EXPRE') { |_,e,_| e }
|
87
87
|
end
|
88
88
|
|
89
|
+
production(:subexpr) do
|
90
|
+
clause('OPAR expression_contents CPAR') { |_,e,_| e }
|
91
|
+
end
|
92
|
+
|
89
93
|
production(:expr_comment) do
|
90
94
|
clause('EXPRST BANG COMMENT EXPRE') { |_,_,e,_| e }
|
91
95
|
end
|
@@ -129,8 +133,8 @@ module FlavourSaver
|
|
129
133
|
clause('argument_list WHITE hash') { |e0,_,e1| e0 + [e1] }
|
130
134
|
clause('hash') { |e| [e] }
|
131
135
|
end
|
132
|
-
|
133
|
-
nonempty_list(:argument_list, [:object_path,:lit], :WHITE)
|
136
|
+
|
137
|
+
nonempty_list(:argument_list, [:object_path,:lit, :local, :subexpr], :WHITE)
|
134
138
|
|
135
139
|
production(:lit) do
|
136
140
|
clause('string') { |e| e }
|
@@ -157,6 +161,7 @@ module FlavourSaver
|
|
157
161
|
end
|
158
162
|
|
159
163
|
production(:hash_item) do
|
164
|
+
clause('IDENT EQ subexpr') { |e0,_,e1| { e0.to_sym => e1 } }
|
160
165
|
clause('IDENT EQ string') { |e0,_,e1| { e0.to_sym => e1 } }
|
161
166
|
clause('IDENT EQ number') { |e0,_,e1| { e0.to_sym => e1 } }
|
162
167
|
clause('IDENT EQ object_path') { |e0,_,e1| { e0.to_sym => e1 } }
|
@@ -909,6 +909,28 @@ describe FlavourSaver do
|
|
909
909
|
end
|
910
910
|
end
|
911
911
|
|
912
|
+
describe 'each with @last' do
|
913
|
+
let(:template) { "{{#each goodbyes}}{{@index}}. {{text}}! {{#if @last}}last{{/if}}{{/each}} cruel {{world}}!" }
|
914
|
+
|
915
|
+
example 'the @last variable is used' do
|
916
|
+
g = Struct.new(:text)
|
917
|
+
context.stub(:goodbyes).and_return([g.new('goodbye'), g.new('Goodbye'), g.new('GOODBYE')])
|
918
|
+
context.stub(:world).and_return('world')
|
919
|
+
subject.should == "0. goodbye! 1. Goodbye! 2. GOODBYE! last cruel world!"
|
920
|
+
end
|
921
|
+
end
|
922
|
+
|
923
|
+
describe 'each with @first' do
|
924
|
+
let(:template) { "{{#each goodbyes}}{{@index}}. {{text}} {{#if @first}}first{{/if}}! {{/each}}cruel {{world}}!" }
|
925
|
+
|
926
|
+
example 'the first variable is used' do
|
927
|
+
g = Struct.new(:text)
|
928
|
+
context.stub(:goodbyes).and_return([g.new('goodbye'), g.new('Goodbye'), g.new('GOODBYE')])
|
929
|
+
context.stub(:world).and_return('world')
|
930
|
+
subject.should == "0. goodbye first! 1. Goodbye ! 2. GOODBYE ! cruel world!"
|
931
|
+
end
|
932
|
+
end
|
933
|
+
|
912
934
|
describe 'log' do
|
913
935
|
let(:template) { "{{log blah}}" }
|
914
936
|
let(:log) { double(:log) }
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
require 'flavour_saver'
|
3
|
+
|
4
|
+
describe 'Subexpressions' do
|
5
|
+
|
6
|
+
subject { Tilt['handlebars'].new{ template }.render(context).gsub(/[\s\r\n]+/, ' ').strip }
|
7
|
+
|
8
|
+
let(:context) { double(:context) }
|
9
|
+
before(:all) do
|
10
|
+
FlavourSaver.register_helper(:sum) { |a,b| a + b}
|
11
|
+
end
|
12
|
+
context "simple subexpression" do
|
13
|
+
let(:template) { "{{sum 1 (sum 1 1)}}" }
|
14
|
+
specify{subject.should == "3"}
|
15
|
+
end
|
16
|
+
|
17
|
+
context "nested subexpressions" do
|
18
|
+
let(:template) { "{{sum 1 (sum 1 (sum 1 1))}}" }
|
19
|
+
specify{subject.should == "4"}
|
20
|
+
end
|
21
|
+
|
22
|
+
context "subexpression as argument" do
|
23
|
+
before {FlavourSaver.register_helper(:cents) { |a| a[:total] + 10}}
|
24
|
+
let(:template) { "{{cents total=(sum 1 1)}}" }
|
25
|
+
specify{subject.should == "12"}
|
26
|
+
end
|
27
|
+
|
28
|
+
context "subexpression in block" do
|
29
|
+
before {FlavourSaver.register_helper(:repeat) do |a, &block|
|
30
|
+
s = ''
|
31
|
+
a.times {s += block.call.contents}
|
32
|
+
s
|
33
|
+
end}
|
34
|
+
let(:template) { "{{#repeat (sum 1 2)}}*{{/repeat}}" }
|
35
|
+
specify{subject.should == "***"}
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -49,6 +49,18 @@ describe FlavourSaver::Lexer do
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
+
describe '{{foo (bar "baz")}}' do
|
53
|
+
subject { FlavourSaver::Lexer.lex "{{foo (bar 'baz')}}" }
|
54
|
+
|
55
|
+
it 'has tokens in the correct order' do
|
56
|
+
subject.map(&:type).should == [ :EXPRST, :IDENT, :WHITE, :OPAR, :IDENT, :WHITE, :S_STRING, :CPAR, :EXPRE, :EOS ]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'has values in the correct order' do
|
60
|
+
subject.map(&:value).compact.should == [ 'foo', 'bar', 'baz' ]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
52
64
|
describe '{{foo bar="baz" hello="goodbye"}}' do
|
53
65
|
subject { FlavourSaver::Lexer.lex '{{foo bar="baz" hello="goodbye"}}' }
|
54
66
|
|
@@ -63,6 +75,18 @@ describe FlavourSaver::Lexer do
|
|
63
75
|
end
|
64
76
|
end
|
65
77
|
|
78
|
+
describe '{{foo bar=(baz qux)}}' do
|
79
|
+
subject { FlavourSaver::Lexer.lex '{{foo bar=(baz qux)}}' }
|
80
|
+
|
81
|
+
it 'has tokens in the correct order' do
|
82
|
+
subject.map(&:type).should == [:EXPRST, :IDENT, :WHITE, :IDENT, :EQ, :OPAR, :IDENT, :WHITE, :IDENT, :CPAR, :EXPRE, :EOS]
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'has values in the correct order' do
|
86
|
+
subject.map(&:value).compact.should == [ 'foo', 'bar', 'baz', 'qux' ]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
66
90
|
describe '{{else}}' do
|
67
91
|
subject { FlavourSaver::Lexer.lex '{{else}}' }
|
68
92
|
|
@@ -143,6 +143,28 @@ describe FlavourSaver::Parser do
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
+
describe '{{foo (bar "baz") }}' do
|
147
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo (bar "baz") }}')) }
|
148
|
+
|
149
|
+
it 'calls the method "foo"' do
|
150
|
+
items.first.method.should be_one
|
151
|
+
items.first.method.first.should be_a(FlavourSaver::CallNode)
|
152
|
+
items.first.method.first.name.should == 'foo'
|
153
|
+
end
|
154
|
+
|
155
|
+
describe 'with arguments' do
|
156
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo (bar "baz") }}')).items.first.method.first.arguments }
|
157
|
+
|
158
|
+
describe '[0]' do
|
159
|
+
it 'is a subexpression' do
|
160
|
+
subject.first.first.should be_a(FlavourSaver::CallNode)
|
161
|
+
subject.first.first.name.should == 'bar'
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
146
168
|
describe '{{foo bar="baz"}}' do
|
147
169
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar="baz"}}')) }
|
148
170
|
|
@@ -154,6 +176,17 @@ describe FlavourSaver::Parser do
|
|
154
176
|
end
|
155
177
|
end
|
156
178
|
|
179
|
+
describe '{{foo bar=(baz "qux")}}' do
|
180
|
+
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar=(baz "qux")}}')) }
|
181
|
+
|
182
|
+
it 'calls the method "foo" with the hash {:bar => (baz "qux")} as arguments' do
|
183
|
+
items.first.method.first.should be_a(FlavourSaver::CallNode)
|
184
|
+
items.first.method.first.name.should == 'foo'
|
185
|
+
items.first.method.first.arguments.first.should be_a(Hash)
|
186
|
+
items.first.method.first.arguments.first[:bar].first.should be_a(FlavourSaver::CallNode)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
157
190
|
describe "{{foo bar=1}}" do
|
158
191
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex("{{foo bar=1}}")) }
|
159
192
|
|
@@ -110,6 +110,17 @@ describe FlavourSaver::Runtime do
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
+
describe 'when called with a subexpression' do
|
114
|
+
let(:template) { "{{hello (there world)}}" }
|
115
|
+
|
116
|
+
it 'calls there & world first, then passes off to hello' do
|
117
|
+
context.should_receive(:world).and_return('world')
|
118
|
+
context.should_receive(:there).with('world').and_return('there world')
|
119
|
+
context.should_receive(:hello).with('there world').and_return('hello there world')
|
120
|
+
subject.evaluate_expression(expr).should == 'hello there world'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
113
124
|
describe 'when called with an object path' do
|
114
125
|
let(:template) { "{{hello.world}}" }
|
115
126
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flavour_saver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Harton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -177,6 +177,7 @@ files:
|
|
177
177
|
- spec/acceptance/sections_spec.rb
|
178
178
|
- spec/acceptance/segment_literals_spec.rb
|
179
179
|
- spec/acceptance/simple_expression_spec.rb
|
180
|
+
- spec/acceptance/subexpression_spec.rb
|
180
181
|
- spec/fixtures/backtrack.hbs
|
181
182
|
- spec/fixtures/comment.hbs
|
182
183
|
- spec/fixtures/custom_block_helper.hbs
|
@@ -230,6 +231,7 @@ test_files:
|
|
230
231
|
- spec/acceptance/sections_spec.rb
|
231
232
|
- spec/acceptance/segment_literals_spec.rb
|
232
233
|
- spec/acceptance/simple_expression_spec.rb
|
234
|
+
- spec/acceptance/subexpression_spec.rb
|
233
235
|
- spec/fixtures/backtrack.hbs
|
234
236
|
- spec/fixtures/comment.hbs
|
235
237
|
- spec/fixtures/custom_block_helper.hbs
|