curlybars 0.9.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/lib/curlybars.rb +108 -0
  3. data/lib/curlybars/configuration.rb +41 -0
  4. data/lib/curlybars/dependency_tracker.rb +8 -0
  5. data/lib/curlybars/error/base.rb +18 -0
  6. data/lib/curlybars/error/compile.rb +11 -0
  7. data/lib/curlybars/error/lex.rb +22 -0
  8. data/lib/curlybars/error/parse.rb +41 -0
  9. data/lib/curlybars/error/presenter/not_found.rb +23 -0
  10. data/lib/curlybars/error/render.rb +11 -0
  11. data/lib/curlybars/error/validate.rb +18 -0
  12. data/lib/curlybars/lexer.rb +60 -0
  13. data/lib/curlybars/method_whitelist.rb +69 -0
  14. data/lib/curlybars/node/block_helper_else.rb +108 -0
  15. data/lib/curlybars/node/boolean.rb +24 -0
  16. data/lib/curlybars/node/each_else.rb +69 -0
  17. data/lib/curlybars/node/if_else.rb +33 -0
  18. data/lib/curlybars/node/item.rb +31 -0
  19. data/lib/curlybars/node/literal.rb +28 -0
  20. data/lib/curlybars/node/option.rb +25 -0
  21. data/lib/curlybars/node/output.rb +24 -0
  22. data/lib/curlybars/node/partial.rb +24 -0
  23. data/lib/curlybars/node/path.rb +137 -0
  24. data/lib/curlybars/node/root.rb +29 -0
  25. data/lib/curlybars/node/string.rb +24 -0
  26. data/lib/curlybars/node/template.rb +32 -0
  27. data/lib/curlybars/node/text.rb +24 -0
  28. data/lib/curlybars/node/unless_else.rb +33 -0
  29. data/lib/curlybars/node/variable.rb +34 -0
  30. data/lib/curlybars/node/with_else.rb +54 -0
  31. data/lib/curlybars/parser.rb +183 -0
  32. data/lib/curlybars/position.rb +7 -0
  33. data/lib/curlybars/presenter.rb +288 -0
  34. data/lib/curlybars/processor/tilde.rb +31 -0
  35. data/lib/curlybars/processor/token_factory.rb +9 -0
  36. data/lib/curlybars/railtie.rb +18 -0
  37. data/lib/curlybars/rendering_support.rb +222 -0
  38. data/lib/curlybars/safe_buffer.rb +11 -0
  39. data/lib/curlybars/template_handler.rb +93 -0
  40. data/lib/curlybars/version.rb +3 -0
  41. data/spec/acceptance/application_layout_spec.rb +60 -0
  42. data/spec/acceptance/collection_blocks_spec.rb +28 -0
  43. data/spec/acceptance/global_helper_spec.rb +25 -0
  44. data/spec/curlybars/configuration_spec.rb +57 -0
  45. data/spec/curlybars/error/base_spec.rb +41 -0
  46. data/spec/curlybars/error/compile_spec.rb +19 -0
  47. data/spec/curlybars/error/lex_spec.rb +25 -0
  48. data/spec/curlybars/error/parse_spec.rb +74 -0
  49. data/spec/curlybars/error/render_spec.rb +19 -0
  50. data/spec/curlybars/error/validate_spec.rb +19 -0
  51. data/spec/curlybars/lexer_spec.rb +466 -0
  52. data/spec/curlybars/method_whitelist_spec.rb +168 -0
  53. data/spec/curlybars/processor/tilde_spec.rb +60 -0
  54. data/spec/curlybars/rendering_support_spec.rb +426 -0
  55. data/spec/curlybars/safe_buffer_spec.rb +46 -0
  56. data/spec/curlybars/template_handler_spec.rb +222 -0
  57. data/spec/integration/cache_spec.rb +124 -0
  58. data/spec/integration/comment_spec.rb +60 -0
  59. data/spec/integration/exception_spec.rb +31 -0
  60. data/spec/integration/node/block_helper_else_spec.rb +422 -0
  61. data/spec/integration/node/each_else_spec.rb +204 -0
  62. data/spec/integration/node/each_spec.rb +291 -0
  63. data/spec/integration/node/escape_spec.rb +27 -0
  64. data/spec/integration/node/helper_spec.rb +176 -0
  65. data/spec/integration/node/if_else_spec.rb +129 -0
  66. data/spec/integration/node/if_spec.rb +143 -0
  67. data/spec/integration/node/output_spec.rb +68 -0
  68. data/spec/integration/node/partial_spec.rb +66 -0
  69. data/spec/integration/node/path_spec.rb +286 -0
  70. data/spec/integration/node/root_spec.rb +15 -0
  71. data/spec/integration/node/template_spec.rb +86 -0
  72. data/spec/integration/node/unless_else_spec.rb +129 -0
  73. data/spec/integration/node/unless_spec.rb +130 -0
  74. data/spec/integration/node/with_spec.rb +116 -0
  75. data/spec/integration/processor/tilde_spec.rb +38 -0
  76. data/spec/integration/processors_spec.rb +30 -0
  77. 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