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.
@@ -1,6 +1,45 @@
1
1
  = handlebar
2
2
 
3
- A simple text templating system
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 &lt;em&gt;blue&lt;/em&gt;"
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 &lt;b&gt;goose&lt;/b&gt; 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&amp;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.0
1
+ 0.2.1
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{handlebar}
8
- s.version = "0.2.0"
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-06-30}
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 = [
@@ -3,7 +3,7 @@ require 'cgi'
3
3
 
4
4
  module Handlebar::Support
5
5
  def uri_escape(object)
6
- URI.escape(object.to_s)
6
+ URI.escape(object.to_s, /[^a-z0-9\-\.]/i)
7
7
  end
8
8
 
9
9
  def html_escape(object)
@@ -1,7 +1,7 @@
1
1
  class Handlebar::Template
2
2
  # == Constants ============================================================
3
3
 
4
- TOKEN_REGEXP = /((?:[^\{]|\{[^\{]|\{\{\{)+)|\{\{\s*([\&\%\$\.\:\?\*\/\=])?([^\}]*)\}\}/.freeze
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
- Hash[variables.collect { |k, v| [ k.to_sym, v ] }]
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
- templates = TemplateHash[
79
- templates.collect do |k, v|
80
- [
81
- k,
82
- case (v)
83
- when Handlebar::Template, Proc, Array
84
- v
85
- when TOKEN_TRIGGER
86
- self.class.new(v, :escape => @escape_method)
87
- else
88
- v.to_s
89
- end
90
- ]
91
- end
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 '&lt;example&gt;&lt;text&gt;', 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.0
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-06-30 00:00:00 -04:00
13
+ date: 2011-07-04 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency