temple 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  module Temple
2
- VERSION = "0.1.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
- autoload :Escapable, 'temple/filters/escapable'
21
+ end
22
+
23
+ module HTML
24
+ autoload :Fast, 'temple/html/fast'
22
25
  end
23
26
  end
@@ -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. Any \n causes a newline in the generated code.
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
@@ -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.pop : {}
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
- return exp unless exp.first == :multi
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(exp[1]) if exp.length == 2
14
+ return compile(exps.first) if exps.length == 1
12
15
  result = [:multi]
13
16
 
14
- exp[1..-1].each do |e|
15
- e = compile(e)
16
- if e.first == :multi
17
- result.concat(e[1..-1])
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 << e
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
@@ -26,15 +26,7 @@ module Temple
26
26
  end
27
27
 
28
28
  def self.to_ruby(str)
29
- str.inspect.gsub(/(\\r)?\\n/m) do |str|
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
+
@@ -25,7 +25,7 @@ module Temple
25
25
  if scanner.stag.nil?
26
26
  case token
27
27
  when Compiler::PercentLine
28
- result << [:static, content] if content.size > 0
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 << [:static, content]
38
+ append_static(result, content)
39
39
  content = ''
40
40
  when '<%%'
41
41
  result << [:static, '<%']
42
42
  else
43
- result << [:static, token]
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
@@ -16,5 +16,14 @@ module Temple
16
16
  # That has to be the only token.
17
17
  lexer.token.nil?
18
18
  end
19
+
20
+ def empty_exp?(exp)
21
+ case exp[0]
22
+ when :multi
23
+ exp[1..-1].all? { |e| e[0] == :newline }
24
+ else
25
+ false
26
+ end
27
+ end
19
28
  end
20
- end
29
+ end
@@ -2,13 +2,13 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{temple}
5
- s.version = "0.1.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/escapable.rb", "lib/temple/filters/multi_flattener.rb", "lib/temple/filters/static_merger.rb", "lib/temple/generator.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_escapable.rb", "test/filters/test_static_merger.rb", "test/helper.rb", "test/test_generator.rb", "test/test_temple.rb"]
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, "\"Hello World\n Have a nice day\""]
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, ["\"Hello \n\"", '"#{@world}"', '""'].join("\\\n")],
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
@@ -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
- "Hello" => 'Hello',
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
- - 1
9
- version: 0.1.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, "&lt;hello&gt;"],
24
- [:block, "CGI.escapeHTML((@world).to_s)"]
25
- ], exp)
26
- end
27
- end
28
-