curlybars 0.9.13
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 +7 -0
- data/lib/curlybars.rb +108 -0
- data/lib/curlybars/configuration.rb +41 -0
- data/lib/curlybars/dependency_tracker.rb +8 -0
- data/lib/curlybars/error/base.rb +18 -0
- data/lib/curlybars/error/compile.rb +11 -0
- data/lib/curlybars/error/lex.rb +22 -0
- data/lib/curlybars/error/parse.rb +41 -0
- data/lib/curlybars/error/presenter/not_found.rb +23 -0
- data/lib/curlybars/error/render.rb +11 -0
- data/lib/curlybars/error/validate.rb +18 -0
- data/lib/curlybars/lexer.rb +60 -0
- data/lib/curlybars/method_whitelist.rb +69 -0
- data/lib/curlybars/node/block_helper_else.rb +108 -0
- data/lib/curlybars/node/boolean.rb +24 -0
- data/lib/curlybars/node/each_else.rb +69 -0
- data/lib/curlybars/node/if_else.rb +33 -0
- data/lib/curlybars/node/item.rb +31 -0
- data/lib/curlybars/node/literal.rb +28 -0
- data/lib/curlybars/node/option.rb +25 -0
- data/lib/curlybars/node/output.rb +24 -0
- data/lib/curlybars/node/partial.rb +24 -0
- data/lib/curlybars/node/path.rb +137 -0
- data/lib/curlybars/node/root.rb +29 -0
- data/lib/curlybars/node/string.rb +24 -0
- data/lib/curlybars/node/template.rb +32 -0
- data/lib/curlybars/node/text.rb +24 -0
- data/lib/curlybars/node/unless_else.rb +33 -0
- data/lib/curlybars/node/variable.rb +34 -0
- data/lib/curlybars/node/with_else.rb +54 -0
- data/lib/curlybars/parser.rb +183 -0
- data/lib/curlybars/position.rb +7 -0
- data/lib/curlybars/presenter.rb +288 -0
- data/lib/curlybars/processor/tilde.rb +31 -0
- data/lib/curlybars/processor/token_factory.rb +9 -0
- data/lib/curlybars/railtie.rb +18 -0
- data/lib/curlybars/rendering_support.rb +222 -0
- data/lib/curlybars/safe_buffer.rb +11 -0
- data/lib/curlybars/template_handler.rb +93 -0
- data/lib/curlybars/version.rb +3 -0
- data/spec/acceptance/application_layout_spec.rb +60 -0
- data/spec/acceptance/collection_blocks_spec.rb +28 -0
- data/spec/acceptance/global_helper_spec.rb +25 -0
- data/spec/curlybars/configuration_spec.rb +57 -0
- data/spec/curlybars/error/base_spec.rb +41 -0
- data/spec/curlybars/error/compile_spec.rb +19 -0
- data/spec/curlybars/error/lex_spec.rb +25 -0
- data/spec/curlybars/error/parse_spec.rb +74 -0
- data/spec/curlybars/error/render_spec.rb +19 -0
- data/spec/curlybars/error/validate_spec.rb +19 -0
- data/spec/curlybars/lexer_spec.rb +466 -0
- data/spec/curlybars/method_whitelist_spec.rb +168 -0
- data/spec/curlybars/processor/tilde_spec.rb +60 -0
- data/spec/curlybars/rendering_support_spec.rb +426 -0
- data/spec/curlybars/safe_buffer_spec.rb +46 -0
- data/spec/curlybars/template_handler_spec.rb +222 -0
- data/spec/integration/cache_spec.rb +124 -0
- data/spec/integration/comment_spec.rb +60 -0
- data/spec/integration/exception_spec.rb +31 -0
- data/spec/integration/node/block_helper_else_spec.rb +422 -0
- data/spec/integration/node/each_else_spec.rb +204 -0
- data/spec/integration/node/each_spec.rb +291 -0
- data/spec/integration/node/escape_spec.rb +27 -0
- data/spec/integration/node/helper_spec.rb +176 -0
- data/spec/integration/node/if_else_spec.rb +129 -0
- data/spec/integration/node/if_spec.rb +143 -0
- data/spec/integration/node/output_spec.rb +68 -0
- data/spec/integration/node/partial_spec.rb +66 -0
- data/spec/integration/node/path_spec.rb +286 -0
- data/spec/integration/node/root_spec.rb +15 -0
- data/spec/integration/node/template_spec.rb +86 -0
- data/spec/integration/node/unless_else_spec.rb +129 -0
- data/spec/integration/node/unless_spec.rb +130 -0
- data/spec/integration/node/with_spec.rb +116 -0
- data/spec/integration/processor/tilde_spec.rb +38 -0
- data/spec/integration/processors_spec.rb +30 -0
- metadata +358 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
describe "Exception reporting" do
|
2
|
+
let(:post) { double("post") }
|
3
|
+
let(:presenter) { IntegrationTest::Presenter.new(double("view_context"), post: post) }
|
4
|
+
let(:global_helpers_providers) { [] }
|
5
|
+
|
6
|
+
it "Throw Curlybars::Error::Lex in case of a lex error occurs" do
|
7
|
+
expect do
|
8
|
+
Curlybars.compile('{{{')
|
9
|
+
end.to raise_error(Curlybars::Error::Lex)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "Throw Curlybars::Error::Parse in case of a lex error occurs" do
|
13
|
+
expect do
|
14
|
+
Curlybars.compile('{{#with "notallowed"}} ... {{/with}}')
|
15
|
+
end.to raise_error(Curlybars::Error::Parse)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "Throw Curlybars::Error::Compile in case of a lex error occurs" do
|
19
|
+
expect do
|
20
|
+
Curlybars.compile('{{#form new_comment_form}} ... {{/different_closing}}')
|
21
|
+
end.to raise_error(Curlybars::Error::Compile)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "Throw Curlybars::Error::Render in case of a rendering error occurs" do
|
25
|
+
compiled = Curlybars.compile('{{#form not_allowed_path}} ... {{/form}}')
|
26
|
+
|
27
|
+
expect do
|
28
|
+
eval(compiled)
|
29
|
+
end.to raise_error(Curlybars::Error::Render)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,422 @@
|
|
1
|
+
describe "{{#helper arg1 arg2 ... key=value ...}}...<{{else}}>...{{/helper}}" do
|
2
|
+
let(:global_helpers_providers) { [IntegrationTest::GlobalHelperProvider.new] }
|
3
|
+
|
4
|
+
describe "#compile" do
|
5
|
+
let(:post) { double("post") }
|
6
|
+
let(:presenter) { IntegrationTest::Presenter.new(double("view_context"), post: post) }
|
7
|
+
|
8
|
+
it "can be a global helper" do
|
9
|
+
template = Curlybars.compile(<<-HBS)
|
10
|
+
{{global_helper 'argument' option='value'}}
|
11
|
+
HBS
|
12
|
+
|
13
|
+
expect(eval(template)).to resemble(<<-HTML)
|
14
|
+
argument - option:value
|
15
|
+
HTML
|
16
|
+
end
|
17
|
+
|
18
|
+
it "accepts no arguments at all" do
|
19
|
+
template = Curlybars.compile(<<-HBS)
|
20
|
+
{{#just_yield}}
|
21
|
+
template
|
22
|
+
{{/just_yield}}
|
23
|
+
HBS
|
24
|
+
|
25
|
+
expect(eval(template)).to resemble(<<-HTML)
|
26
|
+
template
|
27
|
+
HTML
|
28
|
+
end
|
29
|
+
|
30
|
+
it "passes two arguments" do
|
31
|
+
template = Curlybars.compile(<<-HBS)
|
32
|
+
{{#print_args_and_options 'first' 'second'}}
|
33
|
+
{{/print_args_and_options}}
|
34
|
+
HBS
|
35
|
+
|
36
|
+
expect(eval(template)).to resemble(<<-HTML)
|
37
|
+
first, second, key=
|
38
|
+
HTML
|
39
|
+
end
|
40
|
+
|
41
|
+
it "passes two arguments and options" do
|
42
|
+
template = Curlybars.compile(<<-HBS)
|
43
|
+
{{#print_args_and_options 'first' 'second' key='value'}}
|
44
|
+
{{/print_args_and_options}}
|
45
|
+
HBS
|
46
|
+
|
47
|
+
expect(eval(template)).to resemble(<<-HTML)
|
48
|
+
first, second, key=value
|
49
|
+
HTML
|
50
|
+
end
|
51
|
+
|
52
|
+
it "renders the inverse block" do
|
53
|
+
template = Curlybars.compile(<<-HBS)
|
54
|
+
{{#render_inverse}}
|
55
|
+
fn
|
56
|
+
{{else}}
|
57
|
+
inverse
|
58
|
+
{{/render_inverse}}
|
59
|
+
HBS
|
60
|
+
|
61
|
+
expect(eval(template)).to resemble(<<-HTML)
|
62
|
+
inverse
|
63
|
+
HTML
|
64
|
+
end
|
65
|
+
|
66
|
+
it "renders the fn block" do
|
67
|
+
template = Curlybars.compile(<<-HBS)
|
68
|
+
{{#render_fn}}
|
69
|
+
fn
|
70
|
+
{{else}}
|
71
|
+
inverse
|
72
|
+
{{/render_fn}}
|
73
|
+
HBS
|
74
|
+
|
75
|
+
expect(eval(template)).to resemble(<<-HTML)
|
76
|
+
fn
|
77
|
+
HTML
|
78
|
+
end
|
79
|
+
|
80
|
+
it "block helpers can access the current context" do
|
81
|
+
template = Curlybars.compile(<<-HBS)
|
82
|
+
{{#print_current_context}} {{/print_current_context}}
|
83
|
+
HBS
|
84
|
+
|
85
|
+
expect(eval(template)).to resemble(<<-HTML)
|
86
|
+
root_context
|
87
|
+
HTML
|
88
|
+
end
|
89
|
+
|
90
|
+
it "renders a block helper without options" do
|
91
|
+
template = Curlybars.compile(<<-HBS)
|
92
|
+
{{#beautify}}
|
93
|
+
template
|
94
|
+
{{/beautify}}
|
95
|
+
HBS
|
96
|
+
|
97
|
+
expect(eval(template)).to resemble(<<-HTML)
|
98
|
+
bold template italic
|
99
|
+
HTML
|
100
|
+
end
|
101
|
+
|
102
|
+
it "renders a block helper with custom variables" do
|
103
|
+
template = Curlybars.compile(<<-HBS)
|
104
|
+
{{#yield_custom_variable}}
|
105
|
+
{{!--
|
106
|
+
`@custom1` and `@custom2` are variables yielded
|
107
|
+
by the block helper implementation.
|
108
|
+
--}}
|
109
|
+
|
110
|
+
{{@custom1}} {{@custom2}}
|
111
|
+
{{/yield_custom_variable}}
|
112
|
+
HBS
|
113
|
+
|
114
|
+
expect(eval(template)).to resemble(<<-HTML)
|
115
|
+
custom variable1
|
116
|
+
custom variable2
|
117
|
+
HTML
|
118
|
+
end
|
119
|
+
|
120
|
+
it "renders a block helper with custom variables that can be used in conditionals" do
|
121
|
+
template = Curlybars.compile(<<-HBS)
|
122
|
+
{{#yield_custom_variable}}
|
123
|
+
{{!--
|
124
|
+
`@cond` is a boolean variable yielded
|
125
|
+
by the block helper implementation.
|
126
|
+
--}}
|
127
|
+
|
128
|
+
{{#if @cond}}
|
129
|
+
Cond is true
|
130
|
+
{{/if}}
|
131
|
+
{{/yield_custom_variable}}
|
132
|
+
HBS
|
133
|
+
|
134
|
+
expect(eval(template)).to resemble(<<-HTML)
|
135
|
+
Cond is true
|
136
|
+
HTML
|
137
|
+
end
|
138
|
+
|
139
|
+
it "renders a block helper with custom variables that can be seen by nested contexts" do
|
140
|
+
template = Curlybars.compile(<<-HBS)
|
141
|
+
{{#yield_custom_variable}}
|
142
|
+
{{!--
|
143
|
+
`@custom1` and `@custom2` are variables yielded
|
144
|
+
by the block helper implementation.
|
145
|
+
--}}
|
146
|
+
{{#with this}}
|
147
|
+
{{@custom1}} {{@custom2}}
|
148
|
+
{{/with}}
|
149
|
+
{{/yield_custom_variable}}
|
150
|
+
HBS
|
151
|
+
|
152
|
+
expect(eval(template)).to resemble(<<-HTML)
|
153
|
+
custom variable1
|
154
|
+
custom variable2
|
155
|
+
HTML
|
156
|
+
end
|
157
|
+
|
158
|
+
it "renders a block helper with options and presenter" do
|
159
|
+
template = Curlybars.compile(<<-HBS)
|
160
|
+
{{#form new_comment_form class="red" foo="bar"}}
|
161
|
+
{{new_comment_form.button_label}}
|
162
|
+
{{/form}}
|
163
|
+
HBS
|
164
|
+
|
165
|
+
expect(eval(template)).to resemble(<<-HTML)
|
166
|
+
beauty class:red foo:bar submit
|
167
|
+
HTML
|
168
|
+
end
|
169
|
+
|
170
|
+
it "allow empty template" do
|
171
|
+
template = Curlybars.compile(<<-HBS)
|
172
|
+
{{#form new_comment_form class="red" foo="bar"}}{{/form}}
|
173
|
+
HBS
|
174
|
+
|
175
|
+
expect(eval(template)).to resemble(<<-HTML)
|
176
|
+
beauty class:red foo:bar
|
177
|
+
HTML
|
178
|
+
end
|
179
|
+
|
180
|
+
it "renders correctly a return type of integer" do
|
181
|
+
template = Curlybars.compile(<<-HBS)
|
182
|
+
{{#integer new_comment_form}} text {{/integer}}
|
183
|
+
HBS
|
184
|
+
|
185
|
+
expect(eval(template)).to resemble(<<-HTML)
|
186
|
+
0
|
187
|
+
HTML
|
188
|
+
end
|
189
|
+
|
190
|
+
it "renders correctly a return type of boolean" do
|
191
|
+
template = Curlybars.compile(<<-HBS)
|
192
|
+
{{#boolean new_comment_form}} text {{/boolean}}
|
193
|
+
HBS
|
194
|
+
|
195
|
+
expect(eval(template)).to resemble(<<-HTML)
|
196
|
+
true
|
197
|
+
HTML
|
198
|
+
end
|
199
|
+
|
200
|
+
it "accepts a nil context" do
|
201
|
+
template = Curlybars.compile(<<-HBS)
|
202
|
+
{{#this_method_yields return_nil}}
|
203
|
+
{{/this_method_yields}}
|
204
|
+
HBS
|
205
|
+
|
206
|
+
expect(eval(template)).to resemble("")
|
207
|
+
end
|
208
|
+
|
209
|
+
it "yield tolerated nil as pushed context" do
|
210
|
+
template = Curlybars.compile(<<-HBS)
|
211
|
+
{{#this_method_yields return_nil}}
|
212
|
+
text
|
213
|
+
{{/this_method_yields}}
|
214
|
+
HBS
|
215
|
+
|
216
|
+
expect(eval(template)).to resemble(<<-HTML)
|
217
|
+
text
|
218
|
+
HTML
|
219
|
+
end
|
220
|
+
|
221
|
+
it "raises an exception if the context is not a presenter-like object" do
|
222
|
+
template = Curlybars.compile(<<-HBS)
|
223
|
+
{{#boolean post}} text {{/boolean}}
|
224
|
+
HBS
|
225
|
+
|
226
|
+
expect do
|
227
|
+
eval(template)
|
228
|
+
end.to raise_error(Curlybars::Error::Render)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "#validate" do
|
233
|
+
let(:presenter_class) { double(:presenter_class) }
|
234
|
+
|
235
|
+
it "without errors when global helper" do
|
236
|
+
allow(Curlybars.configuration).to receive(:global_helpers_provider_classes).and_return([IntegrationTest::GlobalHelperProvider])
|
237
|
+
|
238
|
+
dependency_tree = {}
|
239
|
+
|
240
|
+
source = <<-HBS
|
241
|
+
{{global_helper}}
|
242
|
+
HBS
|
243
|
+
|
244
|
+
errors = Curlybars.validate(dependency_tree, source)
|
245
|
+
|
246
|
+
expect(errors).to be_empty
|
247
|
+
end
|
248
|
+
|
249
|
+
it "without errors when invoking a leaf" do
|
250
|
+
dependency_tree = { name: nil }
|
251
|
+
|
252
|
+
source = <<-HBS
|
253
|
+
{{name}}
|
254
|
+
HBS
|
255
|
+
|
256
|
+
errors = Curlybars.validate(dependency_tree, source)
|
257
|
+
|
258
|
+
expect(errors).to be_empty
|
259
|
+
end
|
260
|
+
|
261
|
+
it "without errors if argument is a leaf" do
|
262
|
+
dependency_tree = { block_helper: :helper, argument: nil }
|
263
|
+
|
264
|
+
source = <<-HBS
|
265
|
+
{{#block_helper argument}} ... {{/block_helper}}
|
266
|
+
HBS
|
267
|
+
|
268
|
+
errors = Curlybars.validate(dependency_tree, source)
|
269
|
+
|
270
|
+
expect(errors).to be_empty
|
271
|
+
end
|
272
|
+
|
273
|
+
it "without errors if argument is a literal" do
|
274
|
+
dependency_tree = { block_helper: :helper }
|
275
|
+
|
276
|
+
source = <<-HBS
|
277
|
+
{{#block_helper 'argument'}} ... {{/block_helper}}
|
278
|
+
HBS
|
279
|
+
|
280
|
+
errors = Curlybars.validate(dependency_tree, source)
|
281
|
+
|
282
|
+
expect(errors).to be_empty
|
283
|
+
end
|
284
|
+
|
285
|
+
it "without errors if argument is a variable" do
|
286
|
+
dependency_tree = { block_helper: :helper }
|
287
|
+
|
288
|
+
source = <<-HBS
|
289
|
+
{{#block_helper @var}} ... {{/block_helper}}
|
290
|
+
HBS
|
291
|
+
|
292
|
+
errors = Curlybars.validate(dependency_tree, source)
|
293
|
+
|
294
|
+
expect(errors).to be_empty
|
295
|
+
end
|
296
|
+
|
297
|
+
it "without errors if option is a leaf" do
|
298
|
+
dependency_tree = { block_helper: :helper, argument: nil }
|
299
|
+
|
300
|
+
source = <<-HBS
|
301
|
+
{{#block_helper option=argument}} ... {{/block_helper}}
|
302
|
+
HBS
|
303
|
+
|
304
|
+
errors = Curlybars.validate(dependency_tree, source)
|
305
|
+
|
306
|
+
expect(errors).to be_empty
|
307
|
+
end
|
308
|
+
|
309
|
+
it "without errors if option is a literal" do
|
310
|
+
dependency_tree = { block_helper: :helper }
|
311
|
+
|
312
|
+
source = <<-HBS
|
313
|
+
{{#block_helper option='argument'}} ... {{/block_helper}}
|
314
|
+
HBS
|
315
|
+
|
316
|
+
errors = Curlybars.validate(dependency_tree, source)
|
317
|
+
|
318
|
+
expect(errors).to be_empty
|
319
|
+
end
|
320
|
+
|
321
|
+
it "without errors if option is a variable" do
|
322
|
+
dependency_tree = { block_helper: :helper }
|
323
|
+
|
324
|
+
source = <<-HBS
|
325
|
+
{{#block_helper option=@var}} ... {{/block_helper}}
|
326
|
+
HBS
|
327
|
+
|
328
|
+
errors = Curlybars.validate(dependency_tree, source)
|
329
|
+
|
330
|
+
expect(errors).to be_empty
|
331
|
+
end
|
332
|
+
|
333
|
+
it "without errors in block_helper" do
|
334
|
+
dependency_tree = { block_helper: :helper, context: nil }
|
335
|
+
|
336
|
+
source = <<-HBS
|
337
|
+
{{#block_helper context}} ... {{/block_helper}}
|
338
|
+
HBS
|
339
|
+
|
340
|
+
errors = Curlybars.validate(dependency_tree, source)
|
341
|
+
|
342
|
+
expect(errors).to be_empty
|
343
|
+
end
|
344
|
+
|
345
|
+
it "with errors when invoking a leaf with arguments" do
|
346
|
+
dependency_tree = { name: nil }
|
347
|
+
|
348
|
+
source = <<-HBS
|
349
|
+
{{name 'argument'}}
|
350
|
+
HBS
|
351
|
+
|
352
|
+
errors = Curlybars.validate(dependency_tree, source)
|
353
|
+
|
354
|
+
expect(errors).not_to be_empty
|
355
|
+
end
|
356
|
+
|
357
|
+
it "with errors when invoking a leaf with options" do
|
358
|
+
dependency_tree = { name: nil }
|
359
|
+
|
360
|
+
source = <<-HBS
|
361
|
+
{{name option='value'}}
|
362
|
+
HBS
|
363
|
+
|
364
|
+
errors = Curlybars.validate(dependency_tree, source)
|
365
|
+
|
366
|
+
expect(errors).not_to be_empty
|
367
|
+
end
|
368
|
+
|
369
|
+
it "with errors if argument is not a value" do
|
370
|
+
dependency_tree = { block_helper: :helper, not_a_value: {} }
|
371
|
+
|
372
|
+
source = <<-HBS
|
373
|
+
{{#block_helper not_a_value}} ... {{/block_helper}}
|
374
|
+
HBS
|
375
|
+
|
376
|
+
errors = Curlybars.validate(dependency_tree, source)
|
377
|
+
|
378
|
+
expect(errors).not_to be_empty
|
379
|
+
end
|
380
|
+
|
381
|
+
it "with errors if option is not a value" do
|
382
|
+
dependency_tree = { block_helper: :helper, not_a_value: {} }
|
383
|
+
|
384
|
+
source = <<-HBS
|
385
|
+
{{#block_helper option=not_a_value}} ... {{/block_helper}}
|
386
|
+
HBS
|
387
|
+
|
388
|
+
errors = Curlybars.validate(dependency_tree, source)
|
389
|
+
|
390
|
+
expect(errors).not_to be_empty
|
391
|
+
end
|
392
|
+
|
393
|
+
it "with errors in fn block" do
|
394
|
+
dependency_tree = { context: {}, block_helper: :helper }
|
395
|
+
|
396
|
+
source = <<-HBS
|
397
|
+
{{#block_helper context}}
|
398
|
+
{{invalid}}
|
399
|
+
{{/block_helper}}
|
400
|
+
HBS
|
401
|
+
|
402
|
+
errors = Curlybars.validate(dependency_tree, source)
|
403
|
+
|
404
|
+
expect(errors).not_to be_empty
|
405
|
+
end
|
406
|
+
|
407
|
+
it "with errors in inverse block" do
|
408
|
+
dependency_tree = { context: {}, block_helper: :helper }
|
409
|
+
|
410
|
+
source = <<-HBS
|
411
|
+
{{#block_helper context}}
|
412
|
+
{{else}}
|
413
|
+
{{invalid}}
|
414
|
+
{{/block_helper}}
|
415
|
+
HBS
|
416
|
+
|
417
|
+
errors = Curlybars.validate(dependency_tree, source)
|
418
|
+
|
419
|
+
expect(errors).not_to be_empty
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|