curlybars 1.3.1 → 1.7.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 +4 -4
- data/lib/curlybars.rb +8 -1
- data/lib/curlybars/configuration.rb +1 -9
- data/lib/curlybars/error/base.rb +2 -0
- data/lib/curlybars/generic.rb +36 -0
- data/lib/curlybars/lexer.rb +3 -0
- data/lib/curlybars/method_whitelist.rb +25 -3
- data/lib/curlybars/node/block_helper_else.rb +1 -0
- data/lib/curlybars/node/each_else.rb +6 -2
- data/lib/curlybars/node/if_else.rb +1 -1
- data/lib/curlybars/node/path.rb +58 -11
- data/lib/curlybars/node/sub_expression.rb +108 -0
- data/lib/curlybars/node/unless_else.rb +1 -1
- data/lib/curlybars/node/with_else.rb +6 -2
- data/lib/curlybars/parser.rb +39 -0
- data/lib/curlybars/processor/tilde.rb +3 -0
- data/lib/curlybars/rendering_support.rb +9 -1
- data/lib/curlybars/template_handler.rb +18 -6
- data/lib/curlybars/version.rb +1 -1
- data/lib/curlybars/visitor.rb +6 -0
- data/spec/acceptance/application_layout_spec.rb +2 -2
- data/spec/acceptance/collection_blocks_spec.rb +1 -1
- data/spec/acceptance/global_helper_spec.rb +1 -1
- data/spec/curlybars/lexer_spec.rb +25 -2
- data/spec/curlybars/method_whitelist_spec.rb +8 -4
- data/spec/curlybars/rendering_support_spec.rb +4 -9
- data/spec/curlybars/template_handler_spec.rb +33 -30
- data/spec/integration/cache_spec.rb +20 -18
- data/spec/integration/node/block_helper_else_spec.rb +0 -2
- data/spec/integration/node/each_else_spec.rb +208 -4
- data/spec/integration/node/each_spec.rb +0 -2
- data/spec/integration/node/helper_spec.rb +12 -2
- data/spec/integration/node/if_else_spec.rb +0 -2
- data/spec/integration/node/if_spec.rb +2 -4
- data/spec/integration/node/output_spec.rb +0 -2
- data/spec/integration/node/partial_spec.rb +0 -2
- data/spec/integration/node/path_spec.rb +0 -2
- data/spec/integration/node/root_spec.rb +0 -2
- data/spec/integration/node/sub_expression_spec.rb +426 -0
- data/spec/integration/node/template_spec.rb +0 -2
- data/spec/integration/node/unless_else_spec.rb +2 -4
- data/spec/integration/node/unless_spec.rb +0 -2
- data/spec/integration/node/with_spec.rb +66 -4
- data/spec/integration/processor/tilde_spec.rb +1 -1
- data/spec/integration/processors_spec.rb +4 -5
- data/spec/integration/visitor_spec.rb +13 -5
- metadata +49 -15
@@ -1,29 +1,31 @@
|
|
1
1
|
describe "caching" do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
let(:dummy_cache) do
|
3
|
+
Class.new do
|
4
|
+
attr_reader :reads, :hits
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@store = {}
|
8
|
+
@reads = 0
|
9
|
+
@hits = 0
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
def fetch(key)
|
13
|
+
@reads += 1
|
14
|
+
if @store.key?(key)
|
15
|
+
@hits += 1
|
16
|
+
@store[key]
|
17
|
+
else
|
18
|
+
value = yield
|
19
|
+
@store[key] = value
|
20
|
+
value
|
21
|
+
end
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
26
|
let(:global_helpers_providers) { [] }
|
25
27
|
let(:presenter) { IntegrationTest::Presenter.new(double("view_context")) }
|
26
|
-
let(:cache) {
|
28
|
+
let(:cache) { dummy_cache.new }
|
27
29
|
|
28
30
|
before do
|
29
31
|
Curlybars.configure do |config|
|
@@ -230,8 +230,6 @@ describe "{{#helper arg1 arg2 ... key=value ...}}...<{{else}}>...{{/helper}}" do
|
|
230
230
|
end
|
231
231
|
|
232
232
|
describe "#validate" do
|
233
|
-
let(:presenter_class) { double(:presenter_class) }
|
234
|
-
|
235
233
|
it "without errors when global helper" do
|
236
234
|
allow(Curlybars.configuration).to receive(:global_helpers_provider_classes).and_return([IntegrationTest::GlobalHelperProvider])
|
237
235
|
|
@@ -1,9 +1,10 @@
|
|
1
1
|
describe "{{#each collection}}...{{else}}...{{/each}}" do
|
2
|
-
let(:global_helpers_providers) { [] }
|
2
|
+
let(:global_helpers_providers) { [IntegrationTest::GlobalHelperProvider.new] }
|
3
3
|
|
4
4
|
describe "#compile" do
|
5
5
|
let(:post) { double("post") }
|
6
|
-
let(:
|
6
|
+
let(:presenter_class) { IntegrationTest::Presenter }
|
7
|
+
let(:presenter) { presenter_class.new(double("view_context"), post: post) }
|
7
8
|
|
8
9
|
it "uses each_template when collection is not empty" do
|
9
10
|
allow(presenter).to receive(:allows_method?).with(:non_empty_collection).and_return(true)
|
@@ -123,6 +124,41 @@ describe "{{#each collection}}...{{else}}...{{/each}}" do
|
|
123
124
|
HTML
|
124
125
|
end
|
125
126
|
|
127
|
+
it "allows subexpressions" do
|
128
|
+
template = Curlybars.compile(<<-HBS)
|
129
|
+
{{#each (articles)}}left{{else}}right{{/each}}
|
130
|
+
HBS
|
131
|
+
|
132
|
+
expected = "left" * presenter.articles.size
|
133
|
+
expect(eval(template)).to resemble(expected)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "allows subexpressions with collection helpers" do
|
137
|
+
template = Curlybars.compile(<<-HBS)
|
138
|
+
{{#each (reverse_articles)}}
|
139
|
+
{{title}}
|
140
|
+
{{else}}
|
141
|
+
right
|
142
|
+
{{/each}}
|
143
|
+
HBS
|
144
|
+
|
145
|
+
expected = presenter.reverse_articles.inject("") { |res, a| res + a.title }
|
146
|
+
expect(eval(template)).to resemble(expected)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "allows subexpressions with generic collection helpers" do
|
150
|
+
template = Curlybars.compile(<<-HBS)
|
151
|
+
{{#each (refl articles)}}
|
152
|
+
{{title}}
|
153
|
+
{{else}}
|
154
|
+
right
|
155
|
+
{{/each}}
|
156
|
+
HBS
|
157
|
+
|
158
|
+
expected = presenter.articles.inject("") { |res, a| res + a.title }
|
159
|
+
expect(eval(template)).to resemble(expected)
|
160
|
+
end
|
161
|
+
|
126
162
|
it "raises an error if the context is not an array-like object" do
|
127
163
|
allow(IntegrationTest::Presenter).to receive(:allows_method?).with(:not_a_collection).and_return(true)
|
128
164
|
allow(presenter).to receive(:not_a_collection).and_return("string")
|
@@ -151,8 +187,6 @@ describe "{{#each collection}}...{{else}}...{{/each}}" do
|
|
151
187
|
end
|
152
188
|
|
153
189
|
describe "#validate" do
|
154
|
-
let(:presenter_class) { double(:presenter_class) }
|
155
|
-
|
156
190
|
it "without errors" do
|
157
191
|
dependency_tree = { a_presenter_collection: [{}] }
|
158
192
|
|
@@ -200,5 +234,175 @@ describe "{{#each collection}}...{{else}}...{{/each}}" do
|
|
200
234
|
|
201
235
|
expect(errors).not_to be_empty
|
202
236
|
end
|
237
|
+
|
238
|
+
describe "with subexpressions" do
|
239
|
+
before do
|
240
|
+
Curlybars.instance_variable_set(:@global_helpers_dependency_tree, nil)
|
241
|
+
end
|
242
|
+
|
243
|
+
it "without errors when called with a presenter collection" do
|
244
|
+
dependency_tree = { a_presenter_collection: [{}] }
|
245
|
+
|
246
|
+
source = <<-HBS
|
247
|
+
{{#each (a_presenter_collection)}} {{else}} {{/each}}
|
248
|
+
HBS
|
249
|
+
|
250
|
+
errors = Curlybars.validate(dependency_tree, source)
|
251
|
+
|
252
|
+
expect(errors).to be_empty
|
253
|
+
end
|
254
|
+
|
255
|
+
it "without errors when called with a collection helper" do
|
256
|
+
dependency_tree = { a_collection_helper: [:helper, [{ url: nil }]] }
|
257
|
+
|
258
|
+
source = <<-HBS
|
259
|
+
{{#each (a_collection_helper)}}
|
260
|
+
{{url}}
|
261
|
+
{{else}}
|
262
|
+
right
|
263
|
+
{{/each}}
|
264
|
+
HBS
|
265
|
+
|
266
|
+
errors = Curlybars.validate(dependency_tree, source)
|
267
|
+
|
268
|
+
expect(errors).to be_empty
|
269
|
+
end
|
270
|
+
|
271
|
+
context "with a generic collection helper" do
|
272
|
+
it "without errors when arguments are valid" do
|
273
|
+
dependency_tree = {
|
274
|
+
refl: [:helper, [{}]],
|
275
|
+
articles: [{ url: nil }]
|
276
|
+
}
|
277
|
+
|
278
|
+
source = <<-HBS
|
279
|
+
{{#each (refl articles)}}
|
280
|
+
{{url}}
|
281
|
+
{{else}}
|
282
|
+
right
|
283
|
+
{{/each}}
|
284
|
+
HBS
|
285
|
+
|
286
|
+
errors = Curlybars.validate(dependency_tree, source)
|
287
|
+
|
288
|
+
expect(errors).to be_empty
|
289
|
+
end
|
290
|
+
|
291
|
+
it "with errors when the first argument is not a collection" do
|
292
|
+
dependency_tree = {
|
293
|
+
refl: [:helper, [{}]],
|
294
|
+
articles: { url: nil }
|
295
|
+
}
|
296
|
+
|
297
|
+
source = <<-HBS
|
298
|
+
{{#each (refl articles)}}
|
299
|
+
{{url}}
|
300
|
+
{{else}}
|
301
|
+
right
|
302
|
+
{{/each}}
|
303
|
+
HBS
|
304
|
+
|
305
|
+
errors = Curlybars.validate(dependency_tree, source)
|
306
|
+
|
307
|
+
expect(errors).not_to be_empty
|
308
|
+
end
|
309
|
+
|
310
|
+
it "with errors when the first argument is not defined" do
|
311
|
+
dependency_tree = {
|
312
|
+
refl: [:helper, [{}]]
|
313
|
+
}
|
314
|
+
|
315
|
+
source = <<-HBS
|
316
|
+
{{#each (refl articles)}}
|
317
|
+
{{url}}
|
318
|
+
{{else}}
|
319
|
+
right
|
320
|
+
{{/each}}
|
321
|
+
HBS
|
322
|
+
|
323
|
+
errors = Curlybars.validate(dependency_tree, source)
|
324
|
+
|
325
|
+
expect(errors).not_to be_empty
|
326
|
+
end
|
327
|
+
|
328
|
+
it "with errors when no argument is given" do
|
329
|
+
dependency_tree = {
|
330
|
+
refl: [:helper, [{}]]
|
331
|
+
}
|
332
|
+
|
333
|
+
source = <<-HBS
|
334
|
+
{{#each (refl)}}
|
335
|
+
{{url}}
|
336
|
+
{{else}}
|
337
|
+
right
|
338
|
+
{{/each}}
|
339
|
+
HBS
|
340
|
+
|
341
|
+
errors = Curlybars.validate(dependency_tree, source)
|
342
|
+
|
343
|
+
expect(errors).not_to be_empty
|
344
|
+
end
|
345
|
+
|
346
|
+
describe "as a global helper" do
|
347
|
+
let(:global_helpers_provider_classes) { [IntegrationTest::GlobalHelperProvider] }
|
348
|
+
|
349
|
+
before do
|
350
|
+
allow(Curlybars.configuration).to receive(:global_helpers_provider_classes).and_return(global_helpers_provider_classes)
|
351
|
+
end
|
352
|
+
|
353
|
+
it "without errors when the first argument is a collection" do
|
354
|
+
dependency_tree = {
|
355
|
+
articles: [{ url: nil }]
|
356
|
+
}
|
357
|
+
|
358
|
+
source = <<-HBS
|
359
|
+
{{#each (slice articles 0 4)}}
|
360
|
+
{{url}}
|
361
|
+
{{else}}
|
362
|
+
right
|
363
|
+
{{/each}}
|
364
|
+
HBS
|
365
|
+
|
366
|
+
errors = Curlybars.validate(dependency_tree, source)
|
367
|
+
|
368
|
+
expect(errors).to be_empty
|
369
|
+
end
|
370
|
+
|
371
|
+
it "with errors when the first argument is not a collection" do
|
372
|
+
dependency_tree = {
|
373
|
+
articles: { url: nil }
|
374
|
+
}
|
375
|
+
|
376
|
+
source = <<-HBS
|
377
|
+
{{#each (slice articles 0 4)}}
|
378
|
+
{{url}}
|
379
|
+
{{else}}
|
380
|
+
right
|
381
|
+
{{/each}}
|
382
|
+
HBS
|
383
|
+
|
384
|
+
errors = Curlybars.validate(dependency_tree, source)
|
385
|
+
|
386
|
+
expect(errors).not_to be_empty
|
387
|
+
end
|
388
|
+
|
389
|
+
it "with errors when no argument is given" do
|
390
|
+
dependency_tree = {}
|
391
|
+
|
392
|
+
source = <<-HBS
|
393
|
+
{{#each (slice)}}
|
394
|
+
{{url}}
|
395
|
+
{{else}}
|
396
|
+
right
|
397
|
+
{{/each}}
|
398
|
+
HBS
|
399
|
+
|
400
|
+
errors = Curlybars.validate(dependency_tree, source)
|
401
|
+
|
402
|
+
expect(errors).not_to be_empty
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
203
407
|
end
|
204
408
|
end
|
@@ -15,6 +15,18 @@ describe "{{helper context key=value}}" do
|
|
15
15
|
HTML
|
16
16
|
end
|
17
17
|
|
18
|
+
it "calls a helper without arguments in an if statement" do
|
19
|
+
template = Curlybars.compile(<<-HBS)
|
20
|
+
{{#if print_args_and_options}}
|
21
|
+
{{print_args_and_options 'first' 'second'}}
|
22
|
+
{{/if}}
|
23
|
+
HBS
|
24
|
+
|
25
|
+
expect(eval(template)).to resemble(<<-HTML)
|
26
|
+
first, second, key=
|
27
|
+
HTML
|
28
|
+
end
|
29
|
+
|
18
30
|
it "passes two arguments and options" do
|
19
31
|
template = Curlybars.compile(<<-HBS)
|
20
32
|
{{print_args_and_options 'first' 'second' key='value'}}
|
@@ -109,8 +121,6 @@ describe "{{helper context key=value}}" do
|
|
109
121
|
end
|
110
122
|
|
111
123
|
describe "#validate" do
|
112
|
-
let(:presenter_class) { double(:presenter_class) }
|
113
|
-
|
114
124
|
it "with errors" do
|
115
125
|
dependency_tree = {}
|
116
126
|
|
@@ -112,8 +112,6 @@ describe "{{#if}}...{{/if}}" do
|
|
112
112
|
end
|
113
113
|
|
114
114
|
describe "#validate" do
|
115
|
-
let(:presenter_class) { double(:presenter_class) }
|
116
|
-
|
117
115
|
it "validates with errors the condition" do
|
118
116
|
dependency_tree = {}
|
119
117
|
|
@@ -140,7 +138,7 @@ describe "{{#if}}...{{/if}}" do
|
|
140
138
|
expect(errors).not_to be_empty
|
141
139
|
end
|
142
140
|
|
143
|
-
it "validates
|
141
|
+
it "validates without errors the helper as condition" do
|
144
142
|
dependency_tree = { helper: :helper }
|
145
143
|
|
146
144
|
source = <<-HBS
|
@@ -149,7 +147,7 @@ describe "{{#if}}...{{/if}}" do
|
|
149
147
|
|
150
148
|
errors = Curlybars.validate(dependency_tree, source)
|
151
149
|
|
152
|
-
expect(errors).
|
150
|
+
expect(errors).to be_empty
|
153
151
|
end
|
154
152
|
end
|
155
153
|
end
|
@@ -0,0 +1,426 @@
|
|
1
|
+
describe "{{(helper arg1 arg2 ... key=value ...)}}" do
|
2
|
+
let(:global_helpers_providers) { [IntegrationTest::GlobalHelperProvider.new] }
|
3
|
+
|
4
|
+
describe "#compile" do
|
5
|
+
let(:presenter) { IntegrationTest::Presenter.new(double("view_context")) }
|
6
|
+
|
7
|
+
it "can be an argument to helpers" do
|
8
|
+
template = Curlybars.compile(<<-HBS)
|
9
|
+
{{global_helper (global_helper 'argument' option='value') option='value'}}
|
10
|
+
HBS
|
11
|
+
|
12
|
+
expect(eval(template)).to resemble(<<-HTML)
|
13
|
+
argument - option:value - option:value
|
14
|
+
HTML
|
15
|
+
end
|
16
|
+
|
17
|
+
it "can be an argument to itself" do
|
18
|
+
template = Curlybars.compile(<<-HBS)
|
19
|
+
{{global_helper (global_helper (global_helper 'a' option='b') option='c') option='d'}}
|
20
|
+
HBS
|
21
|
+
|
22
|
+
expect(eval(template)).to resemble(<<-HTML)
|
23
|
+
a - option:b - option:c - option:d
|
24
|
+
HTML
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can handle data objects as argument" do
|
28
|
+
template = Curlybars.compile(<<-HBS)
|
29
|
+
{{global_helper (extract user attribute='first_name') option='value'}}
|
30
|
+
HBS
|
31
|
+
|
32
|
+
expect(eval(template)).to resemble(<<-HTML)
|
33
|
+
Libo - option:value
|
34
|
+
HTML
|
35
|
+
end
|
36
|
+
|
37
|
+
it "can handle calls inside with" do
|
38
|
+
template = Curlybars.compile(<<-HBS)
|
39
|
+
{{#with article}}
|
40
|
+
{{global_helper (extract author attribute='first_name') option='value'}}
|
41
|
+
{{/with}}
|
42
|
+
HBS
|
43
|
+
|
44
|
+
expect(eval(template)).to resemble(<<-HTML)
|
45
|
+
Nicolò - option:value
|
46
|
+
HTML
|
47
|
+
end
|
48
|
+
|
49
|
+
it "does not accept subexpressions in the root" do
|
50
|
+
expect do
|
51
|
+
Curlybars.compile(<<-HBS)
|
52
|
+
{{(join articles attribute='title' separator='-'}}
|
53
|
+
HBS
|
54
|
+
end.to raise_error(Curlybars::Error::Parse)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "can be called within if expressions" do
|
58
|
+
template = Curlybars.compile(<<-HBS)
|
59
|
+
{{#if (calc 3 ">" 1)}}
|
60
|
+
True
|
61
|
+
{{/if}}
|
62
|
+
HBS
|
63
|
+
|
64
|
+
expect(eval(template)).to resemble(<<-HTML)
|
65
|
+
True
|
66
|
+
HTML
|
67
|
+
end
|
68
|
+
|
69
|
+
# Replication of Handlebars' subexpression specs for feature parity
|
70
|
+
# https://github.com/handlebars-lang/handlebars.js/blob/1a08e1d0a7f500f2c1188cbd21750bb9180afcbb/spec/subexpressions.js
|
71
|
+
|
72
|
+
it "arg-less helper" do
|
73
|
+
template = Curlybars.compile(<<-HBS)
|
74
|
+
{{foo (bar)}}!
|
75
|
+
HBS
|
76
|
+
|
77
|
+
expect(eval(template)).to resemble(<<-HTML)
|
78
|
+
LOLLOL!
|
79
|
+
HTML
|
80
|
+
end
|
81
|
+
|
82
|
+
context "with blog presenter" do
|
83
|
+
let(:presenter) do
|
84
|
+
IntegrationTest::BlogPresenter.new(
|
85
|
+
lambda { |*args, options|
|
86
|
+
val = args.first
|
87
|
+
"val is #{val}"
|
88
|
+
}
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "helper w args" do
|
93
|
+
template = Curlybars.compile(<<-HBS)
|
94
|
+
{{blog (equal a b)}}
|
95
|
+
HBS
|
96
|
+
|
97
|
+
expect(eval(template)).to resemble(<<-HTML)
|
98
|
+
val is true
|
99
|
+
HTML
|
100
|
+
end
|
101
|
+
|
102
|
+
it "supports much nesting" do
|
103
|
+
template = Curlybars.compile(<<-HBS)
|
104
|
+
{{blog (equal (equal true true) true)}}
|
105
|
+
HBS
|
106
|
+
|
107
|
+
expect(eval(template)).to resemble(<<-HTML)
|
108
|
+
val is true
|
109
|
+
HTML
|
110
|
+
end
|
111
|
+
|
112
|
+
it "with hashes" do
|
113
|
+
template = Curlybars.compile(<<-HBS)
|
114
|
+
{{blog (equal (equal true true) true fun='yes')}}
|
115
|
+
HBS
|
116
|
+
|
117
|
+
expect(eval(template)).to resemble(<<-HTML)
|
118
|
+
val is true
|
119
|
+
HTML
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "with a different blog presenter" do
|
124
|
+
let(:presenter) do
|
125
|
+
IntegrationTest::BlogPresenter.new(
|
126
|
+
lambda { |*args, options|
|
127
|
+
"val is #{options[:fun]}"
|
128
|
+
}
|
129
|
+
)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "as hashes" do
|
133
|
+
template = Curlybars.compile(<<-HBS)
|
134
|
+
{{blog fun=(equal (blog fun=1) 'val is 1')}}
|
135
|
+
HBS
|
136
|
+
|
137
|
+
expect(eval(template)).to resemble(<<-HTML)
|
138
|
+
val is true
|
139
|
+
HTML
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context "with yet another blog presenter" do
|
144
|
+
let(:presenter) do
|
145
|
+
IntegrationTest::BlogPresenter.new(
|
146
|
+
lambda { |*args, options|
|
147
|
+
first, second, third = args
|
148
|
+
"val is #{first}, #{second} and #{third}"
|
149
|
+
}
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "mixed paths and helpers" do
|
154
|
+
template = Curlybars.compile(<<-HBS)
|
155
|
+
{{blog baz.bat (equal a b) baz.bar}}
|
156
|
+
HBS
|
157
|
+
|
158
|
+
expect(eval(template)).to resemble(<<-HTML)
|
159
|
+
val is bat!, true and bar!
|
160
|
+
HTML
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "GH-800 : Complex subexpressions" do
|
165
|
+
let(:presenter) do
|
166
|
+
IntegrationTest::LetterPresenter.new(
|
167
|
+
a: 'a', b: 'b', c: { c: 'c' }, d: 'd', e: { e: 'e' }
|
168
|
+
)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "can handle complex subexpressions" do
|
172
|
+
inputs = [
|
173
|
+
"{{dash 'abc' (concat a b)}}",
|
174
|
+
"{{dash d (concat a b)}}",
|
175
|
+
"{{dash c.c (concat a b)}}",
|
176
|
+
"{{dash (concat a b) c.c}}",
|
177
|
+
"{{dash (concat a e.e) c.c}}"
|
178
|
+
]
|
179
|
+
|
180
|
+
expected_results = [
|
181
|
+
"abc-ab",
|
182
|
+
"d-ab",
|
183
|
+
"c-ab",
|
184
|
+
"ab-c",
|
185
|
+
"ae-c"
|
186
|
+
]
|
187
|
+
|
188
|
+
aggregate_failures do
|
189
|
+
inputs.each_with_index do |input, i|
|
190
|
+
expect(eval(Curlybars.compile(input))).to resemble(expected_results[i])
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
it "multiple subexpressions in a hash" do
|
197
|
+
template = Curlybars.compile(<<-HBS)
|
198
|
+
{{input aria-label=(t "Name") placeholder=(t "Example User")}}
|
199
|
+
HBS
|
200
|
+
|
201
|
+
expected_output = '<input aria-label="Name" placeholder="Example User" />'
|
202
|
+
.gsub("<", "<")
|
203
|
+
.gsub(">", ">")
|
204
|
+
.gsub('"', """)
|
205
|
+
|
206
|
+
expect(eval(template)).to resemble(expected_output)
|
207
|
+
end
|
208
|
+
|
209
|
+
context "with item show presenter" do
|
210
|
+
let(:presenter) do
|
211
|
+
IntegrationTest::ItemShowPresenter.new(field: "Name", placeholder: "Example User")
|
212
|
+
end
|
213
|
+
|
214
|
+
it "multiple subexpressions in a hash with context" do
|
215
|
+
template = Curlybars.compile(<<-HBS)
|
216
|
+
{{input aria-label=(t item.field) placeholder=(t item.placeholder)}}
|
217
|
+
HBS
|
218
|
+
|
219
|
+
expected_output = '<input aria-label="Name" placeholder="Example User" />'
|
220
|
+
.gsub("<", "<")
|
221
|
+
.gsub(">", ">")
|
222
|
+
.gsub('"', """)
|
223
|
+
|
224
|
+
expect(eval(template)).to resemble(expected_output)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe "#validate" do
|
230
|
+
before do
|
231
|
+
allow(Curlybars.configuration).to receive(:global_helpers_provider_classes).and_return([IntegrationTest::GlobalHelperProvider])
|
232
|
+
end
|
233
|
+
|
234
|
+
it "without errors when global helper" do
|
235
|
+
dependency_tree = {}
|
236
|
+
|
237
|
+
source = <<-HBS
|
238
|
+
{{#if (global_helper)}} ... {{/if}}
|
239
|
+
HBS
|
240
|
+
|
241
|
+
errors = Curlybars.validate(dependency_tree, source)
|
242
|
+
|
243
|
+
expect(errors).to be_empty
|
244
|
+
end
|
245
|
+
|
246
|
+
it "with errors when invoking a leaf" do
|
247
|
+
dependency_tree = { name: nil }
|
248
|
+
|
249
|
+
source = <<-HBS
|
250
|
+
{{#if (name)}} ... {{/if}}
|
251
|
+
HBS
|
252
|
+
|
253
|
+
errors = Curlybars.validate(dependency_tree, source)
|
254
|
+
|
255
|
+
expect(errors).not_to be_empty
|
256
|
+
end
|
257
|
+
|
258
|
+
it "without errors if argument is a leaf" do
|
259
|
+
dependency_tree = { helper: :helper, argument: nil }
|
260
|
+
|
261
|
+
source = <<-HBS
|
262
|
+
{{#if (helper argument)}} ... {{/if}}
|
263
|
+
HBS
|
264
|
+
|
265
|
+
errors = Curlybars.validate(dependency_tree, source)
|
266
|
+
|
267
|
+
expect(errors).to be_empty
|
268
|
+
end
|
269
|
+
|
270
|
+
it "without errors if argument is a literal" do
|
271
|
+
dependency_tree = { helper: :helper }
|
272
|
+
|
273
|
+
source = <<-HBS
|
274
|
+
{{#if (helper 'argument')}} ... {{/if}}
|
275
|
+
HBS
|
276
|
+
|
277
|
+
errors = Curlybars.validate(dependency_tree, source)
|
278
|
+
|
279
|
+
expect(errors).to be_empty
|
280
|
+
end
|
281
|
+
|
282
|
+
it "without errors if argument is a variable" do
|
283
|
+
dependency_tree = { helper: :helper }
|
284
|
+
|
285
|
+
source = <<-HBS
|
286
|
+
{{#if (helper @var)}} ... {{/if}}
|
287
|
+
HBS
|
288
|
+
|
289
|
+
errors = Curlybars.validate(dependency_tree, source)
|
290
|
+
|
291
|
+
expect(errors).to be_empty
|
292
|
+
end
|
293
|
+
|
294
|
+
it "without errors if argument is another subexpression" do
|
295
|
+
dependency_tree = { helper: :helper }
|
296
|
+
|
297
|
+
source = <<-HBS
|
298
|
+
{{#if (helper (helper option='argument'))}} ... {{/if}}
|
299
|
+
HBS
|
300
|
+
|
301
|
+
errors = Curlybars.validate(dependency_tree, source)
|
302
|
+
|
303
|
+
expect(errors).to be_empty
|
304
|
+
end
|
305
|
+
|
306
|
+
it "without errors if option is a leaf" do
|
307
|
+
dependency_tree = { helper: :helper, argument: nil }
|
308
|
+
|
309
|
+
source = <<-HBS
|
310
|
+
{{#if (helper option=argument)}} ... {{/if}}
|
311
|
+
HBS
|
312
|
+
|
313
|
+
errors = Curlybars.validate(dependency_tree, source)
|
314
|
+
|
315
|
+
expect(errors).to be_empty
|
316
|
+
end
|
317
|
+
|
318
|
+
it "without errors if option is a literal" do
|
319
|
+
dependency_tree = { helper: :helper }
|
320
|
+
|
321
|
+
source = <<-HBS
|
322
|
+
{{#if (helper option='argument')}} ... {{/if}}
|
323
|
+
HBS
|
324
|
+
|
325
|
+
errors = Curlybars.validate(dependency_tree, source)
|
326
|
+
|
327
|
+
expect(errors).to be_empty
|
328
|
+
end
|
329
|
+
|
330
|
+
it "without errors if option is a variable" do
|
331
|
+
dependency_tree = { helper: :helper }
|
332
|
+
|
333
|
+
source = <<-HBS
|
334
|
+
{{#if (helper option=@var)}} ... {{/if}}
|
335
|
+
HBS
|
336
|
+
|
337
|
+
errors = Curlybars.validate(dependency_tree, source)
|
338
|
+
|
339
|
+
expect(errors).to be_empty
|
340
|
+
end
|
341
|
+
|
342
|
+
it "without errors if option is another subexpression" do
|
343
|
+
dependency_tree = { helper: :helper }
|
344
|
+
|
345
|
+
source = <<-HBS
|
346
|
+
{{#if (helper option=(helper))}} ... {{/if}}
|
347
|
+
HBS
|
348
|
+
|
349
|
+
errors = Curlybars.validate(dependency_tree, source)
|
350
|
+
|
351
|
+
expect(errors).to be_empty
|
352
|
+
end
|
353
|
+
|
354
|
+
it "with errors when helper does not exist" do
|
355
|
+
dependency_tree = {}
|
356
|
+
|
357
|
+
source = <<-HBS
|
358
|
+
{{#if (helper)}} ... {{/if}}
|
359
|
+
HBS
|
360
|
+
|
361
|
+
errors = Curlybars.validate(dependency_tree, source)
|
362
|
+
|
363
|
+
expect(errors).not_to be_empty
|
364
|
+
end
|
365
|
+
|
366
|
+
it "with errors when invoking a leaf with arguments" do
|
367
|
+
dependency_tree = { name: nil }
|
368
|
+
|
369
|
+
source = <<-HBS
|
370
|
+
{{#if (name 'argument')}} ... {{/if}}
|
371
|
+
HBS
|
372
|
+
|
373
|
+
errors = Curlybars.validate(dependency_tree, source)
|
374
|
+
|
375
|
+
expect(errors).not_to be_empty
|
376
|
+
end
|
377
|
+
|
378
|
+
it "with errors when invoking a leaf with options" do
|
379
|
+
dependency_tree = { name: nil }
|
380
|
+
|
381
|
+
source = <<-HBS
|
382
|
+
{{#if (name option='value')}} ... {{/if}}
|
383
|
+
HBS
|
384
|
+
|
385
|
+
errors = Curlybars.validate(dependency_tree, source)
|
386
|
+
|
387
|
+
expect(errors).not_to be_empty
|
388
|
+
end
|
389
|
+
|
390
|
+
it "with errors if argument is not a value" do
|
391
|
+
dependency_tree = { helper: :helper }
|
392
|
+
|
393
|
+
source = <<-HBS
|
394
|
+
{{#if (helper not_a_value)}} ... {{/if}}
|
395
|
+
HBS
|
396
|
+
|
397
|
+
errors = Curlybars.validate(dependency_tree, source)
|
398
|
+
|
399
|
+
expect(errors).not_to be_empty
|
400
|
+
end
|
401
|
+
|
402
|
+
it "with errors if option is not a value" do
|
403
|
+
dependency_tree = { helper: :helper }
|
404
|
+
|
405
|
+
source = <<-HBS
|
406
|
+
{{#if (helper option=not_a_value)}} ... {{/if}}
|
407
|
+
HBS
|
408
|
+
|
409
|
+
errors = Curlybars.validate(dependency_tree, source)
|
410
|
+
|
411
|
+
expect(errors).not_to be_empty
|
412
|
+
end
|
413
|
+
|
414
|
+
it "without errors when invoking a helper with the result of a subexpression" do
|
415
|
+
dependency_tree = { join: :helper, uppercase: :helper, article: nil }
|
416
|
+
|
417
|
+
source = <<-HBS
|
418
|
+
{{join (uppercase article) attribute='title' separator='-'}}
|
419
|
+
HBS
|
420
|
+
|
421
|
+
errors = Curlybars.validate(dependency_tree, source)
|
422
|
+
|
423
|
+
expect(errors).to be_empty
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|