flavour_saver 0.3.7 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +26 -0
- data/CHANGELOG.md +23 -0
- data/Gemfile.lock +34 -62
- data/README.md +34 -11
- data/flavour_saver.gemspec +14 -9
- data/lib/flavour_saver/helpers.rb +6 -5
- data/lib/flavour_saver/lexer.rb +18 -5
- data/lib/flavour_saver/nodes.rb +1 -1
- data/lib/flavour_saver/parser.rb +7 -2
- data/lib/flavour_saver/runtime.rb +6 -6
- data/lib/flavour_saver/version.rb +1 -1
- data/spec/acceptance/backtrack_spec.rb +1 -1
- data/spec/acceptance/comment_spec.rb +1 -1
- data/spec/acceptance/custom_block_helper_spec.rb +2 -2
- data/spec/acceptance/custom_helper_spec.rb +1 -1
- data/spec/acceptance/ensure_no_rce_spec.rb +2 -2
- data/spec/acceptance/handlebars_qunit_spec.rb +236 -214
- data/spec/acceptance/if_else_spec.rb +2 -2
- data/spec/acceptance/multi_level_with_spec.rb +1 -1
- data/spec/acceptance/one_character_identifier_spec.rb +2 -2
- data/spec/acceptance/raw_block_spec.rb +1 -1
- data/spec/acceptance/runtime_run_spec.rb +1 -1
- data/spec/acceptance/sections_spec.rb +3 -3
- data/spec/acceptance/segment_literals_spec.rb +3 -3
- data/spec/acceptance/simple_expression_spec.rb +3 -3
- data/spec/acceptance/subexpression_spec.rb +37 -0
- data/spec/lib/flavour_saver/lexer_spec.rb +73 -28
- data/spec/lib/flavour_saver/parser_spec.rb +115 -82
- data/spec/lib/flavour_saver/runtime_spec.rb +44 -33
- metadata +26 -75
- data/.travis.yml +0 -14
- data/Guardfile +0 -12
|
@@ -8,10 +8,10 @@ describe 'Fixture: if_else.hbs' do
|
|
|
8
8
|
|
|
9
9
|
it 'renders correctly when given a name' do
|
|
10
10
|
context.name = 'Alan'
|
|
11
|
-
subject.
|
|
11
|
+
expect(subject).to eq "Say hello to Alan."
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
it 'renders correctly when not given a name' do
|
|
15
|
-
subject.
|
|
15
|
+
expect(subject).to eq "Nobody to say hi to."
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -9,7 +9,7 @@ describe 'Fixture: multi_level_with.hbs' do
|
|
|
9
9
|
it 'renders correctly when person has a name' do
|
|
10
10
|
context.person = Struct.new(:name).new('Alan')
|
|
11
11
|
context.company = Struct.new(:name).new('Rad, Inc.')
|
|
12
|
-
subject.
|
|
12
|
+
expect(subject).to eq 'Alan - Rad, Inc.'
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
end
|
|
@@ -7,7 +7,7 @@ describe 'Fixture: one_character_identifier.hbs' do
|
|
|
7
7
|
let(:context) { double(:context) }
|
|
8
8
|
|
|
9
9
|
it 'renders correctly' do
|
|
10
|
-
context.
|
|
11
|
-
subject.
|
|
10
|
+
expect(context).to receive(:a).and_return('foo')
|
|
11
|
+
expect(subject).to eq "foo"
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -8,18 +8,18 @@ describe 'Fixture: sections.hbs' do
|
|
|
8
8
|
|
|
9
9
|
it 'renders correctly when given a name' do
|
|
10
10
|
context.name = 'Alan'
|
|
11
|
-
subject.
|
|
11
|
+
expect(subject).to eq "Say hello to Alan."
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
it 'renders correctly when given a list of names' do
|
|
15
15
|
context.names = ['Foo', 'Bar']
|
|
16
|
-
subject.
|
|
16
|
+
expect(subject).to eq "* Foo * Bar"
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
it 'renders correctly when given an order' do
|
|
20
20
|
class Order; def number; 1234; end; end
|
|
21
21
|
context.order = Order.new
|
|
22
|
-
subject.
|
|
22
|
+
expect(subject).to eq 'Number: 1234'
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
@@ -17,10 +17,10 @@ describe FlavourSaver do
|
|
|
17
17
|
foos = []
|
|
18
18
|
foos << double(:foo)
|
|
19
19
|
foos << double(:foo)
|
|
20
|
-
foos[1].
|
|
20
|
+
expect(foos[1]).to receive(:bar).and_return('two')
|
|
21
21
|
|
|
22
|
-
context.
|
|
23
|
-
subject.
|
|
22
|
+
allow(context).to receive(:foos).and_return(foos)
|
|
23
|
+
expect(subject).to eq 'two'
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
end
|
|
@@ -7,11 +7,11 @@ describe 'Fixture: simple_expression.hbs' do
|
|
|
7
7
|
let(:context) { double(:context) }
|
|
8
8
|
|
|
9
9
|
it 'renders correctly' do
|
|
10
|
-
context.
|
|
11
|
-
subject.
|
|
10
|
+
expect(context).to receive(:hello).and_return('hello world')
|
|
11
|
+
expect(subject).to eq "hello world"
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
it 'renders nothing if undefined' do
|
|
15
|
-
subject.
|
|
15
|
+
expect(subject).to eq ""
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
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{expect(subject).to eq "3"}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
context "nested subexpressions" do
|
|
18
|
+
let(:template) { "{{sum 1 (sum 1 (sum 1 1))}}" }
|
|
19
|
+
specify{expect(subject).to eq "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{expect(subject).to eq "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{expect(subject).to eq "***"}
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -2,7 +2,7 @@ require 'flavour_saver/lexer'
|
|
|
2
2
|
|
|
3
3
|
describe FlavourSaver::Lexer do
|
|
4
4
|
it 'is an RLTK lexer' do
|
|
5
|
-
subject.
|
|
5
|
+
expect(subject).to be_a(RLTK::Lexer)
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
describe 'Tokens' do
|
|
@@ -11,17 +11,17 @@ describe FlavourSaver::Lexer do
|
|
|
11
11
|
subject { FlavourSaver::Lexer.lex "{{foo}}" }
|
|
12
12
|
|
|
13
13
|
it 'begins with an EXPRST' do
|
|
14
|
-
subject.first.type.
|
|
14
|
+
expect(subject.first.type).to eq :EXPRST
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
it 'ends with an EXPRE' do
|
|
18
|
-
subject[-2].type.
|
|
18
|
+
expect(subject[-2].type).to eq :EXPRE
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
it 'contains only the identifier "foo"' do
|
|
22
|
-
subject[1..-3].size.
|
|
23
|
-
subject[1].type.
|
|
24
|
-
subject[1].value.
|
|
22
|
+
expect(subject[1..-3].size).to eq 1
|
|
23
|
+
expect(subject[1].type).to eq :IDENT
|
|
24
|
+
expect(subject[1].value).to eq 'foo'
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -29,11 +29,11 @@ describe FlavourSaver::Lexer do
|
|
|
29
29
|
subject { FlavourSaver::Lexer.lex "{{foo bar}}" }
|
|
30
30
|
|
|
31
31
|
it 'has tokens in the correct order' do
|
|
32
|
-
subject.map(&:type).
|
|
32
|
+
expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :WHITE, :IDENT, :EXPRE, :EOS ]
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it 'has values in the correct order' do
|
|
36
|
-
subject.map(&:value).compact.
|
|
36
|
+
expect(subject.map(&:value).compact).to eq [ 'foo', 'bar' ]
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -41,11 +41,23 @@ describe FlavourSaver::Lexer do
|
|
|
41
41
|
subject { FlavourSaver::Lexer.lex "{{foo \"bar\"}}" }
|
|
42
42
|
|
|
43
43
|
it 'has tokens in the correct order' do
|
|
44
|
-
subject.map(&:type).
|
|
44
|
+
expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :WHITE, :STRING, :EXPRE, :EOS ]
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
it 'has values in the correct order' do
|
|
48
|
-
subject.map(&:value).compact.
|
|
48
|
+
expect(subject.map(&:value).compact).to eq [ 'foo', 'bar' ]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
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
|
+
expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :WHITE, :OPAR, :IDENT, :WHITE, :S_STRING, :CPAR, :EXPRE, :EOS ]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'has values in the correct order' do
|
|
60
|
+
expect(subject.map(&:value).compact).to eq [ 'foo', 'bar', 'baz' ]
|
|
49
61
|
end
|
|
50
62
|
end
|
|
51
63
|
|
|
@@ -53,21 +65,54 @@ describe FlavourSaver::Lexer do
|
|
|
53
65
|
subject { FlavourSaver::Lexer.lex '{{foo bar="baz" hello="goodbye"}}' }
|
|
54
66
|
|
|
55
67
|
it 'has tokens in the correct order' do
|
|
56
|
-
subject.map(&:type).
|
|
68
|
+
expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :WHITE, :IDENT, :EQ, :STRING, :WHITE, :IDENT, :EQ, :STRING, :EXPRE, :EOS ]
|
|
57
69
|
end
|
|
58
70
|
|
|
59
71
|
it 'has values in the correct order' do
|
|
60
|
-
subject.map(&:value).compact.
|
|
72
|
+
expect(subject.map(&:value).compact).to eq [ 'foo', 'bar', 'baz', 'hello', 'goodbye' ]
|
|
61
73
|
end
|
|
62
74
|
|
|
63
75
|
end
|
|
64
76
|
end
|
|
65
77
|
|
|
78
|
+
describe 'Identities' do
|
|
79
|
+
|
|
80
|
+
it 'supports as ruby methods' do
|
|
81
|
+
ids = %w( _ __ __123__ __ABC__ ABC123 Abc134def )
|
|
82
|
+
ids.each do |id|
|
|
83
|
+
subject = FlavourSaver::Lexer.lex "{{#{id}}}"
|
|
84
|
+
expect(subject[1].type).to eq :IDENT
|
|
85
|
+
expect(subject[1].value).to eq id
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'maps non-ruby identities to literals' do
|
|
90
|
+
ids = %w( A-B 12_Mine - :example 0A test? )
|
|
91
|
+
ids.each do |id|
|
|
92
|
+
subject = FlavourSaver::Lexer.lex "{{#{id}}}"
|
|
93
|
+
expect(subject[1].type).to eq :LITERAL
|
|
94
|
+
expect(subject[1].value).to eq id
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
describe '{{foo bar=(baz qux)}}' do
|
|
100
|
+
subject { FlavourSaver::Lexer.lex '{{foo bar=(baz qux)}}' }
|
|
101
|
+
|
|
102
|
+
it 'has tokens in the correct order' do
|
|
103
|
+
expect(subject.map(&:type)).to eq [:EXPRST, :IDENT, :WHITE, :IDENT, :EQ, :OPAR, :IDENT, :WHITE, :IDENT, :CPAR, :EXPRE, :EOS]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'has values in the correct order' do
|
|
107
|
+
expect(subject.map(&:value).compact).to eq [ 'foo', 'bar', 'baz', 'qux' ]
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
66
111
|
describe '{{else}}' do
|
|
67
112
|
subject { FlavourSaver::Lexer.lex '{{else}}' }
|
|
68
113
|
|
|
69
114
|
it 'has tokens in the correct order' do
|
|
70
|
-
subject.map(&:type).
|
|
115
|
+
expect(subject.map(&:type)).to eq [ :EXPRST, :ELSE, :EXPRE, :EOS ]
|
|
71
116
|
end
|
|
72
117
|
end
|
|
73
118
|
|
|
@@ -76,11 +121,11 @@ describe FlavourSaver::Lexer do
|
|
|
76
121
|
subject { FlavourSaver::Lexer.lex "{{foo.bar}}" }
|
|
77
122
|
|
|
78
123
|
it 'has tokens in the correct order' do
|
|
79
|
-
subject.map(&:type).
|
|
124
|
+
expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :DOT, :IDENT, :EXPRE, :EOS ]
|
|
80
125
|
end
|
|
81
126
|
|
|
82
127
|
it 'has the correct values' do
|
|
83
|
-
subject.map(&:value).compact.
|
|
128
|
+
expect(subject.map(&:value).compact).to eq ['foo', 'bar']
|
|
84
129
|
end
|
|
85
130
|
end
|
|
86
131
|
|
|
@@ -88,11 +133,11 @@ describe FlavourSaver::Lexer do
|
|
|
88
133
|
subject { FlavourSaver::Lexer.lex "{{foo.[10].bar}}" }
|
|
89
134
|
|
|
90
135
|
it 'has tokens in the correct order' do
|
|
91
|
-
subject.map(&:type).
|
|
136
|
+
expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :DOT, :LITERAL, :DOT, :IDENT, :EXPRE, :EOS ]
|
|
92
137
|
end
|
|
93
138
|
|
|
94
139
|
it 'has the correct values' do
|
|
95
|
-
subject.map(&:value).compact.
|
|
140
|
+
expect(subject.map(&:value).compact).to eq ['foo', '10', 'bar']
|
|
96
141
|
end
|
|
97
142
|
end
|
|
98
143
|
|
|
@@ -100,11 +145,11 @@ describe FlavourSaver::Lexer do
|
|
|
100
145
|
subject { FlavourSaver::Lexer.lex '{{foo.[he!@#$(&@klA)].bar}}' }
|
|
101
146
|
|
|
102
147
|
it 'has tokens in the correct order' do
|
|
103
|
-
subject.map(&:type).
|
|
148
|
+
expect(subject.map(&:type)).to eq [ :EXPRST, :IDENT, :DOT, :LITERAL, :DOT, :IDENT, :EXPRE, :EOS ]
|
|
104
149
|
end
|
|
105
150
|
|
|
106
151
|
it 'has the correct values' do
|
|
107
|
-
subject.map(&:value).compact.
|
|
152
|
+
expect(subject.map(&:value).compact).to eq ['foo', 'he!@#$(&@klA)', 'bar']
|
|
108
153
|
end
|
|
109
154
|
end
|
|
110
155
|
end
|
|
@@ -113,7 +158,7 @@ describe FlavourSaver::Lexer do
|
|
|
113
158
|
subject { FlavourSaver::Lexer.lex "{{{foo}}}" }
|
|
114
159
|
|
|
115
160
|
it 'has tokens in the correct order' do
|
|
116
|
-
subject.map(&:type).
|
|
161
|
+
expect(subject.map(&:type)).to eq [ :TEXPRST, :IDENT, :TEXPRE, :EOS ]
|
|
117
162
|
end
|
|
118
163
|
end
|
|
119
164
|
|
|
@@ -121,7 +166,7 @@ describe FlavourSaver::Lexer do
|
|
|
121
166
|
subject { FlavourSaver::Lexer.lex "{{! WAT}}" }
|
|
122
167
|
|
|
123
168
|
it 'has tokens in the correct order' do
|
|
124
|
-
subject.map(&:type).
|
|
169
|
+
expect(subject.map(&:type)).to eq [ :EXPRST, :BANG, :COMMENT, :EXPRE, :EOS ]
|
|
125
170
|
end
|
|
126
171
|
end
|
|
127
172
|
|
|
@@ -129,7 +174,7 @@ describe FlavourSaver::Lexer do
|
|
|
129
174
|
subject { FlavourSaver::Lexer.lex "{{../foo}}" }
|
|
130
175
|
|
|
131
176
|
it 'has tokens in the correct order' do
|
|
132
|
-
subject.map(&:type).
|
|
177
|
+
expect(subject.map(&:type)).to eq [:EXPRST, :DOT, :DOT, :FWSL, :IDENT, :EXPRE, :EOS]
|
|
133
178
|
end
|
|
134
179
|
end
|
|
135
180
|
|
|
@@ -137,7 +182,7 @@ describe FlavourSaver::Lexer do
|
|
|
137
182
|
subject { FlavourSaver::Lexer.lex "{{foo}}\n{{bar}}\r{{baz}}" }
|
|
138
183
|
|
|
139
184
|
it 'has tokens in the correct order' do
|
|
140
|
-
subject.map(&:type).
|
|
185
|
+
expect(subject.map(&:type)).to eq [:EXPRST,:IDENT,:EXPRE,:OUT,:EXPRST,:IDENT,:EXPRE,:OUT,:EXPRST,:IDENT,:EXPRE,:EOS]
|
|
141
186
|
end
|
|
142
187
|
end
|
|
143
188
|
|
|
@@ -146,7 +191,7 @@ describe FlavourSaver::Lexer do
|
|
|
146
191
|
|
|
147
192
|
describe '{{#foo}}{{bar}}{{/foo}}' do
|
|
148
193
|
it 'has tokens in the correct order' do
|
|
149
|
-
subject.map(&:type).
|
|
194
|
+
expect(subject.map(&:type)).to eq [
|
|
150
195
|
:EXPRST, :HASH, :IDENT, :EXPRE,
|
|
151
196
|
:EXPRST, :IDENT, :EXPRE,
|
|
152
197
|
:EXPRST, :FWSL, :IDENT, :EXPRE,
|
|
@@ -155,7 +200,7 @@ describe FlavourSaver::Lexer do
|
|
|
155
200
|
end
|
|
156
201
|
|
|
157
202
|
it 'has identifiers in the correct order' do
|
|
158
|
-
subject.map(&:value).compact.
|
|
203
|
+
expect(subject.map(&:value).compact).to eq [ 'foo', 'bar', 'foo' ]
|
|
159
204
|
end
|
|
160
205
|
end
|
|
161
206
|
end
|
|
@@ -164,7 +209,7 @@ describe FlavourSaver::Lexer do
|
|
|
164
209
|
subject { FlavourSaver::Lexer.lex "\r" }
|
|
165
210
|
|
|
166
211
|
it 'has tokens in the correct order' do
|
|
167
|
-
subject.map(&:type).
|
|
212
|
+
expect(subject.map(&:type)).to eq [:OUT,:EOS]
|
|
168
213
|
end
|
|
169
214
|
end
|
|
170
215
|
|
|
@@ -172,7 +217,7 @@ describe FlavourSaver::Lexer do
|
|
|
172
217
|
subject { FlavourSaver::Lexer.lex "\n" }
|
|
173
218
|
|
|
174
219
|
it 'has tokens in the correct order' do
|
|
175
|
-
subject.map(&:type).
|
|
220
|
+
expect(subject.map(&:type)).to eq [:OUT,:EOS]
|
|
176
221
|
end
|
|
177
222
|
end
|
|
178
223
|
|
|
@@ -180,7 +225,7 @@ describe FlavourSaver::Lexer do
|
|
|
180
225
|
subject { FlavourSaver::Lexer.lex "{" }
|
|
181
226
|
|
|
182
227
|
it 'has tokens in the correct order' do
|
|
183
|
-
subject.map(&:type).
|
|
228
|
+
expect(subject.map(&:type)).to eq [:OUT,:EOS]
|
|
184
229
|
end
|
|
185
230
|
end
|
|
186
231
|
end
|