temple 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/temple.rb +5 -2
- data/lib/temple/core.rb +2 -9
- data/lib/temple/engine.rb +2 -2
- data/lib/temple/filters/multi_flattener.rb +12 -9
- data/lib/temple/generator.rb +2 -10
- data/lib/temple/html/fast.rb +159 -0
- data/lib/temple/parsers/erb.rb +11 -4
- data/lib/temple/utils.rb +10 -1
- data/temple.gemspec +2 -2
- data/test/filters/test_dynamic_inliner.rb +3 -3
- data/test/test_generator.rb +4 -26
- metadata +3 -4
- data/lib/temple/filters/escapable.rb +0 -32
- data/test/filters/test_escapable.rb +0 -28
data/lib/temple.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Temple
|
2
|
-
VERSION = "0.1.
|
2
|
+
VERSION = "0.1.2"
|
3
3
|
|
4
4
|
autoload :Core, 'temple/core'
|
5
5
|
autoload :Engine, 'temple/engine'
|
@@ -18,6 +18,9 @@ module Temple
|
|
18
18
|
autoload :MultiFlattener, 'temple/filters/multi_flattener'
|
19
19
|
autoload :StaticMerger, 'temple/filters/static_merger'
|
20
20
|
autoload :DynamicInliner, 'temple/filters/dynamic_inliner'
|
21
|
-
|
21
|
+
end
|
22
|
+
|
23
|
+
module HTML
|
24
|
+
autoload :Fast, 'temple/html/fast'
|
22
25
|
end
|
23
26
|
end
|
data/lib/temple/core.rb
CHANGED
@@ -25,8 +25,6 @@ module Temple
|
|
25
25
|
# === [:static, string]
|
26
26
|
#
|
27
27
|
# Static indicates that the given string should be appended to the result.
|
28
|
-
# Every \n will be also cause a newline in the generated code. \r\n on the
|
29
|
-
# other hand, only causes a newline in the result.
|
30
28
|
#
|
31
29
|
# Example:
|
32
30
|
#
|
@@ -35,18 +33,13 @@ module Temple
|
|
35
33
|
# _buf << "Hello World"
|
36
34
|
#
|
37
35
|
# [:static, "Hello \n World"]
|
38
|
-
# # is the same as:
|
39
|
-
# _buf << "Hello
|
40
|
-
# World"
|
41
|
-
#
|
42
|
-
# [:static, "Hello \r\n World"]
|
43
36
|
# # is the same as
|
44
37
|
# _buf << "Hello\nWorld"
|
45
38
|
#
|
46
39
|
# === [:dynamic, ruby]
|
47
40
|
#
|
48
41
|
# Dynamic indicates that the given Ruby code should be evaluated and then
|
49
|
-
# appended to the result.
|
42
|
+
# appended to the result.
|
50
43
|
#
|
51
44
|
# The Ruby code must be a complete expression in the sense that you can pass
|
52
45
|
# it to eval() and it would not raise SyntaxError.
|
@@ -129,4 +122,4 @@ module Temple
|
|
129
122
|
end
|
130
123
|
end
|
131
124
|
end
|
132
|
-
end
|
125
|
+
end
|
data/lib/temple/engine.rb
CHANGED
@@ -47,7 +47,7 @@ module Temple
|
|
47
47
|
|
48
48
|
def initialize(options = {})
|
49
49
|
@chain = self.class.filters.map do |filter, args, blk|
|
50
|
-
opt = args.last.is_a?(Hash) ? args.
|
50
|
+
opt = args.last.is_a?(Hash) ? args.last : {}
|
51
51
|
opt = args.inject(opt) do |memo, ele|
|
52
52
|
memo[ele] = options[ele] if options.has_key?(ele)
|
53
53
|
memo
|
@@ -61,4 +61,4 @@ module Temple
|
|
61
61
|
@chain.inject(thing) { |m, e| e.compile(m) }
|
62
62
|
end
|
63
63
|
end
|
64
|
-
end
|
64
|
+
end
|
@@ -4,19 +4,22 @@ module Temple
|
|
4
4
|
def initialize(options = {})
|
5
5
|
@options = {}
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def compile(exp)
|
9
|
-
|
9
|
+
exp.first == :multi ? on_multi(*exp[1..-1]) : exp
|
10
|
+
end
|
11
|
+
|
12
|
+
def on_multi(*exps)
|
10
13
|
# If the multi contains a single element, just return the element
|
11
|
-
return compile(
|
14
|
+
return compile(exps.first) if exps.length == 1
|
12
15
|
result = [:multi]
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
if
|
17
|
-
result.concat(
|
17
|
+
exps.each do |exp|
|
18
|
+
exp = compile(exp)
|
19
|
+
if exp.first == :multi
|
20
|
+
result.concat(exp[1..-1])
|
18
21
|
else
|
19
|
-
result <<
|
22
|
+
result << exp
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
@@ -24,4 +27,4 @@ module Temple
|
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
27
|
-
end
|
30
|
+
end
|
data/lib/temple/generator.rb
CHANGED
@@ -26,15 +26,7 @@ module Temple
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.to_ruby(str)
|
29
|
-
str.inspect
|
30
|
-
if $`[-1] == ?\\
|
31
|
-
str
|
32
|
-
elsif $1
|
33
|
-
"\\n"
|
34
|
-
else
|
35
|
-
"\n"
|
36
|
-
end
|
37
|
-
end
|
29
|
+
str.inspect
|
38
30
|
end
|
39
31
|
|
40
32
|
def to_ruby(str)
|
@@ -83,4 +75,4 @@ module Temple
|
|
83
75
|
@options[:buffer] = prev_buffer
|
84
76
|
end
|
85
77
|
end
|
86
|
-
end
|
78
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module Temple
|
2
|
+
module HTML
|
3
|
+
class Fast
|
4
|
+
DEFAULT_OPTIONS = {
|
5
|
+
:format => :xhtml,
|
6
|
+
:attr_wrapper => "'",
|
7
|
+
:autoclose => %w[meta img link br hr input area param col base]
|
8
|
+
}
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
12
|
+
|
13
|
+
unless [:xhtml, :html4, :html5].include?(@options[:format])
|
14
|
+
raise "Invalid format #{@options[:format].inspect}"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def xhtml?
|
20
|
+
@options[:format] == :xhtml
|
21
|
+
end
|
22
|
+
|
23
|
+
def html?
|
24
|
+
html5? or html4?
|
25
|
+
end
|
26
|
+
|
27
|
+
def html5?
|
28
|
+
@options[:format] == :html5
|
29
|
+
end
|
30
|
+
|
31
|
+
def html4?
|
32
|
+
@options[:format] == :html4
|
33
|
+
end
|
34
|
+
|
35
|
+
def compile(exp)
|
36
|
+
case exp[0]
|
37
|
+
when :multi, :capture
|
38
|
+
send("on_#{exp[0]}", *exp[1..-1])
|
39
|
+
when :html
|
40
|
+
send("on_#{exp[1]}", *exp[2..-1])
|
41
|
+
else
|
42
|
+
exp
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_multi(*exp)
|
47
|
+
[:multi, *exp.map { |e| compile(e) }]
|
48
|
+
end
|
49
|
+
|
50
|
+
def on_doctype(type)
|
51
|
+
trailing_newlines = type[/(\A|[^\r])(\n+)\Z/, 2].to_s
|
52
|
+
|
53
|
+
text = type.to_s.downcase.strip
|
54
|
+
if text.index("xml") == 0
|
55
|
+
if html?
|
56
|
+
return [:multi].concat([[:newline]] * trailing_newlines.size)
|
57
|
+
end
|
58
|
+
|
59
|
+
wrapper = @options[:attr_wrapper]
|
60
|
+
str = "<?xml version=#{wrapper}1.0#{wrapper} encoding=#{wrapper}#{text.split(' ')[1] || "utf-8"}#{wrapper} ?>"
|
61
|
+
end
|
62
|
+
|
63
|
+
str = "<!DOCTYPE html>" if html5?
|
64
|
+
|
65
|
+
str ||= if xhtml?
|
66
|
+
case text
|
67
|
+
when /^1\.1/; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
|
68
|
+
when /^5/; '<!DOCTYPE html>'
|
69
|
+
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
70
|
+
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
|
71
|
+
when "mobile"; '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
|
72
|
+
when "basic"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
|
73
|
+
else '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
74
|
+
end
|
75
|
+
elsif html4?
|
76
|
+
case text
|
77
|
+
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
|
78
|
+
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
|
79
|
+
else '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
str << trailing_newlines
|
84
|
+
[:static, str]
|
85
|
+
end
|
86
|
+
|
87
|
+
def on_comment(content)
|
88
|
+
[:multi,
|
89
|
+
[:static, "<!--"],
|
90
|
+
compile(content),
|
91
|
+
[:static, "-->"]]
|
92
|
+
end
|
93
|
+
|
94
|
+
def on_tag(name, attrs, content)
|
95
|
+
ac = @options[:autoclose].include?(name)
|
96
|
+
result = [:multi]
|
97
|
+
result << [:static, "<#{name}"]
|
98
|
+
result << compile(attrs)
|
99
|
+
result << [:static, " /"] if ac && xhtml?
|
100
|
+
result << [:static, ">"]
|
101
|
+
result << compile(content)
|
102
|
+
result << [:static, "</#{name}>"] if !ac
|
103
|
+
result
|
104
|
+
end
|
105
|
+
|
106
|
+
def on_attrs(*exp)
|
107
|
+
if exp.all? { |e| attr_easily_compilable?(e) }
|
108
|
+
[:multi, *merge_basicattrs(exp).map { |e| compile(e) }]
|
109
|
+
else
|
110
|
+
raise "[:html, :attrs] currently only support basicattrs"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def attr_easily_compilable?(exp)
|
115
|
+
exp[1] == :basicattr and
|
116
|
+
exp[2][0] == :static
|
117
|
+
end
|
118
|
+
|
119
|
+
def merge_basicattrs(attrs)
|
120
|
+
result = []
|
121
|
+
position = {}
|
122
|
+
|
123
|
+
attrs.each do |(html, type, (name_type, name), value)|
|
124
|
+
if pos = position[name]
|
125
|
+
case name
|
126
|
+
when 'class', 'id'
|
127
|
+
value = [:multi,
|
128
|
+
result[pos].last, # previous value
|
129
|
+
[:static, (name == 'class' ? ' ' : '_')], # delimiter
|
130
|
+
value] # new value
|
131
|
+
end
|
132
|
+
|
133
|
+
result[pos] = [name, value]
|
134
|
+
else
|
135
|
+
position[name] = result.size
|
136
|
+
result << [name, value]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
final = []
|
141
|
+
result.each_with_index do |(name, value), index|
|
142
|
+
final << [:html, :basicattr, [:static, name], value]
|
143
|
+
end
|
144
|
+
final
|
145
|
+
end
|
146
|
+
|
147
|
+
def on_basicattr(name, value)
|
148
|
+
[:multi,
|
149
|
+
[:static, " "],
|
150
|
+
name,
|
151
|
+
[:static, "="],
|
152
|
+
[:static, @options[:attr_wrapper]],
|
153
|
+
value,
|
154
|
+
[:static, @options[:attr_wrapper]]]
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
data/lib/temple/parsers/erb.rb
CHANGED
@@ -25,7 +25,7 @@ module Temple
|
|
25
25
|
if scanner.stag.nil?
|
26
26
|
case token
|
27
27
|
when Compiler::PercentLine
|
28
|
-
result
|
28
|
+
append_static(result, content) if content.size > 0
|
29
29
|
content = ''
|
30
30
|
result << [:block, token.to_s.strip]
|
31
31
|
result << [:newline]
|
@@ -35,12 +35,12 @@ module Temple
|
|
35
35
|
scanner.stag = token
|
36
36
|
when "\n"
|
37
37
|
content << "\n"
|
38
|
-
result
|
38
|
+
append_static(result, content)
|
39
39
|
content = ''
|
40
40
|
when '<%%'
|
41
41
|
result << [:static, '<%']
|
42
42
|
else
|
43
|
-
result
|
43
|
+
append_static(result, token)
|
44
44
|
end
|
45
45
|
else
|
46
46
|
case token
|
@@ -71,6 +71,13 @@ module Temple
|
|
71
71
|
|
72
72
|
result
|
73
73
|
end
|
74
|
+
|
75
|
+
def append_static(result, content)
|
76
|
+
result << [:static, content]
|
77
|
+
content.count("\n").times do
|
78
|
+
result << [:newline]
|
79
|
+
end
|
80
|
+
end
|
74
81
|
end
|
75
82
|
end
|
76
|
-
end
|
83
|
+
end
|
data/lib/temple/utils.rb
CHANGED
data/temple.gemspec
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{temple}
|
5
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.2"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Magnus Holm"]
|
9
9
|
s.date = %q{2010-01-23}
|
10
10
|
s.email = %q{judofyr@gmail.com}
|
11
|
-
s.files = [".yardopts", "LICENSE", "README.md", "Rakefile", "lib/temple.rb", "lib/temple/core.rb", "lib/temple/engine.rb", "lib/temple/engines/erb.rb", "lib/temple/filters/dynamic_inliner.rb", "lib/temple/filters/
|
11
|
+
s.files = [".yardopts", "LICENSE", "README.md", "Rakefile", "lib/temple.rb", "lib/temple/core.rb", "lib/temple/engine.rb", "lib/temple/engines/erb.rb", "lib/temple/filters/dynamic_inliner.rb", "lib/temple/filters/multi_flattener.rb", "lib/temple/filters/static_merger.rb", "lib/temple/generator.rb", "lib/temple/html/fast.rb", "lib/temple/parsers/erb.rb", "lib/temple/utils.rb", "temple.gemspec", "test/engines/hello.erb", "test/engines/test_erb.rb", "test/engines/test_erb_m17n.rb", "test/filters/test_dynamic_inliner.rb", "test/filters/test_static_merger.rb", "test/helper.rb", "test/test_generator.rb", "test/test_temple.rb"]
|
12
12
|
s.homepage = %q{http://dojo.rubyforge.org/}
|
13
13
|
s.require_paths = ["lib"]
|
14
14
|
s.rubygems_version = %q{1.3.6}
|
@@ -9,7 +9,7 @@ class TestTempleFiltersDynamicInliner < TestFilter(:DynamicInliner)
|
|
9
9
|
])
|
10
10
|
|
11
11
|
assert_equal([:multi,
|
12
|
-
[:dynamic, "
|
12
|
+
[:dynamic, '"Hello World\n Have a nice day"']
|
13
13
|
], exp)
|
14
14
|
end
|
15
15
|
|
@@ -96,7 +96,7 @@ class TestTempleFiltersDynamicInliner < TestFilter(:DynamicInliner)
|
|
96
96
|
])
|
97
97
|
|
98
98
|
assert_equal([:multi,
|
99
|
-
[:dynamic, ["
|
99
|
+
[:dynamic, ['"Hello \n"', '"#{@world}"', '""'].join("\\\n")]
|
100
100
|
], exp)
|
101
101
|
end
|
102
102
|
|
@@ -113,4 +113,4 @@ class TestTempleFiltersDynamicInliner < TestFilter(:DynamicInliner)
|
|
113
113
|
[:block, "world"]
|
114
114
|
], exp)
|
115
115
|
end
|
116
|
-
end
|
116
|
+
end
|
data/test/test_generator.rb
CHANGED
@@ -93,30 +93,8 @@ class TestTempleGenerator < Test::Unit::TestCase
|
|
93
93
|
|
94
94
|
def test_to_ruby
|
95
95
|
simple = Simple.new
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
"Hello\r\nWorld" => 'Hello\nWorld',
|
100
|
-
"Hello\nWorld" => %w|Hello World|,
|
101
|
-
"Hello\n\r\n\nWorld" => %w|Hello \n World|,
|
102
|
-
"\r\n\nHelloWorld\n" => %w|\n HelloWorld .|,
|
103
|
-
"\nHelloWorld\r\n" => %w|. HelloWorld\n|,
|
104
|
-
}.
|
105
|
-
each do |actual, expected|
|
106
|
-
if expected.is_a?(Array)
|
107
|
-
expected = expected.map do |x|
|
108
|
-
if x == "."
|
109
|
-
# Use the dot so we can easily match a newline
|
110
|
-
# at the end or the beginning.
|
111
|
-
""
|
112
|
-
else
|
113
|
-
x
|
114
|
-
end
|
115
|
-
end.join("\n")
|
116
|
-
end
|
117
|
-
|
118
|
-
expected = '"' + expected + '"'
|
119
|
-
assert_equal(expected, simple.to_ruby(actual))
|
120
|
-
end
|
96
|
+
|
97
|
+
assert_equal('"Hello"', simple.to_ruby("Hello"))
|
98
|
+
assert_equal('"Hello\nWorld"', simple.to_ruby("Hello\nWorld"))
|
121
99
|
end
|
122
|
-
end
|
100
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 2
|
9
|
+
version: 0.1.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Magnus Holm
|
@@ -36,10 +36,10 @@ files:
|
|
36
36
|
- lib/temple/engine.rb
|
37
37
|
- lib/temple/engines/erb.rb
|
38
38
|
- lib/temple/filters/dynamic_inliner.rb
|
39
|
-
- lib/temple/filters/escapable.rb
|
40
39
|
- lib/temple/filters/multi_flattener.rb
|
41
40
|
- lib/temple/filters/static_merger.rb
|
42
41
|
- lib/temple/generator.rb
|
42
|
+
- lib/temple/html/fast.rb
|
43
43
|
- lib/temple/parsers/erb.rb
|
44
44
|
- lib/temple/utils.rb
|
45
45
|
- temple.gemspec
|
@@ -47,7 +47,6 @@ files:
|
|
47
47
|
- test/engines/test_erb.rb
|
48
48
|
- test/engines/test_erb_m17n.rb
|
49
49
|
- test/filters/test_dynamic_inliner.rb
|
50
|
-
- test/filters/test_escapable.rb
|
51
50
|
- test/filters/test_static_merger.rb
|
52
51
|
- test/helper.rb
|
53
52
|
- test/test_generator.rb
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'cgi'
|
2
|
-
|
3
|
-
module Temple
|
4
|
-
module Filters
|
5
|
-
class Escapable
|
6
|
-
def initialize(options = {})
|
7
|
-
@escaper = options[:escaper] || 'CGI.escapeHTML((%s).to_s)'
|
8
|
-
end
|
9
|
-
|
10
|
-
def compile(exp)
|
11
|
-
return exp if !exp.is_a?(Enumerable) || exp.is_a?(String)
|
12
|
-
|
13
|
-
if is_escape?(exp)
|
14
|
-
case exp[1][0]
|
15
|
-
when :static
|
16
|
-
[:static, eval(@escaper % exp[1][1].inspect)]
|
17
|
-
when :dynamic, :block
|
18
|
-
[exp[1][0], @escaper % exp[1][1]]
|
19
|
-
else
|
20
|
-
raise "Escapable can only handle :static, :dynamic and :block for the moment."
|
21
|
-
end
|
22
|
-
else
|
23
|
-
exp.map { |e| compile(e) }
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def is_escape?(exp)
|
28
|
-
exp.respond_to?(:[]) && exp[0] == :escape
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../helper'
|
2
|
-
|
3
|
-
class TestTempleFiltersEscapable < TestFilter(:Escapable)
|
4
|
-
def test_escape
|
5
|
-
exp = @filter.compile([:multi,
|
6
|
-
[:escape, [:dynamic, "@hello"]],
|
7
|
-
[:escape, [:block, "@world"]]
|
8
|
-
])
|
9
|
-
|
10
|
-
assert_equal([:multi,
|
11
|
-
[:dynamic, "CGI.escapeHTML((@hello).to_s)"],
|
12
|
-
[:block, "CGI.escapeHTML((@world).to_s)"]
|
13
|
-
], exp)
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_escape_static_content
|
17
|
-
exp = @filter.compile([:multi,
|
18
|
-
[:escape, [:static, "<hello>"]],
|
19
|
-
[:escape, [:block, "@world"]]
|
20
|
-
])
|
21
|
-
|
22
|
-
assert_equal([:multi,
|
23
|
-
[:static, "<hello>"],
|
24
|
-
[:block, "CGI.escapeHTML((@world).to_s)"]
|
25
|
-
], exp)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|