flavour_saver 0.3.7 → 2.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 +47 -0
- data/CHANGELOG.md +40 -0
- data/Gemfile.lock +34 -62
- data/README.md +34 -11
- data/flavour_saver.gemspec +14 -9
- data/lib/flavour_saver/helpers.rb +28 -13
- data/lib/flavour_saver/lexer.rb +19 -6
- data/lib/flavour_saver/nodes.rb +1 -1
- data/lib/flavour_saver/parser.rb +8 -7
- data/lib/flavour_saver/runtime.rb +8 -8
- 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 +299 -214
- data/spec/acceptance/if_else_spec.rb +37 -6
- 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/acceptance/unless_spec.rb +48 -0
- data/spec/fixtures/if_else.hbs +3 -3
- data/spec/fixtures/unless.hbs +5 -0
- data/spec/lib/flavour_saver/lexer_spec.rb +104 -28
- data/spec/lib/flavour_saver/parser_spec.rb +115 -82
- data/spec/lib/flavour_saver/runtime_spec.rb +44 -33
- metadata +27 -72
- data/.travis.yml +0 -14
- data/Guardfile +0 -12
@@ -5,18 +5,18 @@ describe FlavourSaver::Parser do
|
|
5
5
|
let (:items) { subject.items }
|
6
6
|
|
7
7
|
it 'is a RLTK::Parser' do
|
8
|
-
subject.
|
8
|
+
expect(subject).to be_a(RLTK::Parser)
|
9
9
|
end
|
10
10
|
|
11
11
|
describe 'HTML template' do
|
12
12
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('<html><h1>Hello world!</h1></html>')) }
|
13
13
|
|
14
14
|
it 'is an output node' do
|
15
|
-
items.first.
|
15
|
+
expect(items.first).to be_a(FlavourSaver::OutputNode)
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'has the correct contents' do
|
19
|
-
items.first.value.
|
19
|
+
expect(items.first.value).to eq '<html><h1>Hello world!</h1></html>'
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -24,7 +24,7 @@ describe FlavourSaver::Parser do
|
|
24
24
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('<html>{{foo}}</html>')) }
|
25
25
|
|
26
26
|
it 'has template output either side of the expression' do
|
27
|
-
items.map(&:class).
|
27
|
+
expect(items.map(&:class)).to eq [FlavourSaver::OutputNode, FlavourSaver::ExpressionNode, FlavourSaver::OutputNode]
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -32,14 +32,14 @@ describe FlavourSaver::Parser do
|
|
32
32
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo}}')) }
|
33
33
|
|
34
34
|
it 'contains an expression node' do
|
35
|
-
items.first.
|
35
|
+
expect(items.first).to be_a(FlavourSaver::ExpressionNode)
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'calls the method "foo" with no arguments' do
|
39
|
-
items.first.method.
|
40
|
-
items.first.method.first.
|
41
|
-
items.first.method.first.name.
|
42
|
-
items.first.method.first.arguments.
|
39
|
+
expect(items.first.method).to be_one
|
40
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
41
|
+
expect(items.first.method.first.name).to eq 'foo'
|
42
|
+
expect(items.first.method.first.arguments).to be_empty
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
@@ -47,19 +47,19 @@ describe FlavourSaver::Parser do
|
|
47
47
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo.bar}}')) }
|
48
48
|
|
49
49
|
it 'calls two methods' do
|
50
|
-
items.first.method.size.
|
50
|
+
expect(items.first.method.size).to eq 2
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'calls the method "foo" with no arguments first' do
|
54
|
-
items.first.method.first.
|
55
|
-
items.first.method.first.name.
|
56
|
-
items.first.method.first.arguments.
|
54
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
55
|
+
expect(items.first.method.first.name).to eq 'foo'
|
56
|
+
expect(items.first.method.first.arguments).to be_empty
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'calls the method "bar" with no arguments second' do
|
60
|
-
items.first.method[1].
|
61
|
-
items.first.method[1].name.
|
62
|
-
items.first.method[1].arguments.
|
60
|
+
expect(items.first.method[1]).to be_a(FlavourSaver::CallNode)
|
61
|
+
expect(items.first.method[1].name).to eq 'bar'
|
62
|
+
expect(items.first.method[1].arguments).to be_empty
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -67,25 +67,25 @@ describe FlavourSaver::Parser do
|
|
67
67
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo.[&@^$*].bar}}')) }
|
68
68
|
|
69
69
|
it 'calls three methods' do
|
70
|
-
items.first.method.size.
|
70
|
+
expect(items.first.method.size).to eq 3
|
71
71
|
end
|
72
72
|
|
73
73
|
it 'calls the method "foo" with no arguments first' do
|
74
|
-
items.first.method.first.
|
75
|
-
items.first.method.first.name.
|
76
|
-
items.first.method.first.arguments.
|
74
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
75
|
+
expect(items.first.method.first.name).to eq 'foo'
|
76
|
+
expect(items.first.method.first.arguments).to be_empty
|
77
77
|
end
|
78
78
|
|
79
79
|
it 'calls the method "&@^$*" with no arguments second' do
|
80
|
-
items.first.method[1].
|
81
|
-
items.first.method[1].name.
|
82
|
-
items.first.method[1].arguments.
|
80
|
+
expect(items.first.method[1]).to be_a(FlavourSaver::CallNode)
|
81
|
+
expect(items.first.method[1].name).to eq '&@^$*'
|
82
|
+
expect(items.first.method[1].arguments).to be_empty
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'calls the method "bar" with no arguments third' do
|
86
|
-
items.first.method[2].
|
87
|
-
items.first.method[2].name.
|
88
|
-
items.first.method[2].arguments.
|
86
|
+
expect(items.first.method[2]).to be_a(FlavourSaver::CallNode)
|
87
|
+
expect(items.first.method[2].name).to eq 'bar'
|
88
|
+
expect(items.first.method[2].arguments).to be_empty
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
@@ -93,12 +93,12 @@ describe FlavourSaver::Parser do
|
|
93
93
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar}}')) }
|
94
94
|
|
95
95
|
it 'calls the method "foo" with a method argument of "bar"' do
|
96
|
-
items.first.method.
|
97
|
-
items.first.method.first.
|
98
|
-
items.first.method.first.name.
|
99
|
-
items.first.method.first.arguments.
|
100
|
-
items.first.method.first.arguments.first.first.
|
101
|
-
items.first.method.first.arguments.first.first.name.
|
96
|
+
expect(items.first.method).to be_one
|
97
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
98
|
+
expect(items.first.method.first.name).to eq 'foo'
|
99
|
+
expect(items.first.method.first.arguments).to be_one
|
100
|
+
expect(items.first.method.first.arguments.first.first).to be_a(FlavourSaver::CallNode)
|
101
|
+
expect(items.first.method.first.arguments.first.first.name).to eq 'bar'
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
@@ -106,12 +106,12 @@ describe FlavourSaver::Parser do
|
|
106
106
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo "bar" }}')) }
|
107
107
|
|
108
108
|
it 'calls the method "foo" with a string argument of "bar"' do
|
109
|
-
items.first.method.
|
110
|
-
items.first.method.first.
|
111
|
-
items.first.method.first.name.
|
112
|
-
items.first.method.first.arguments.
|
113
|
-
items.first.method.first.arguments.first.
|
114
|
-
items.first.method.first.arguments.first.value.
|
109
|
+
expect(items.first.method).to be_one
|
110
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
111
|
+
expect(items.first.method.first.name).to eq 'foo'
|
112
|
+
expect(items.first.method.first.arguments).to be_one
|
113
|
+
expect(items.first.method.first.arguments.first).to be_a(FlavourSaver::StringNode)
|
114
|
+
expect(items.first.method.first.arguments.first.value).to eq 'bar'
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
@@ -119,9 +119,9 @@ describe FlavourSaver::Parser do
|
|
119
119
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar "baz" }}')) }
|
120
120
|
|
121
121
|
it 'calls the method "foo"' do
|
122
|
-
items.first.method.
|
123
|
-
items.first.method.first.
|
124
|
-
items.first.method.first.name.
|
122
|
+
expect(items.first.method).to be_one
|
123
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
124
|
+
expect(items.first.method.first.name).to eq 'foo'
|
125
125
|
end
|
126
126
|
|
127
127
|
describe 'with arguments' do
|
@@ -129,28 +129,61 @@ describe FlavourSaver::Parser do
|
|
129
129
|
|
130
130
|
describe '[0]' do
|
131
131
|
it 'is the method call "bar" with no arguments' do
|
132
|
-
subject.first.first.
|
133
|
-
subject.first.first.name.
|
132
|
+
expect(subject.first.first).to be_a(FlavourSaver::CallNode)
|
133
|
+
expect(subject.first.first.name).to eq 'bar'
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
137
137
|
describe '[1]' do
|
138
138
|
it 'is the string "baz"' do
|
139
|
-
subject[1].
|
140
|
-
subject[1].value.
|
139
|
+
expect(subject[1]).to be_a(FlavourSaver::StringNode)
|
140
|
+
expect(subject[1].value).to eq 'baz'
|
141
141
|
end
|
142
142
|
end
|
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
|
+
expect(items.first.method).to be_one
|
151
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
152
|
+
expect(items.first.method.first.name).to eq '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
|
+
expect(subject.first.first).to be_a(FlavourSaver::CallNode)
|
161
|
+
expect(subject.first.first.name).to eq '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
|
|
149
171
|
it 'calls the method "foo" with the hash {:bar => "baz"} as arguments' do
|
150
|
-
items.first.method.first.
|
151
|
-
items.first.method.first.name.
|
152
|
-
items.first.method.first.arguments.first.
|
153
|
-
items.first.method.first.arguments.first.
|
172
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
173
|
+
expect(items.first.method.first.name).to eq 'foo'
|
174
|
+
expect(items.first.method.first.arguments.first).to be_a(Hash)
|
175
|
+
expect(items.first.method.first.arguments.first).to eq({ :bar => FlavourSaver::StringNode.new('baz') })
|
176
|
+
end
|
177
|
+
end
|
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
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
184
|
+
expect(items.first.method.first.name).to eq 'foo'
|
185
|
+
expect(items.first.method.first.arguments.first).to be_a(Hash)
|
186
|
+
expect(items.first.method.first.arguments.first[:bar].first).to be_a(FlavourSaver::CallNode)
|
154
187
|
end
|
155
188
|
end
|
156
189
|
|
@@ -158,14 +191,14 @@ describe FlavourSaver::Parser do
|
|
158
191
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex("{{foo bar=1}}")) }
|
159
192
|
|
160
193
|
it "doesn't throw a NotInLanguage exception" do
|
161
|
-
|
194
|
+
expect { subject }.to_not raise_error
|
162
195
|
end
|
163
196
|
|
164
197
|
it 'calls the method "foo" with the hash {:bar => 1} as arguments' do
|
165
|
-
items.first.method.first.
|
166
|
-
items.first.method.first.name.
|
167
|
-
items.first.method.first.arguments.first.
|
168
|
-
items.first.method.first.arguments.first.
|
198
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
199
|
+
expect(items.first.method.first.name).to eq 'foo'
|
200
|
+
expect(items.first.method.first.arguments.first).to be_a(Hash)
|
201
|
+
expect(items.first.method.first.arguments.first).to eq({ :bar => FlavourSaver::NumberNode.new('1') })
|
169
202
|
end
|
170
203
|
end
|
171
204
|
|
@@ -173,10 +206,10 @@ describe FlavourSaver::Parser do
|
|
173
206
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar="baz" fred="wilma"}}')) }
|
174
207
|
|
175
208
|
it 'calls the method "foo" with the hash {:bar => "baz", :fred => "wilma"} as arguments' do
|
176
|
-
items.first.method.first.
|
177
|
-
items.first.method.first.name.
|
178
|
-
items.first.method.first.arguments.first.
|
179
|
-
items.first.method.first.arguments.first.
|
209
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
210
|
+
expect(items.first.method.first.name).to eq 'foo'
|
211
|
+
expect(items.first.method.first.arguments.first).to be_a(Hash)
|
212
|
+
expect(items.first.method.first.arguments.first).to eq({ :bar => FlavourSaver::StringNode.new('baz'), :fred => FlavourSaver::StringNode.new('wilma') })
|
180
213
|
end
|
181
214
|
end
|
182
215
|
|
@@ -184,7 +217,7 @@ describe FlavourSaver::Parser do
|
|
184
217
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo bar="baz" fred "wilma"}}')) }
|
185
218
|
|
186
219
|
it 'raises an exception' do
|
187
|
-
|
220
|
+
expect { subject }.to raise_exception(RLTK::NotInLanguage)
|
188
221
|
end
|
189
222
|
end
|
190
223
|
|
@@ -192,7 +225,7 @@ describe FlavourSaver::Parser do
|
|
192
225
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{{foo}}}')) }
|
193
226
|
|
194
227
|
it 'returns a safe expression node' do
|
195
|
-
items.first.
|
228
|
+
expect(items.first).to be_a(FlavourSaver::SafeExpressionNode)
|
196
229
|
end
|
197
230
|
end
|
198
231
|
|
@@ -200,7 +233,7 @@ describe FlavourSaver::Parser do
|
|
200
233
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{../foo}}')) }
|
201
234
|
|
202
235
|
it 'returns a parent call node' do
|
203
|
-
items.first.method.first.
|
236
|
+
expect(items.first.method.first).to be_a(FlavourSaver::ParentCallNode)
|
204
237
|
end
|
205
238
|
end
|
206
239
|
|
@@ -208,7 +241,7 @@ describe FlavourSaver::Parser do
|
|
208
241
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{! comment}}')) }
|
209
242
|
|
210
243
|
it 'returns a comment node' do
|
211
|
-
items.first.
|
244
|
+
expect(items.first).to be_a(FlavourSaver::CommentNode)
|
212
245
|
end
|
213
246
|
end
|
214
247
|
|
@@ -216,14 +249,14 @@ describe FlavourSaver::Parser do
|
|
216
249
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{#foo}}hello{{/foo}}')) }
|
217
250
|
|
218
251
|
it 'has a block start and end' do
|
219
|
-
items.map(&:class).
|
252
|
+
expect(items.map(&:class)).to eq [ FlavourSaver::BlockExpressionNode ]
|
220
253
|
end
|
221
254
|
|
222
255
|
describe '#contents' do
|
223
256
|
it 'contains a single output node' do
|
224
|
-
items.first.contents.items.size.
|
225
|
-
items.first.contents.items.first.
|
226
|
-
items.first.contents.items.first.value.
|
257
|
+
expect(items.first.contents.items.size).to eq 1
|
258
|
+
expect(items.first.contents.items.first).to be_a(FlavourSaver::OutputNode)
|
259
|
+
expect(items.first.contents.items.first.value).to eq 'hello'
|
227
260
|
end
|
228
261
|
end
|
229
262
|
end
|
@@ -232,7 +265,7 @@ describe FlavourSaver::Parser do
|
|
232
265
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{/foo}}')) }
|
233
266
|
|
234
267
|
it 'raises a syntax error' do
|
235
|
-
|
268
|
+
expect { subject }.to raise_error(RLTK::NotInLanguage)
|
236
269
|
end
|
237
270
|
end
|
238
271
|
|
@@ -240,7 +273,7 @@ describe FlavourSaver::Parser do
|
|
240
273
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{#foo}}')) }
|
241
274
|
|
242
275
|
it 'raises a syntax error' do
|
243
|
-
|
276
|
+
expect { subject }.to raise_error(RLTK::NotInLanguage)
|
244
277
|
end
|
245
278
|
end
|
246
279
|
|
@@ -248,7 +281,7 @@ describe FlavourSaver::Parser do
|
|
248
281
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex("{{foo}}\n")) }
|
249
282
|
|
250
283
|
it 'has a block start and end' do
|
251
|
-
items.map(&:class).
|
284
|
+
expect(items.map(&:class)).to eq [ FlavourSaver::ExpressionNode, FlavourSaver::OutputNode ]
|
252
285
|
end
|
253
286
|
end
|
254
287
|
|
@@ -256,7 +289,7 @@ describe FlavourSaver::Parser do
|
|
256
289
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{#foo}}{{#bar}}{{/foo}}')) }
|
257
290
|
|
258
291
|
it 'raises a syntax error' do
|
259
|
-
|
292
|
+
expect { subject }.to raise_error(FlavourSaver::Parser::UnbalancedBlockError)
|
260
293
|
end
|
261
294
|
end
|
262
295
|
|
@@ -264,7 +297,7 @@ describe FlavourSaver::Parser do
|
|
264
297
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex("{{#foo}}\n{{/foo}}")) }
|
265
298
|
|
266
299
|
it "doesn't throw a NotInLanguage exception" do
|
267
|
-
|
300
|
+
expect { subject }.to_not raise_error
|
268
301
|
end
|
269
302
|
end
|
270
303
|
|
@@ -275,8 +308,8 @@ describe FlavourSaver::Parser do
|
|
275
308
|
let(:block) { subject.items.first }
|
276
309
|
|
277
310
|
it 'should contain another block' do
|
278
|
-
block.contents.items.size.
|
279
|
-
block.contents.items.first.
|
311
|
+
expect(block.contents.items.size).to eq 1
|
312
|
+
expect(block.contents.items.first).to be_a(FlavourSaver::BlockExpressionNode)
|
280
313
|
end
|
281
314
|
end
|
282
315
|
end
|
@@ -285,7 +318,7 @@ describe FlavourSaver::Parser do
|
|
285
318
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex("{{#foo bar 'baz'}}{{/foo}}")) }
|
286
319
|
|
287
320
|
it "doesn't throw a NotInLanguage exception" do
|
288
|
-
|
321
|
+
expect { subject }.to_not raise_error
|
289
322
|
end
|
290
323
|
end
|
291
324
|
|
@@ -293,25 +326,25 @@ describe FlavourSaver::Parser do
|
|
293
326
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex("{{#foo bar 'baz' }}{{/foo}}")) }
|
294
327
|
|
295
328
|
it "doesn't throw a NotInLanguage exception" do
|
296
|
-
|
329
|
+
expect { subject }.to_not raise_error
|
297
330
|
end
|
298
331
|
end
|
299
332
|
describe '' do
|
300
333
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('')) }
|
301
334
|
|
302
335
|
it 'returns an empty template' do
|
303
|
-
items.
|
336
|
+
expect(items).to be_empty
|
304
337
|
end
|
305
338
|
end
|
306
339
|
describe '{{foo "bar" fred="wilma"}}' do
|
307
340
|
subject { FlavourSaver::Parser.parse(FlavourSaver::Lexer.lex('{{foo "bar" fred="wilma"}}')) }
|
308
341
|
it 'calls the method "foo" with the "bar" and {:fred => "wilma"} as arguments' do
|
309
|
-
items.first.method.first.
|
310
|
-
items.first.method.first.name.
|
311
|
-
items.first.method.first.arguments.first.
|
312
|
-
items.first.method.first.arguments.first.value.
|
313
|
-
items.first.method.first.arguments.last.
|
314
|
-
items.first.method.first.arguments.last.
|
342
|
+
expect(items.first.method.first).to be_a(FlavourSaver::CallNode)
|
343
|
+
expect(items.first.method.first.name).to eq 'foo'
|
344
|
+
expect(items.first.method.first.arguments.first).to be_a(FlavourSaver::StringNode)
|
345
|
+
expect(items.first.method.first.arguments.first.value).to eq 'bar'
|
346
|
+
expect(items.first.method.first.arguments.last).to be_a(Hash)
|
347
|
+
expect(items.first.method.first.arguments.last).to eq({ :fred => FlavourSaver::StringNode.new('wilma') })
|
315
348
|
end
|
316
349
|
end
|
317
350
|
end
|
@@ -12,7 +12,7 @@ describe FlavourSaver::Runtime do
|
|
12
12
|
let(:template) { "hello world" }
|
13
13
|
|
14
14
|
it "concatenates all the nodes items together" do
|
15
|
-
subject.evaluate_node(ast).
|
15
|
+
expect(subject.evaluate_node(ast)).to eq 'hello world'
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -21,7 +21,7 @@ describe FlavourSaver::Runtime do
|
|
21
21
|
|
22
22
|
it "returns the value of OutputNodes" do
|
23
23
|
node = ast.items.first
|
24
|
-
subject.evaluate_node(node).
|
24
|
+
expect(subject.evaluate_node(node)).to eq 'hello world'
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -30,7 +30,7 @@ describe FlavourSaver::Runtime do
|
|
30
30
|
let(:node) { ast.items.select { |n| n.class == FlavourSaver::ExpressionNode }.first.method.first.arguments.first }
|
31
31
|
|
32
32
|
it 'returns the value of the string' do
|
33
|
-
subject.evaluate_node(node).
|
33
|
+
expect(subject.evaluate_node(node)).to eq 'WAT'
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -39,13 +39,13 @@ describe FlavourSaver::Runtime do
|
|
39
39
|
let (:template) { "{{foo}}" }
|
40
40
|
|
41
41
|
it 'calls evaluate_node with the node' do
|
42
|
-
subject.
|
42
|
+
expect(subject).to receive(:evaluate_expression).with(node)
|
43
43
|
subject.evaluate_node(node)
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'should HTML escape the output' do
|
47
|
-
context.
|
48
|
-
subject.evaluate_node(node).
|
47
|
+
expect(context).to receive(:foo).and_return("<html>LOL</html>")
|
48
|
+
expect(subject.evaluate_node(node)).to eq '<html>LOL</html>'
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
@@ -54,8 +54,8 @@ describe FlavourSaver::Runtime do
|
|
54
54
|
let (:template) { "{{{foo}}}" }
|
55
55
|
|
56
56
|
it 'should not HTML escape the output' do
|
57
|
-
context.
|
58
|
-
subject.evaluate_node(node).
|
57
|
+
expect(context).to receive(:foo).and_return("<html>LOL</html>")
|
58
|
+
expect(subject.evaluate_node(node)).to eq '<html>LOL</html>'
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -64,7 +64,7 @@ describe FlavourSaver::Runtime do
|
|
64
64
|
let(:node) { ast.items.select { |n| n.class == FlavourSaver::CommentNode }.first }
|
65
65
|
|
66
66
|
it 'should return zilch' do
|
67
|
-
subject.evaluate_node(node).
|
67
|
+
expect(subject.evaluate_node(node)).to eq ''
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -72,8 +72,8 @@ describe FlavourSaver::Runtime do
|
|
72
72
|
let(:template) { "{{#foo}}bar{{/foo}}baz" }
|
73
73
|
|
74
74
|
it 'snatches up the block contents and skips them from evaluation' do
|
75
|
-
context.
|
76
|
-
subject.evaluate_node(ast).
|
75
|
+
allow(context).to receive(:foo)
|
76
|
+
expect(subject.evaluate_node(ast)).to eq 'baz'
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -86,8 +86,8 @@ describe FlavourSaver::Runtime do
|
|
86
86
|
let (:template) { "{{foo}}" }
|
87
87
|
|
88
88
|
it 'calls the method and return the result' do
|
89
|
-
context.
|
90
|
-
subject.evaluate_expression(expr).
|
89
|
+
expect(context).to receive(:foo).and_return('foo result')
|
90
|
+
expect(subject.evaluate_expression(expr)).to eq 'foo result'
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -95,8 +95,8 @@ describe FlavourSaver::Runtime do
|
|
95
95
|
let(:template) { "{{hello \"world\"}}" }
|
96
96
|
|
97
97
|
it 'calls the method with the arguments and return the result' do
|
98
|
-
context.
|
99
|
-
subject.evaluate_expression(expr).
|
98
|
+
expect(context).to receive(:hello).with("world").and_return("hello world")
|
99
|
+
expect(subject.evaluate_expression(expr)).to eq 'hello world'
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
@@ -104,9 +104,20 @@ describe FlavourSaver::Runtime do
|
|
104
104
|
let(:template) { "{{hello world}}" }
|
105
105
|
|
106
106
|
it 'calls hello & world on the context and return the result' do
|
107
|
-
context.
|
108
|
-
context.
|
109
|
-
subject.evaluate_expression(expr).
|
107
|
+
expect(context).to receive(:world).and_return('world')
|
108
|
+
expect(context).to receive(:hello).with('world').and_return('hello world')
|
109
|
+
expect(subject.evaluate_expression(expr)).to eq 'hello world'
|
110
|
+
end
|
111
|
+
end
|
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
|
+
expect(context).to receive(:world).and_return('world')
|
118
|
+
expect(context).to receive(:there).with('world').and_return('there world')
|
119
|
+
expect(context).to receive(:hello).with('there world').and_return('hello there world')
|
120
|
+
expect(subject.evaluate_expression(expr)).to eq 'hello there world'
|
110
121
|
end
|
111
122
|
end
|
112
123
|
|
@@ -114,8 +125,8 @@ describe FlavourSaver::Runtime do
|
|
114
125
|
let(:template) { "{{hello.world}}" }
|
115
126
|
|
116
127
|
it 'calls world on the result of hello' do
|
117
|
-
context.
|
118
|
-
subject.evaluate_expression(expr).
|
128
|
+
allow(context).to receive_message_chain(:hello, :world).and_return('hello world')
|
129
|
+
expect(subject.evaluate_expression(expr)).to eq 'hello world'
|
119
130
|
end
|
120
131
|
end
|
121
132
|
|
@@ -123,8 +134,8 @@ describe FlavourSaver::Runtime do
|
|
123
134
|
let(:template) { "{{[WAT]}}" }
|
124
135
|
|
125
136
|
it 'indexes the context with WAT' do
|
126
|
-
context.
|
127
|
-
subject.evaluate_expression(expr).
|
137
|
+
expect(context).to receive(:[]).with('WAT').and_return 'w00t'
|
138
|
+
expect(subject.evaluate_expression(expr)).to eq 'w00t'
|
128
139
|
end
|
129
140
|
end
|
130
141
|
|
@@ -133,11 +144,11 @@ describe FlavourSaver::Runtime do
|
|
133
144
|
|
134
145
|
it 'indexes the result of hello and calls world on it' do
|
135
146
|
world = double(:world)
|
136
|
-
world.
|
147
|
+
expect(world).to receive(:world).and_return('vr00m')
|
137
148
|
hash = double(:hash)
|
138
|
-
hash.
|
139
|
-
context.
|
140
|
-
subject.evaluate_expression(expr).
|
149
|
+
expect(hash).to receive(:[]).with('WAT').and_return(world)
|
150
|
+
expect(context).to receive(:hello).and_return(hash)
|
151
|
+
expect(subject.evaluate_expression(expr)).to eq 'vr00m'
|
141
152
|
end
|
142
153
|
end
|
143
154
|
|
@@ -145,7 +156,7 @@ describe FlavourSaver::Runtime do
|
|
145
156
|
let (:template) { "{{../foo}}" }
|
146
157
|
|
147
158
|
it 'raises an error' do
|
148
|
-
|
159
|
+
expect { subject.evaluate_expression(expr) }.to raise_error(FlavourSaver::UnknownContextException)
|
149
160
|
end
|
150
161
|
end
|
151
162
|
|
@@ -153,7 +164,7 @@ describe FlavourSaver::Runtime do
|
|
153
164
|
let (:template) { '{{foo bar="baz"}}' }
|
154
165
|
|
155
166
|
it 'receives the argument as a hash' do
|
156
|
-
context.
|
167
|
+
expect(context).to receive(:foo).with({:bar => 'baz'})
|
157
168
|
subject.evaluate_expression(expr)
|
158
169
|
end
|
159
170
|
end
|
@@ -162,8 +173,8 @@ describe FlavourSaver::Runtime do
|
|
162
173
|
let (:template) { "{{foo bar=baz}}" }
|
163
174
|
|
164
175
|
it 'calls the value and returns it\'s result in the hash' do
|
165
|
-
context.
|
166
|
-
context.
|
176
|
+
expect(context).to receive(:baz).and_return('OMGLOLWAT')
|
177
|
+
expect(context).to receive(:foo).with({:bar => 'OMGLOLWAT'})
|
167
178
|
subject.evaluate_expression(expr)
|
168
179
|
end
|
169
180
|
end
|
@@ -175,15 +186,15 @@ describe FlavourSaver::Runtime do
|
|
175
186
|
let(:block) { ast.items.first }
|
176
187
|
|
177
188
|
it 'creates a new runtime' do
|
178
|
-
subject.
|
179
|
-
context.
|
189
|
+
expect(subject).to receive(:create_child_runtime)
|
190
|
+
allow(context).to receive(:foo)
|
180
191
|
subject.evaluate_block(block, context)
|
181
192
|
end
|
182
193
|
end
|
183
194
|
|
184
195
|
describe '#create_child_runtime' do
|
185
196
|
it 'creates a new runtime' do
|
186
|
-
subject.create_child_runtime([]).
|
197
|
+
expect(subject.create_child_runtime([])).to be_a(FlavourSaver::Runtime)
|
187
198
|
end
|
188
199
|
end
|
189
200
|
|