handlebar 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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