handlebar 0.2.0 → 0.2.1
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.
- data/README.rdoc +40 -1
- data/VERSION +1 -1
- data/handlebar.gemspec +2 -2
- data/lib/handlebar/support.rb +1 -1
- data/lib/handlebar/template.rb +50 -27
- data/test/test_handlebar_template.rb +39 -3
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -1,6 +1,45 @@
|
|
1
1
|
= handlebar
|
2
2
|
|
3
|
-
A simple text
|
3
|
+
A simple text template system for generating output for a variety of uses
|
4
|
+
including plain-text, HTML, and JavaScript.
|
5
|
+
|
6
|
+
== Examples
|
7
|
+
|
8
|
+
The straight-forward usage is substitutions:
|
9
|
+
|
10
|
+
template = Handlebar::Template.new("This {{noun}} is {{adjective}}")
|
11
|
+
|
12
|
+
template.render(:noun => 'shoe', :adjective => 'red')
|
13
|
+
# => "This shoe is red"
|
14
|
+
|
15
|
+
If required, the content can be HTML-escaped automatically:
|
16
|
+
|
17
|
+
template = Handlebar::Template.new(
|
18
|
+
"This {{noun}} is {{adjective}}",
|
19
|
+
:escape => :html
|
20
|
+
)
|
21
|
+
|
22
|
+
template.render(:noun => 'goose', :adjective => '<em>blue</em>')
|
23
|
+
# => "This goose is <em>blue</em>"
|
24
|
+
|
25
|
+
This can also be engaged on a case-by-case basis:
|
26
|
+
|
27
|
+
template = Handlebar::Template.new("This {{&noun}} is {{adjective}}")
|
28
|
+
|
29
|
+
template.render(:noun => '<b>goose</b>', :adjective => '<em>blue</em>')
|
30
|
+
# => "This <b>goose</b> is <em>blue</em>"
|
31
|
+
|
32
|
+
Also available is URI encoding for links:
|
33
|
+
|
34
|
+
template = Handlebar::Template.new(
|
35
|
+
"<a href='/home?user_id={{%user_id}}'>{{&label}}</a>"
|
36
|
+
)
|
37
|
+
|
38
|
+
template.render(:user_id => 'joe&2', :label => 'Joe&2')
|
39
|
+
# => "<a href='/home?user_id=joe%262'>Joe&2</a>"
|
40
|
+
|
41
|
+
A number of other usage cases are described in test/test_handlebar_template.rb
|
42
|
+
as a reference.
|
4
43
|
|
5
44
|
== Copyright
|
6
45
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/handlebar.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{handlebar}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Scott Tadman"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-07-04}
|
13
13
|
s.description = %q{A simple text templating system}
|
14
14
|
s.email = %q{github@tadman.ca}
|
15
15
|
s.extra_rdoc_files = [
|
data/lib/handlebar/support.rb
CHANGED
data/lib/handlebar/template.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Handlebar::Template
|
2
2
|
# == Constants ============================================================
|
3
3
|
|
4
|
-
TOKEN_REGEXP = /((?:[^\{]|\{[^\{]|\{\{\{)+)|\{\{\s*([
|
4
|
+
TOKEN_REGEXP = /((?:[^\{]|\{[^\{]|\{\{\{)+)|\{\{\s*([\&\%\$\.\:\*\/\=]|\?\!?)?([^\}]*)\}\}/.freeze
|
5
5
|
TOKEN_TRIGGER = /\{\{/.freeze
|
6
6
|
|
7
7
|
# == Utility Classes ======================================================
|
@@ -66,7 +66,11 @@ class Handlebar::Template
|
|
66
66
|
when Array
|
67
67
|
variables
|
68
68
|
when Hash
|
69
|
-
|
69
|
+
_variables = variables
|
70
|
+
|
71
|
+
Hash.new do |h, k|
|
72
|
+
h[k] = (_variables[k.to_sym] || _variables[k.to_s])
|
73
|
+
end
|
70
74
|
else
|
71
75
|
[ variables ]
|
72
76
|
end
|
@@ -75,21 +79,20 @@ class Handlebar::Template
|
|
75
79
|
# Unless the template options have already been processed, mapping
|
76
80
|
# will need to be performed.
|
77
81
|
unless (templates.is_a?(TemplateHash))
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
]
|
82
|
+
_templates = templates
|
83
|
+
templates = TemplateHash.new do |h, k|
|
84
|
+
v = _templates[k]
|
85
|
+
|
86
|
+
h[k] =
|
87
|
+
case (v)
|
88
|
+
when Handlebar::Template, Proc, Array
|
89
|
+
v
|
90
|
+
when TOKEN_TRIGGER
|
91
|
+
self.class.new(v, :escape => @escape_method)
|
92
|
+
else
|
93
|
+
v.to_s
|
94
|
+
end
|
95
|
+
end
|
93
96
|
end
|
94
97
|
else
|
95
98
|
templates = TemplateHash.new
|
@@ -100,6 +103,11 @@ class Handlebar::Template
|
|
100
103
|
when Array
|
101
104
|
_parents = parents.dup
|
102
105
|
_parent = _parents.shift
|
106
|
+
|
107
|
+
unless (_parent.is_a?(Handlebar::Template))
|
108
|
+
_parent = self.class.new(_parent, :escape => @escape_method)
|
109
|
+
end
|
110
|
+
|
103
111
|
_parent.render(
|
104
112
|
variables,
|
105
113
|
templates.merge(
|
@@ -114,6 +122,21 @@ class Handlebar::Template
|
|
114
122
|
nil => self.to_proc.call(variables, templates)
|
115
123
|
)
|
116
124
|
)
|
125
|
+
when String
|
126
|
+
_parent = parents
|
127
|
+
|
128
|
+
unless (_parent.is_a?(Handlebar::Template))
|
129
|
+
_parent = self.class.new(_parent, :escape => @escape_method)
|
130
|
+
end
|
131
|
+
|
132
|
+
_parent.render(
|
133
|
+
variables,
|
134
|
+
templates.merge(
|
135
|
+
nil => self.to_proc.call(variables, templates)
|
136
|
+
)
|
137
|
+
)
|
138
|
+
else
|
139
|
+
raise ArgumentError, "Invalid options passed in to parents"
|
117
140
|
end
|
118
141
|
else
|
119
142
|
self.to_proc.call(variables, templates)
|
@@ -141,7 +164,7 @@ class Handlebar::Template
|
|
141
164
|
tag = tag.empty? ? nil : tag.to_sym
|
142
165
|
|
143
166
|
case (tag_type)
|
144
|
-
when
|
167
|
+
when '&'
|
145
168
|
# HTML escaped
|
146
169
|
index = stack[-1][2][tag.inspect]
|
147
170
|
|
@@ -149,28 +172,28 @@ class Handlebar::Template
|
|
149
172
|
|
150
173
|
variables and variables[tag] = true
|
151
174
|
|
152
|
-
when
|
175
|
+
when '%'
|
153
176
|
# URI escaped
|
154
177
|
index = stack[-1][2][tag.inspect]
|
155
178
|
|
156
179
|
source and source << "v&&r<<h.uri_escape(v.is_a?(Array)?v[#{index}]:v[#{tag.inspect}]);"
|
157
180
|
|
158
181
|
variables and variables[tag] = true
|
159
|
-
when
|
182
|
+
when '$'
|
160
183
|
# JavaScript escaped
|
161
184
|
index = stack[-1][2][tag.inspect]
|
162
185
|
|
163
186
|
source and source << "v&&r<<h.js_escape(v.is_a?(Array)?v[#{index}]:v[#{tag.inspect}]);"
|
164
187
|
|
165
188
|
variables and variables[tag] = true
|
166
|
-
when
|
189
|
+
when '.'
|
167
190
|
# CSS escaped
|
168
191
|
index = stack[-1][2][tag.inspect]
|
169
192
|
|
170
193
|
source and source << "v&&r<<h.css_escape(v.is_a?(Array)?v[#{index}]:v[#{tag.inspect}]);"
|
171
194
|
|
172
195
|
variables and variables[tag] = true
|
173
|
-
when
|
196
|
+
when ':'
|
174
197
|
# Defines start of a :section
|
175
198
|
index = stack[-1][2][tag.inspect]
|
176
199
|
|
@@ -181,7 +204,7 @@ class Handlebar::Template
|
|
181
204
|
source and source << "h.iterate(v){|v|;v=h.cast_as_vars(v, s);"
|
182
205
|
|
183
206
|
sections and sections[tag] = true
|
184
|
-
when
|
207
|
+
when '?', '?!'
|
185
208
|
# Defines start of a ?conditional
|
186
209
|
|
187
210
|
stack[-1][2][tag.inspect]
|
@@ -189,14 +212,14 @@ class Handlebar::Template
|
|
189
212
|
# The stack will inherit the variable assignment locations from the
|
190
213
|
# existing stack layer.
|
191
214
|
stack << [ :conditional, tag, stack[-1][2] ]
|
192
|
-
source and source << "if(v&&v.is_a?(Hash)&&v[#{tag.inspect}]);"
|
215
|
+
source and source << "#{tag_type=='?' ? 'if' : 'unless'}(v&&v.is_a?(Hash)&&v[#{tag.inspect}]);"
|
193
216
|
|
194
217
|
variables and variables[tag] = true
|
195
|
-
when
|
218
|
+
when '*'
|
196
219
|
source and source << "_t=t&&t[#{tag.inspect}];r<<(_t.respond_to?(:call)?_t.call(v,t):_t.to_s);"
|
197
220
|
|
198
221
|
templates and templates[tag] = true
|
199
|
-
when
|
222
|
+
when '/'
|
200
223
|
# Closes out a section or conditional
|
201
224
|
closed = stack.pop
|
202
225
|
|
@@ -212,7 +235,7 @@ class Handlebar::Template
|
|
212
235
|
when :base
|
213
236
|
raise ParseError, "Unexpected {{#{tag}}}, too many tags closed"
|
214
237
|
end
|
215
|
-
when
|
238
|
+
when '='
|
216
239
|
# Literal insertion
|
217
240
|
index = stack[-1][2][tag.inspect]
|
218
241
|
|
@@ -33,6 +33,12 @@ class TestHandlebarTemplate < Test::Unit::TestCase
|
|
33
33
|
assert_equal 'false', template.render
|
34
34
|
assert_equal 'true false', template.render(:boolean => true)
|
35
35
|
assert_equal 'false', template.render(:boolean => false)
|
36
|
+
|
37
|
+
template = Handlebar::Template.new('{{?boolean}}true{{/}}{{?!boolean}}false{{/}}')
|
38
|
+
|
39
|
+
assert_equal 'false', template.render
|
40
|
+
assert_equal 'true', template.render(:boolean => true)
|
41
|
+
assert_equal 'false', template.render(:boolean => false)
|
36
42
|
end
|
37
43
|
|
38
44
|
def test_sectioned_templates
|
@@ -71,6 +77,26 @@ class TestHandlebarTemplate < Test::Unit::TestCase
|
|
71
77
|
assert_equal 'child', template.render(nil, { :example => '{{*parent}}', :parent => 'child' }.freeze)
|
72
78
|
end
|
73
79
|
|
80
|
+
def test_dynamic_variables
|
81
|
+
template = Handlebar::Template.new('{{example}}{{text}}', :escape => :html)
|
82
|
+
|
83
|
+
generator = Hash.new do |h, k|
|
84
|
+
h[k] = "<#{k}>"
|
85
|
+
end
|
86
|
+
|
87
|
+
assert_equal '<example><text>', template.render(generator)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_dynamic_templates
|
91
|
+
template = Handlebar::Template.new('<{{*example}}>', :escape => :html)
|
92
|
+
|
93
|
+
generator = Hash.new do |h, k|
|
94
|
+
h[k] = k.to_s.upcase
|
95
|
+
end
|
96
|
+
|
97
|
+
assert_equal '<EXAMPLE>', template.render(nil, generator)
|
98
|
+
end
|
99
|
+
|
74
100
|
def test_missing_templates
|
75
101
|
template = Handlebar::Template.new('{{*example}}', :escape => :html)
|
76
102
|
|
@@ -86,9 +112,9 @@ class TestHandlebarTemplate < Test::Unit::TestCase
|
|
86
112
|
end
|
87
113
|
|
88
114
|
def test_parent_templates
|
89
|
-
parent_template = Handlebar::Template.new('{{a}}[{{*}}]{{b}}')
|
90
|
-
child_template = Handlebar::Template.new('{{c}}{{*}}')
|
91
|
-
final_template = Handlebar::Template.new('{{a}}')
|
115
|
+
parent_template = Handlebar::Template.new('{{a}}[{{*}}]{{b}}'.freeze)
|
116
|
+
child_template = Handlebar::Template.new('{{c}}{{*}}'.freeze)
|
117
|
+
final_template = Handlebar::Template.new('{{a}}'.freeze)
|
92
118
|
|
93
119
|
variables = { :a => 'A', :b => 'B', :c => 'C' }
|
94
120
|
|
@@ -96,6 +122,16 @@ class TestHandlebarTemplate < Test::Unit::TestCase
|
|
96
122
|
assert_equal 'CA', final_template.render(variables, nil, child_template)
|
97
123
|
assert_equal 'A[CA]B', final_template.render(variables, nil, [ child_template, parent_template ].freeze)
|
98
124
|
end
|
125
|
+
|
126
|
+
def test_inline_parent_templates
|
127
|
+
template = Handlebar::Template.new('{{a}}')
|
128
|
+
|
129
|
+
variables = { :a => 'A', :b => 'B', :c => 'C' }
|
130
|
+
|
131
|
+
assert_equal 'A', template.render(variables)
|
132
|
+
assert_equal 'CA', template.render(variables, nil, '{{c}}{{*}}'.freeze)
|
133
|
+
assert_equal 'A[CA]B', template.render(variables, nil, %w[ {{c}}{{*}} {{a}}[{{*}}]{{b}} ].freeze)
|
134
|
+
end
|
99
135
|
|
100
136
|
def test_extract_variables
|
101
137
|
template = Handlebar::Template.new('{{a}}{{?b}}{{=c}}{{/b}}{{&d}}{{$e}}{{.f}}{{%g}}{{:h}}{{i}}{{/h}}')
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: handlebar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.2.
|
5
|
+
version: 0.2.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Scott Tadman
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-07-04 00:00:00 -04:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|