mvz-ruby-handlebars 0.0.8 → 0.0.9

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.
@@ -0,0 +1,23 @@
1
+ require_relative 'default_helper'
2
+
3
+ module Handlebars
4
+ module Helpers
5
+ class IfHelper < DefaultHelper
6
+ def self.registry_name
7
+ 'if'
8
+ end
9
+
10
+ def self.apply(context, condition, block, else_block)
11
+ condition = !condition.empty? if condition.respond_to?(:empty?)
12
+
13
+ if condition
14
+ block.fn(context)
15
+ elsif else_block
16
+ else_block.fn(context)
17
+ else
18
+ ""
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ require_relative 'each_helper'
2
+ require_relative 'helper_missing_helper'
3
+ require_relative 'if_helper'
4
+ require_relative 'unless_helper'
5
+
6
+ module Handlebars
7
+ module Helpers
8
+ def self.register_default_helpers(hbs)
9
+ EachHelper.register(hbs)
10
+ HelperMissingHelper.register(hbs)
11
+ IfHelper.register(hbs)
12
+ UnlessHelper.register(hbs)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'default_helper'
2
+
3
+ module Handlebars
4
+ module Helpers
5
+ class UnlessHelper < DefaultHelper
6
+ def self.registry_name
7
+ 'unless'
8
+ end
9
+
10
+ def self.apply(context, condition, block, else_block)
11
+ condition = !condition.empty? if condition.respond_to?(:empty?)
12
+
13
+ unless condition
14
+ block.fn(context)
15
+ else
16
+ else_block ? else_block.fn(context) : ""
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -10,12 +10,21 @@ module Handlebars
10
10
  rule(:slash) { str('/')}
11
11
  rule(:ocurly) { str('{')}
12
12
  rule(:ccurly) { str('}')}
13
+ rule(:pipe) { str('|')}
14
+ rule(:eq) { str('=')}
15
+
13
16
 
14
17
  rule(:docurly) { ocurly >> ocurly }
15
18
  rule(:dccurly) { ccurly >> ccurly }
19
+ rule(:tocurly) { ocurly >> ocurly >> ocurly }
20
+ rule(:tccurly) { ccurly >> ccurly >> ccurly }
21
+
22
+ rule(:else_kw) { str('else') }
23
+ rule(:as_kw) { str('as') }
16
24
 
17
- rule(:identifier) { match['a-zA-Z0-9_\?'].repeat(1) }
18
- rule(:path) { identifier >> (dot >> identifier).repeat }
25
+ rule(:identifier) { (else_kw >> space? >> dccurly).absent? >> match['@\-a-zA-Z0-9_\?'].repeat(1) }
26
+ rule(:directory) { (else_kw >> space? >> dccurly).absent? >> match['@\-a-zA-Z0-9_\/\?'].repeat(1) }
27
+ rule(:path) { identifier >> (dot >> (identifier | else_kw)).repeat }
19
28
 
20
29
  rule(:nocurly) { match('[^{}]') }
21
30
  rule(:eof) { any.absent? }
@@ -27,18 +36,49 @@ module Handlebars
27
36
  ocurly >> eof # Opening curly that doesn't start a {{}} because it's the end
28
37
  ).repeat(1).as(:template_content) }
29
38
 
39
+ rule(:unsafe_replacement) { docurly >> space? >> path.as(:replaced_unsafe_item) >> space? >> dccurly }
40
+ rule(:safe_replacement) { tocurly >> space? >> path.as(:replaced_safe_item) >> space? >> tccurly }
41
+
30
42
  rule(:sq_string) { match("'") >> match("[^']").repeat.maybe.as(:str_content) >> match("'") }
31
43
  rule(:dq_string) { match('"') >> match('[^"]').repeat.maybe.as(:str_content) >> match('"') }
32
44
  rule(:string) { sq_string | dq_string }
33
45
 
34
- rule(:parameter) { (path | string).as(:parameter_name) }
46
+ rule(:parameter) {
47
+ (as_kw >> space? >> pipe).absent? >>
48
+ (
49
+ (path | string).as(:parameter_name) |
50
+ (str('(') >> space? >> identifier.as(:safe_helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> str(')'))
51
+ )
52
+ }
35
53
  rule(:parameters) { parameter >> (space >> parameter).repeat }
36
54
 
37
- rule(:unsafe_helper) { docurly >> space? >> path.as(:helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> dccurly}
38
- rule(:safe_helper) { ocurly >> helper >> ccurly }
55
+ rule(:argument) { identifier.as(:key) >> space? >> eq >> space? >> parameter.as(:value) }
56
+ rule(:arguments) { argument >> (space >> argument).repeat }
57
+
58
+ rule(:unsafe_helper) { docurly >> space? >> identifier.as(:unsafe_helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> dccurly }
59
+ rule(:safe_helper) { tocurly >> space? >> identifier.as(:safe_helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> tccurly }
39
60
 
40
61
  rule(:helper) { unsafe_helper | safe_helper }
41
62
 
63
+ rule(:as_block_helper) {
64
+ docurly >>
65
+ hash >>
66
+ identifier.capture(:helper_name).as(:helper_name) >>
67
+ space >> parameters.as(:parameters) >>
68
+ space >> as_kw >> space >> pipe >> space? >> parameters.as(:as_parameters) >> space? >> pipe >>
69
+ space? >>
70
+ dccurly >>
71
+ scope {
72
+ block
73
+ } >>
74
+ scope {
75
+ docurly >> space? >> else_kw >> space? >> dccurly >> scope { block_item.repeat.as(:else_block_items) }
76
+ }.maybe >>
77
+ dynamic { |src, scope|
78
+ docurly >> slash >> str(scope.captures[:helper_name]) >> dccurly
79
+ }
80
+ }
81
+
42
82
  rule(:block_helper) {
43
83
  docurly >>
44
84
  hash >>
@@ -49,6 +89,9 @@ module Handlebars
49
89
  scope {
50
90
  block
51
91
  } >>
92
+ scope {
93
+ docurly >> space? >> else_kw >> space? >> dccurly >> scope { block_item.repeat.as(:else_block_items) }
94
+ }.maybe >>
52
95
  dynamic { |src, scope|
53
96
  docurly >> slash >> str(scope.captures[:helper_name]) >> dccurly
54
97
  }
@@ -58,12 +101,15 @@ module Handlebars
58
101
  docurly >>
59
102
  gt >>
60
103
  space? >>
61
- identifier.as(:partial_name) >>
104
+ directory.as(:partial_name) >>
105
+ space? >>
106
+ arguments.as(:arguments).maybe >>
62
107
  space? >>
63
108
  dccurly
64
109
  }
65
110
 
66
- rule(:block) { (template_content | helper | partial | block_helper ).repeat.as(:block_items) }
111
+ rule(:block_item) { (template_content | unsafe_replacement | safe_replacement | helper | partial | block_helper | as_block_helper) }
112
+ rule(:block) { block_item.repeat.as(:block_items) }
67
113
 
68
114
  root :block
69
115
  end
@@ -14,6 +14,23 @@ module Handlebars
14
14
  end
15
15
  end
16
16
 
17
+ class Replacement < TreeItem.new(:item)
18
+ def _eval(context)
19
+ helper = context.get_helper(item.to_s)
20
+ if helper && helper.arity == 1
21
+ helper.apply(context)
22
+ else
23
+ context.get(item.to_s)
24
+ end
25
+ end
26
+ end
27
+
28
+ class EscapedReplacement < Replacement
29
+ def _eval(context)
30
+ context.escaper.escape(super(context).to_s)
31
+ end
32
+ end
33
+
17
34
  class String < TreeItem.new(:content)
18
35
  def _eval(context)
19
36
  return content
@@ -30,17 +47,31 @@ module Handlebars
30
47
  end
31
48
  end
32
49
 
33
- class Helper < TreeItem.new(:name, :parameters, :block)
50
+ class Helper < TreeItem.new(:name, :parameters, :block, :else_block)
34
51
  def _eval(context)
35
- if context.get_helper(name.to_s).nil?
36
- context.get(name.to_s)
52
+ helper = context.get_helper(name.to_s)
53
+ if helper.nil?
54
+ context.get_helper('helperMissing').apply(context, String.new(name.to_s))
37
55
  else
38
- context.get_helper(name.to_s).apply(context, parameters, block)
56
+ helper.apply(context, parameters, block, else_block)
39
57
  end
40
58
  end
59
+ end
41
60
 
42
- def is_else?
43
- name.to_s == 'else'
61
+ class AsHelper < TreeItem.new(:name, :parameters, :as_parameters, :block, :else_block)
62
+ def _eval(context)
63
+ helper = context.get_as_helper(name.to_s)
64
+ if helper.nil?
65
+ context.get_helper('helperMissing').apply(context, String.new(name.to_s))
66
+ else
67
+ helper.apply_as(context, parameters, as_parameters, block, else_block)
68
+ end
69
+ end
70
+ end
71
+
72
+ class EscapedHelper < Helper
73
+ def _eval(context)
74
+ context.escaper.escape(super(context).to_s)
44
75
  end
45
76
  end
46
77
 
@@ -50,6 +81,15 @@ module Handlebars
50
81
  end
51
82
  end
52
83
 
84
+ class PartialWithArgs < TreeItem.new(:partial_name, :arguments)
85
+ def _eval(context)
86
+ [arguments].flatten.map(&:values).map do |vals|
87
+ context.add_item vals.first.to_s, vals.last._eval(context)
88
+ end
89
+ context.get_partial(partial_name.to_s).call_with_context(context)
90
+ end
91
+ end
92
+
53
93
  class Block < TreeItem.new(:items)
54
94
  def _eval(context)
55
95
  items.map {|item| item._eval(context)}.join()
@@ -59,22 +99,26 @@ module Handlebars
59
99
  def add_item(i)
60
100
  items << i
61
101
  end
102
+
62
103
  end
63
104
  end
64
105
 
65
106
  class Transform < Parslet::Transform
66
107
  rule(template_content: simple(:content)) {Tree::TemplateContent.new(content)}
108
+ rule(replaced_unsafe_item: simple(:item)) {Tree::EscapedReplacement.new(item)}
109
+ rule(replaced_safe_item: simple(:item)) {Tree::Replacement.new(item)}
67
110
  rule(str_content: simple(:content)) {Tree::String.new(content)}
68
111
  rule(parameter_name: simple(:name)) {Tree::Parameter.new(name)}
69
112
 
70
113
  rule(
71
- helper_name: simple(:name)
114
+ unsafe_helper_name: simple(:name),
115
+ parameters: subtree(:parameters)
72
116
  ) {
73
- Tree::Helper.new(name, [])
117
+ Tree::EscapedHelper.new(name, parameters)
74
118
  }
75
119
 
76
120
  rule(
77
- helper_name: simple(:name),
121
+ safe_helper_name: simple(:name),
78
122
  parameters: subtree(:parameters)
79
123
  ) {
80
124
  Tree::Helper.new(name, parameters)
@@ -82,20 +126,64 @@ module Handlebars
82
126
 
83
127
  rule(
84
128
  helper_name: simple(:name),
85
- block_items: subtree(:block_items)
129
+ block_items: subtree(:block_items),
86
130
  ) {
87
131
  Tree::Helper.new(name, [], block_items)
88
132
  }
89
133
 
134
+ rule(
135
+ helper_name: simple(:name),
136
+ block_items: subtree(:block_items),
137
+ else_block_items: subtree(:else_block_items)
138
+ ) {
139
+ Tree::Helper.new(name, [], block_items, else_block_items)
140
+ }
141
+
90
142
  rule(
91
143
  helper_name: simple(:name),
92
144
  parameters: subtree(:parameters),
93
- block_items: subtree(:block_items)
145
+ block_items: subtree(:block_items),
94
146
  ) {
95
147
  Tree::Helper.new(name, parameters, block_items)
96
148
  }
97
149
 
150
+ rule(
151
+ helper_name: simple(:name),
152
+ parameters: subtree(:parameters),
153
+ block_items: subtree(:block_items),
154
+ else_block_items: subtree(:else_block_items)
155
+ ) {
156
+ Tree::Helper.new(name, parameters, block_items, else_block_items)
157
+ }
158
+
159
+ rule(
160
+ helper_name: simple(:name),
161
+ parameters: subtree(:parameters),
162
+ as_parameters: subtree(:as_parameters),
163
+ block_items: subtree(:block_items),
164
+ ) {
165
+ Tree::AsHelper.new(name, parameters, as_parameters, block_items)
166
+ }
167
+
168
+ rule(
169
+ helper_name: simple(:name),
170
+ parameters: subtree(:parameters),
171
+ as_parameters: subtree(:as_parameters),
172
+ block_items: subtree(:block_items),
173
+ else_block_items: subtree(:else_block_items)
174
+ ) {
175
+ Tree::AsHelper.new(name, parameters, as_parameters, block_items, else_block_items)
176
+ }
177
+
178
+ rule(
179
+ partial_name: simple(:partial_name),
180
+ arguments: subtree(:arguments)
181
+ ) {
182
+ Tree::PartialWithArgs.new(partial_name, arguments)
183
+ }
184
+
98
185
  rule(partial_name: simple(:partial_name)) {Tree::Partial.new(partial_name)}
99
186
  rule(block_items: subtree(:block_items)) {Tree::Block.new(block_items)}
187
+ rule(else_block_items: subtree(:else_block_items)) {Tree::Block.new(block_items)}
100
188
  end
101
189
  end
@@ -1,3 +1,3 @@
1
1
  module Handlebars
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -1,5 +1,7 @@
1
1
  require_relative 'spec_helper'
2
2
  require_relative '../lib/ruby-handlebars'
3
+ require_relative '../lib/ruby-handlebars/escapers/dummy_escaper'
4
+
3
5
 
4
6
  describe Handlebars::Handlebars do
5
7
  let(:hbs) {Handlebars::Handlebars.new}
@@ -17,6 +19,18 @@ describe Handlebars::Handlebars do
17
19
  expect(evaluate('Hello {{name}}', {name: 'world'})).to eq('Hello world')
18
20
  end
19
21
 
22
+ it 'a double braces replacement with unsafe characters' do
23
+ expect(evaluate('Hello {{name}}', {name: '<"\'>&'})).to eq('Hello &lt;&quot;&#39;&gt;&amp;')
24
+ end
25
+
26
+ it 'a double braces replacement with nil' do
27
+ expect(evaluate('Hello {{name}}', {name: nil})).to eq('Hello ')
28
+ end
29
+
30
+ it 'a triple braces replacement with unsafe characters' do
31
+ expect(evaluate('Hello {{{name}}}', {name: '<"\'>&'})).to eq('Hello <"\'>&')
32
+ end
33
+
20
34
  it 'allows values specified by methods' do
21
35
  expect(evaluate('Hello {{name}}', double(name: 'world'))).to eq('Hello world')
22
36
  end
@@ -33,16 +47,55 @@ describe Handlebars::Handlebars do
33
47
  expect(evaluate('My simple template: {{person.name}}', {person: {name: 'Another name'}})).to eq('My simple template: Another name')
34
48
  end
35
49
 
50
+ it 'prefers a replacement even if its name matches a helper' do
51
+ expect(evaluate('Hello {{each}}', {each: 'world'})).to eq('Hello world')
52
+ end
53
+
54
+ it 'handles a parameter with a dash' do
55
+ expect(evaluate('Hello {{first-name}}', double("first-name": 'world'))).to eq('Hello world')
56
+ end
57
+
36
58
  context 'partials' do
37
59
  it 'simple' do
38
60
  hbs.register_partial('plic', "Plic")
39
61
  expect(evaluate("Hello {{> plic}}")).to eq("Hello Plic")
40
62
  end
41
63
 
64
+ it 'using a name with a slash' do
65
+ hbs.register_partial('parent/plic', "Plic")
66
+ expect(evaluate("Hello {{> parent/plic}}")).to eq("Hello Plic")
67
+ end
68
+
69
+ it 'using a name that begins with a slash' do
70
+ hbs.register_partial('/parent/plic', "Plic")
71
+ expect(evaluate("Hello {{> /parent/plic}}")).to eq("Hello Plic")
72
+ end
73
+
42
74
  it 'using context' do
43
75
  hbs.register_partial('brackets', "[{{name}}]")
44
76
  expect(evaluate("Hello {{> brackets}}", {name: 'world'})).to eq("Hello [world]")
45
77
  end
78
+
79
+ it 'with a string argument' do
80
+ hbs.register_partial('with_args', "[{{name}}]")
81
+ expect(evaluate("Hello {{> with_args name='jon'}}")).to eq("Hello [jon]")
82
+ end
83
+
84
+ it 'with string arguments' do
85
+ hbs.register_partial('with_args', "[{{fname}} {{lname}}]")
86
+ expect(evaluate("Hello {{> with_args fname='jon' lname='doe'}}")).to eq("Hello [jon doe]")
87
+ end
88
+
89
+ it 'with variables in arguments' do
90
+ hbs.register_partial('with_args', "[{{fname}} {{lname}}]")
91
+ expect(evaluate("Hello {{> with_args fname='jon' lname=last_name}}", {last_name: 'doe'})).to eq("Hello [jon doe]")
92
+ end
93
+
94
+ it 'with a helper as an argument' do
95
+ hbs.register_helper('wrap_parens') {|context, value| "(#{value})"}
96
+ hbs.register_partial('with_args', "[{{fname}} {{lname}}]")
97
+ expect(evaluate("Hello {{> with_args fname='jon' lname=(wrap_parens 'doe')}}")).to eq("Hello [jon (doe)]")
98
+ end
46
99
  end
47
100
 
48
101
  context 'helpers' do
@@ -60,7 +113,22 @@ describe Handlebars::Handlebars do
60
113
  it 'with multiple arguments, including strings' do
61
114
  hbs.register_helper('add') {|context, left, op, right| "#{left} #{op} #{right}"}
62
115
 
63
- expect(evaluate("{{add left '&' right}}", {left: 'Law', right: 'Order'})).to eq("Law & Order")
116
+ expect(evaluate("{{add left '&' right}}", {left: 'Law', right: 'Order'})).to eq("Law &amp; Order")
117
+ expect(evaluate("{{{add left '&' right}}}", {left: 'Law', right: 'Order'})).to eq("Law & Order")
118
+ end
119
+
120
+ it 'with an empty string argument' do
121
+ hbs.register_helper('noah') {|context, value| value.to_s.gsub(/a/, '')}
122
+
123
+ expect(evaluate("hey{{noah ''}}there", {})).to eq("heythere")
124
+ end
125
+
126
+ it 'with helpers as arguments' do
127
+ hbs.register_helper('wrap_parens') {|context, value| "(#{value})"}
128
+ hbs.register_helper('wrap_dashes') {|context, value| "-#{value}-"}
129
+
130
+ expect(evaluate('{{wrap_dashes (wrap_parens "hello")}}', {})).to eq("-(hello)-")
131
+ expect(evaluate('{{wrap_dashes (wrap_parens world)}}', {world: "world"})).to eq("-(world)-")
64
132
  end
65
133
 
66
134
  it 'with an empty string argument' do
@@ -115,213 +183,95 @@ describe Handlebars::Handlebars do
115
183
  data = {company: {people: ['a', 'b', 'c']}}
116
184
  expect(evaluate("{{#each company.people}}{{{this}}}{{/each}}", data)).to eq('abc')
117
185
  end
186
+
187
+ it 'a else keyword out of a helper will raise an error' do
188
+ expect { evaluate('My {{ else }} template') }.to raise_exception(Parslet::ParseFailed)
189
+ end
190
+
191
+ it '"else" can be part of a path' do
192
+ expect(evaluate('My {{ something.else }} template', { something: { else: 'awesome' }})).to eq('My awesome template')
193
+ end
118
194
  end
119
195
 
120
- context 'default helpers' do
121
- context 'if' do
122
- it 'without else' do
123
- template = [
124
- "{{#if condition}}",
125
- " Show something",
126
- "{{/if}}"
127
- ].join("\n")
128
- expect(evaluate(template, {condition: true})).to eq("\n Show something\n")
129
- expect(evaluate(template, {condition: false})).to eq("")
196
+ context 'as_helpers' do
197
+ it 'can be used to have names parameters inside the block' do
198
+ hbs.register_as_helper('test_with') do |context, value, name, block|
199
+ context.with_temporary_context(name => value) do
200
+ block.fn(context)
201
+ end
130
202
  end
131
203
 
132
- it 'with an else' do
133
- template = [
134
- "{{#if condition}}",
135
- " Show something",
136
- "{{ else }}",
137
- " Do not show something",
138
- "{{/if}}"
139
- ].join("\n")
140
- expect(evaluate(template, {condition: true})).to eq("\n Show something\n")
141
- expect(evaluate(template, {condition: false})).to eq("\n Do not show something\n")
142
- end
204
+ expect(evaluate("{{#test_with name as |duck|}}Duck name is: {{duck}}{{/test_with}}", {name: "Dewey"})).to eq('Duck name is: Dewey')
205
+ end
206
+
207
+ it 'can have multiple "as" parameters' do
208
+ hbs.register_as_helper('test_with') do |context, value1, value2, name1, name2, block|
209
+ mapping = {}
210
+ mapping[name1] = value1
211
+ mapping[name2] = value2
143
212
 
144
- it 'imbricated ifs' do
145
- template = [
146
- "{{#if first_condition}}",
147
- " {{#if second_condition}}",
148
- " Case 1",
149
- " {{else}}",
150
- " Case 2",
151
- " {{/if}}",
152
- "{{else}}",
153
- " {{#if second_condition}}",
154
- " Case 3",
155
- " {{else}}",
156
- " Case 4",
157
- " {{/if}}",
158
- "{{/if}}"
159
- ].join("\n")
160
-
161
- expect(evaluate(template, {first_condition: true, second_condition: true}).strip).to eq("Case 1")
162
- expect(evaluate(template, {first_condition: true, second_condition: false}).strip).to eq("Case 2")
163
- expect(evaluate(template, {first_condition: false, second_condition: true}).strip).to eq("Case 3")
164
- expect(evaluate(template, {first_condition: false, second_condition: false}).strip).to eq("Case 4")
213
+ context.with_temporary_context(mapping) do
214
+ block.fn(context)
215
+ end
165
216
  end
217
+
218
+ expect(evaluate("{{#test_with name1 name2 as |duck1 duck2|}}Duck names are {{duck1}} and {{duck2}}{{/test_with}}", {name1: "Huey", name2: "Dewey"})).to eq('Duck names are Huey and Dewey')
166
219
  end
220
+ end
221
+ end
167
222
 
168
- context 'each' do
169
- let(:ducks) {[{name: 'Huey'}, {name: 'Dewey'}, {name: 'Louis'}]}
170
-
171
- it 'simple case' do
172
- template = [
173
- "<ul>",
174
- "{{#each items}} <li>{{this.name}}</li>",
175
- "{{/each}}</ul>"
176
- ].join("\n")
177
-
178
- data = {items: ducks}
179
- expect(evaluate(template, data)).to eq([
180
- "<ul>",
181
- " <li>Huey</li>",
182
- " <li>Dewey</li>",
183
- " <li>Louis</li>",
184
- "</ul>"
185
- ].join("\n"))
186
-
187
- data = {items: []}
188
- expect(evaluate(template, data)).to eq([
189
- "<ul>",
190
- "</ul>"
191
- ].join("\n"))
192
- end
223
+ context 'escaping characters' do
224
+ let(:escaper) { nil }
225
+ let(:name) { '<"\'>&' }
226
+ let(:replacement_escaped) { evaluate('Hello {{ name }}', {name: name}) }
227
+ let(:helper_replacement_escaped) {
228
+ hbs.register_helper('wrap_parens') {|context, value| "(#{value})"}
229
+ evaluate('Hello {{wrap_parens name}}', {name: name})
230
+ }
231
+
232
+ before do
233
+ hbs.set_escaper(escaper)
234
+ end
193
235
 
194
- it 'considers not found items as an empty list and does not raise an error' do
195
- template = [
196
- "<ul>",
197
- "{{#each stuff}} <li>{{this.name}}</li>",
198
- "{{/each}}</ul>"
199
- ].join("\n")
200
-
201
- expect(evaluate(template, {})).to eq([
202
- "<ul>",
203
- "</ul>"
204
- ].join("\n"))
205
- end
236
+ context 'default escaper' do
237
+ it 'escapes HTML characters in simple replacements' do
238
+ expect(replacement_escaped).to eq('Hello &lt;&quot;&#39;&gt;&amp;')
239
+ end
206
240
 
207
- it 'considers not found items as an empty list and uses else block if provided' do
208
- template = [
209
- "<ul>",
210
- "{{#each stuff}} <li>{{this.name}}</li>",
211
- "{{else}} <li>No stuff found....</li>",
212
- "{{/each}}</ul>"
213
- ].join("\n")
214
-
215
- expect(evaluate(template, {})).to eq([
216
- "<ul>",
217
- " <li>No stuff found....</li>",
218
- "</ul>"
219
- ].join("\n"))
220
- end
241
+ it 'escapes HTML characters in helpers' do
242
+ expect(helper_replacement_escaped).to eq('Hello (&lt;&quot;&#39;&gt;&amp;)')
243
+ end
244
+ end
221
245
 
222
- it 'works with non-hash data' do
223
- template = [
224
- "<ul>",
225
- "{{#each items}} <li>{{this.name}}</li>",
226
- "{{/each}}</ul>"
227
- ].join("\n")
228
-
229
- data = double(items: ducks)
230
- expect(evaluate(template, data)).to eq([
231
- "<ul>",
232
- " <li>Huey</li>",
233
- " <li>Dewey</li>",
234
- " <li>Louis</li>",
235
- "</ul>"
236
- ].join("\n"))
237
-
238
- data = {items: []}
239
- expect(evaluate(template, data)).to eq([
240
- "<ul>",
241
- "</ul>"
242
- ].join("\n"))
243
- end
246
+ context 'DummyEscaper' do
247
+ let(:escaper) { Handlebars::Escapers::DummyEscaper }
244
248
 
245
- it 'using an else statement' do
246
- template = [
247
- "<ul>",
248
- "{{#each items}} <li>{{this.name}}</li>",
249
- "{{else}} <li>No ducks to display</li>",
250
- "{{/each}}</ul>"
251
- ].join("\n")
252
-
253
- data = {items: ducks}
254
- expect(evaluate(template, data)).to eq([
255
- "<ul>",
256
- " <li>Huey</li>",
257
- " <li>Dewey</li>",
258
- " <li>Louis</li>",
259
- "</ul>"
260
- ].join("\n"))
261
-
262
- data = {items: []}
263
- expect(evaluate(template, data)).to eq([
264
- "<ul>",
265
- " <li>No ducks to display</li>",
266
- "</ul>"
267
- ].join("\n"))
268
- end
249
+ it 'escapes nothing' do
250
+ expect(replacement_escaped).to eq('Hello <"\'>&')
251
+ end
252
+
253
+ it 'escapes nothing in helpers' do
254
+ expect(helper_replacement_escaped).to eq('Hello (<"\'>&)')
255
+ end
256
+ end
269
257
 
270
- it 'imbricated' do
271
- data = {people: [
272
- {
273
- name: 'Huey',
274
- email: 'huey@junior-woodchucks.example.com',
275
- phones: ['1234', '5678'],
276
- },
277
- {
278
- name: 'Dewey',
279
- email: 'dewey@junior-woodchucks.example.com',
280
- phones: ['4321'],
281
- }
282
- ]}
283
-
284
- template = [
285
- "People:",
286
- "<ul>",
287
- " {{#each people}}",
288
- " <li>",
289
- " <ul>",
290
- " <li>Name: {{this.name}}</li>",
291
- " <li>Phones: {{#each this.phones}} {{this}} {{/each}}</li>",
292
- " <li>email: {{this.email}}</li>",
293
- " </ul>",
294
- " </li>",
295
- " {{else}}",
296
- " <li>No one to display</li>",
297
- " {{/each}}",
298
- "</ul>"
299
- ].join("\n")
300
-
301
- expect(evaluate(template, data)).to eq([
302
- "People:",
303
- "<ul>",
304
- " ",
305
- " <li>",
306
- " <ul>",
307
- " <li>Name: Huey</li>",
308
- " <li>Phones: 1234 5678 </li>",
309
- " <li>email: huey@junior-woodchucks.example.com</li>",
310
- " </ul>",
311
- " </li>",
312
- " ",
313
- " <li>",
314
- " <ul>",
315
- " <li>Name: Dewey</li>",
316
- " <li>Phones: 4321 </li>",
317
- " <li>email: dewey@junior-woodchucks.example.com</li>",
318
- " </ul>",
319
- " </li>",
320
- " ",
321
- "</ul>"
322
- ].join("\n"))
258
+ context 'custom escaper' do
259
+ class VowelEscaper
260
+ def self.escape(value)
261
+ value.gsub(/([aeiuo])/, '-\1')
323
262
  end
324
263
  end
264
+
265
+ let(:escaper) { VowelEscaper }
266
+ let(:name) { 'Her Serene Highness' }
267
+
268
+ it 'applies the escaping' do
269
+ expect(replacement_escaped).to eq('Hello H-er S-er-en-e H-ighn-ess')
270
+ end
271
+
272
+ it 'applies the escaping in helpers' do
273
+ expect(helper_replacement_escaped).to eq('Hello (H-er S-er-en-e H-ighn-ess)')
274
+ end
325
275
  end
326
276
  end
327
277
  end