feather 0.3.1 → 0.4.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.
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/RELEASES.txt +19 -0
- data/VERSION +1 -1
- data/feather.gemspec +4 -3
- data/lib/feather.rb +2 -0
- data/lib/feather/template.rb +33 -4
- data/test/helper.rb +1 -2
- data/test/test_feather_template.rb +19 -0
- metadata +4 -3
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# feather
|
2
2
|
|
3
|
-
A simple text template system for generating output for a
|
4
|
-
including plain-text, HTML, and JavaScript.
|
3
|
+
A simple text template system inspired by Mustache for generating output for a
|
4
|
+
variety of uses including plain-text, HTML, and JavaScript.
|
5
5
|
|
6
6
|
## Examples
|
7
7
|
|
data/RELEASES.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
0.4.0
|
2
|
+
- Made more compatible with the Mustache template library semantics.
|
3
|
+
- Added support for {{#...}} section definitions.
|
4
|
+
- Added support for {{^...}} negative definitions.
|
5
|
+
- Added support for {{!...}} comments.
|
6
|
+
0.3.1
|
7
|
+
- Template names can be supplied as either Strings or Symbols.
|
8
|
+
- Variables can be defined with either String or Symbol keys.
|
9
|
+
0.3.0
|
10
|
+
- Renaming library to Feather.
|
11
|
+
0.2.2
|
12
|
+
- Handling nil template arguments and empty template substitutions.
|
13
|
+
0.2.1
|
14
|
+
- Adding support for Hash-compatible objects to be passed in, responding to
|
15
|
+
the [] method is sufficient.
|
16
|
+
0.2.0
|
17
|
+
- Adding ? and ?! conditional tests.
|
18
|
+
0.1.0
|
19
|
+
- Initial thin prototype.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/feather.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "feather"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
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 = "2013-
|
12
|
+
s.date = "2013-04-09"
|
13
13
|
s.description = "A simple light-weight text templating system"
|
14
14
|
s.email = "github@tadman.ca"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
"Gemfile",
|
22
22
|
"LICENSE.txt",
|
23
23
|
"README.md",
|
24
|
+
"RELEASES.txt",
|
24
25
|
"Rakefile",
|
25
26
|
"VERSION",
|
26
27
|
"feather.gemspec",
|
@@ -36,7 +37,7 @@ Gem::Specification.new do |s|
|
|
36
37
|
s.homepage = "http://github.com/twg/feather"
|
37
38
|
s.licenses = ["MIT"]
|
38
39
|
s.require_paths = ["lib"]
|
39
|
-
s.rubygems_version = "1.8.
|
40
|
+
s.rubygems_version = "1.8.25"
|
40
41
|
s.summary = "Light-weight text tempating system"
|
41
42
|
|
42
43
|
if s.respond_to? :specification_version then
|
data/lib/feather.rb
CHANGED
@@ -6,12 +6,14 @@ module Feather
|
|
6
6
|
|
7
7
|
# == Module Methods =======================================================
|
8
8
|
|
9
|
+
# Returns the current library version
|
9
10
|
def self.version
|
10
11
|
@version ||= File.readlines(
|
11
12
|
File.expand_path('../VERSION', File.dirname(__FILE__))
|
12
13
|
).first.chomp
|
13
14
|
end
|
14
15
|
|
16
|
+
# Create a new template with a supplied template body and optional options.
|
15
17
|
def self.new(*args)
|
16
18
|
template = Feather::Template.new(*args)
|
17
19
|
|
data/lib/feather/template.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Feather::Template
|
2
2
|
# == Constants ============================================================
|
3
3
|
|
4
|
-
TOKEN_REGEXP = /((?:[^\{]|\{[^\{]|\{\{\{)+)|\{\{\s*([
|
4
|
+
TOKEN_REGEXP = /((?:[^\{]|\{[^\{]|\{\{\{)+)|\{\{\s*([\&\%\$\.\:\#\^\*\/\=\!]|\?\!?)?([^\}]*)\}\}/.freeze
|
5
5
|
TOKEN_TRIGGER = /\{\{/.freeze
|
6
6
|
|
7
7
|
TO_YAML_PROPERTIES = %w[ @content @escape_method ].freeze
|
@@ -29,6 +29,9 @@ class Feather::Template
|
|
29
29
|
|
30
30
|
# == Instance Methods =====================================================
|
31
31
|
|
32
|
+
# Creates a new template with the supplied contens. Options may be specified:
|
33
|
+
# * :html - Automatically escape fields for HTML
|
34
|
+
# * :text - Default mode, render all fields literally
|
32
35
|
def initialize(content, options = nil)
|
33
36
|
if (options)
|
34
37
|
if (source = options[:escape])
|
@@ -54,6 +57,7 @@ class Feather::Template
|
|
54
57
|
yield(self) if (block_given?)
|
55
58
|
end
|
56
59
|
|
60
|
+
# Returns a function that can be used to evaluate the template.
|
57
61
|
def to_proc
|
58
62
|
@_proc ||= begin
|
59
63
|
source = ''
|
@@ -64,6 +68,10 @@ class Feather::Template
|
|
64
68
|
end
|
65
69
|
end
|
66
70
|
|
71
|
+
# Render the template with the given variables, templates, and parent chain.
|
72
|
+
# The variables are specified in a Hash, Array, or object that supports
|
73
|
+
# [](key). templates must be a Hash or [](key) accessible object. The parents
|
74
|
+
# chain is defined as an array.
|
67
75
|
def render(variables = nil, templates = nil, parents = nil)
|
68
76
|
variables = Feather::Support.variable_stack(variables, true)
|
69
77
|
|
@@ -138,6 +146,12 @@ class Feather::Template
|
|
138
146
|
end
|
139
147
|
alias_method :call, :render
|
140
148
|
|
149
|
+
# Compiles a template and manipulates the options strucutre passed in. Keys
|
150
|
+
# supported are:
|
151
|
+
# * :escape_method - Defines the default escape method for this template.
|
152
|
+
# * :templates - Hash to capture the templates referenced in this template.
|
153
|
+
# * :variables - Hash to capture the variables referenced in this template.
|
154
|
+
# * :source - String to capture the Ruby equivalent of this template.
|
141
155
|
def compile(options)
|
142
156
|
escape_method = options[:escape_method]
|
143
157
|
sections = options[:sections]
|
@@ -165,7 +179,6 @@ class Feather::Template
|
|
165
179
|
source and source << "v&&r<<h.html_escape(v[#{tag.inspect}].to_s);"
|
166
180
|
|
167
181
|
variables and variables[tag] = true
|
168
|
-
|
169
182
|
when '%'
|
170
183
|
# URI escaped
|
171
184
|
index = stack[-1][2][tag.inspect]
|
@@ -187,8 +200,8 @@ class Feather::Template
|
|
187
200
|
source and source << "v&&r<<h.css_escape(v.is_a?(Array)?v[#{index}]:v[#{tag.inspect}]);"
|
188
201
|
|
189
202
|
variables and variables[tag] = true
|
190
|
-
when ':'
|
191
|
-
# Defines start of a :section
|
203
|
+
when ':', '#'
|
204
|
+
# Defines start of a :section or #section
|
192
205
|
index = stack[-1][2][tag.inspect]
|
193
206
|
|
194
207
|
stack_variables ||= 's=[];'
|
@@ -198,6 +211,16 @@ class Feather::Template
|
|
198
211
|
source and source << "h.iterate(v){|v|;v=h.cast_as_vars(v, s);"
|
199
212
|
|
200
213
|
sections and sections[tag] = true
|
214
|
+
when '^'
|
215
|
+
# Displays if referenced variable is undefined or empty
|
216
|
+
index = stack[-1][2][tag.inspect]
|
217
|
+
|
218
|
+
stack_variables ||= 's=[];'
|
219
|
+
stack << [ :empty_section, tag, stack[-1][2] ]
|
220
|
+
|
221
|
+
source and source << "t=v.is_a?(Array)?v[#{index}]:(v.is_a?(Hash)&&v[#{tag.inspect}]);if(!t||t.respond_to?(:empty?)&&t.empty?);"
|
222
|
+
|
223
|
+
variables and variables[tag] = true
|
201
224
|
when '?', '?!'
|
202
225
|
# Defines start of a ?conditional
|
203
226
|
|
@@ -222,6 +245,8 @@ class Feather::Template
|
|
222
245
|
end
|
223
246
|
|
224
247
|
source and source << "};v=s.pop;end;"
|
248
|
+
when :empty_section
|
249
|
+
source and source << "end;"
|
225
250
|
when :conditional
|
226
251
|
source and source << "end;"
|
227
252
|
when :base
|
@@ -269,10 +294,12 @@ class Feather::Template
|
|
269
294
|
true
|
270
295
|
end
|
271
296
|
|
297
|
+
# For compatibility with YAML.dump
|
272
298
|
def to_yaml_properties
|
273
299
|
TO_YAML_PROPERTIES
|
274
300
|
end
|
275
301
|
|
302
|
+
# For compatibility with the Psych YAML library
|
276
303
|
def psych_to_yaml(dump)
|
277
304
|
# Avoid serializing the generated proc by moving it to a temporary
|
278
305
|
# variable for the duration of this operation.
|
@@ -285,10 +312,12 @@ class Feather::Template
|
|
285
312
|
dump
|
286
313
|
end
|
287
314
|
|
315
|
+
# For compatibility with Marshal.dump
|
288
316
|
def marshal_dump
|
289
317
|
[ @content, { :escape => @escape_method } ]
|
290
318
|
end
|
291
319
|
|
320
|
+
# For compatibility with Marshal.load
|
292
321
|
def marshal_load(dump)
|
293
322
|
@content, options = dump
|
294
323
|
|
data/test/helper.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
|
3
2
|
require 'test/unit'
|
4
3
|
|
5
4
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
@@ -14,7 +13,7 @@ class Test::Unit::TestCase
|
|
14
13
|
rescue exception_class
|
15
14
|
# Expected
|
16
15
|
else
|
17
|
-
flunk
|
16
|
+
flunk(message || "Did not raise #{exception_class}")
|
18
17
|
end
|
19
18
|
end
|
20
19
|
end
|
@@ -79,6 +79,25 @@ class TestFeatherTemplate < Test::Unit::TestCase
|
|
79
79
|
assert_equal '<div></div>', template.render(:link => nil)
|
80
80
|
assert_equal '<div></div>', template.render(:link => [ ])
|
81
81
|
end
|
82
|
+
|
83
|
+
def test_empty_section
|
84
|
+
template = Feather::Template.new('<head>{{:head}}{{tag}}{{/head}}{{^head}}<title></title>{{/head}}</head>')
|
85
|
+
|
86
|
+
assert_equal '<head><title></title></head>', template.render
|
87
|
+
assert_equal '<head><title></title></head>', template.render(:head => nil)
|
88
|
+
assert_equal '<head><title></title></head>', template.render(:head => '')
|
89
|
+
assert_equal '<head><title></title></head>', template.render(:head => [ ])
|
90
|
+
assert_equal '<head><title></title></head>', template.render(:head => { })
|
91
|
+
assert_equal '<head>0</head>', template.render(:head => 0)
|
92
|
+
assert_equal '<head><test><tags></head>', template.render(:head => %w[ <test> <tags> ])
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_comment
|
96
|
+
template = Feather::Template.new('<test>{{!commment with all kinds of <markup>}}</test>')
|
97
|
+
|
98
|
+
assert_equal '<test></test>', template.render
|
99
|
+
assert_equal '<test></test>', template.render(:comment => 'test')
|
100
|
+
end
|
82
101
|
|
83
102
|
def test_template_with_context
|
84
103
|
template = Feather::Template.new('{{example}}', :escape => :html)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feather
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-04-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: jeweler
|
@@ -39,6 +39,7 @@ files:
|
|
39
39
|
- Gemfile
|
40
40
|
- LICENSE.txt
|
41
41
|
- README.md
|
42
|
+
- RELEASES.txt
|
42
43
|
- Rakefile
|
43
44
|
- VERSION
|
44
45
|
- feather.gemspec
|
@@ -71,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
72
|
version: '0'
|
72
73
|
requirements: []
|
73
74
|
rubyforge_project:
|
74
|
-
rubygems_version: 1.8.
|
75
|
+
rubygems_version: 1.8.25
|
75
76
|
signing_key:
|
76
77
|
specification_version: 3
|
77
78
|
summary: Light-weight text tempating system
|