temple 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,75 @@
1
+ module Temple
2
+ module HTML
3
+ class Pretty < Fast
4
+ set_default_options :indent => ' ',
5
+ :pretty => true
6
+
7
+ INDENT_TAGS = %w(base div doctype form head html img input li link meta ol
8
+ script style table tbody td th thead title tr ul).freeze
9
+
10
+ def initialize(opts = {})
11
+ super
12
+ @last = nil
13
+ @stack = []
14
+ end
15
+
16
+ def on_static(content)
17
+ if options[:pretty]
18
+ @last = nil
19
+ [:static, content.gsub("\n", indent)]
20
+ else
21
+ [:static, content]
22
+ end
23
+ end
24
+
25
+ def on_dynamic(content)
26
+ if options[:pretty]
27
+ @last = nil
28
+ [:dynamic, %{(#{content}).to_s.gsub("\n", #{indent.inspect})}]
29
+ else
30
+ [:dynamic, content]
31
+ end
32
+ end
33
+
34
+ def on_html_doctype(type)
35
+ @last = 'doctype'
36
+ super
37
+ end
38
+
39
+ def on_html_comment(content)
40
+ return super if !options[:pretty]
41
+ [:multi, [:static, indent], super]
42
+ end
43
+
44
+ def on_html_tag(name, attrs, closed, content)
45
+ return super if !options[:pretty]
46
+
47
+ closed ||= options[:autoclose].include?(name)
48
+ raise "Closed tag #{name} has content" if closed && !empty_exp?(content)
49
+
50
+ result = [:multi, [:static, "#{tag_indent(name)}<#{name}"], compile!(attrs)]
51
+ result << [:static, ' /'] if closed && xhtml?
52
+ result << [:static, '>']
53
+
54
+ @stack << name
55
+ @last = name
56
+ result << compile!(content)
57
+ @stack.pop
58
+
59
+ result << [:static, "#{tag_indent(name)}</#{name}>"] if !closed
60
+ @last = name
61
+ result
62
+ end
63
+
64
+ # Return indentation if not in pre tag
65
+ def indent
66
+ @stack.include?('pre') ? '' : ("\n" + ((options[:indent] || '') * @stack.size))
67
+ end
68
+
69
+ # Return indentation before tag
70
+ def tag_indent(name)
71
+ @last && (INDENT_TAGS.include?(@last) || INDENT_TAGS.include?(name)) ? indent : ''
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,66 @@
1
+ module Temple
2
+ module Mixins
3
+ module Dispatcher
4
+ def self.included(base)
5
+ base.class_eval { extend ClassMethods }
6
+ end
7
+
8
+ def compile(exp)
9
+ compile!(exp)
10
+ end
11
+
12
+ def compile!(exp)
13
+ type, *args = exp
14
+ if respond_to?("on_#{type}")
15
+ send("on_#{type}", *args)
16
+ else
17
+ exp
18
+ end
19
+ end
20
+
21
+ def on_multi(*exps)
22
+ [:multi, *exps.map {|exp| compile!(exp) }]
23
+ end
24
+
25
+ def on_capture(name, exp)
26
+ [:capture, name, compile!(exp)]
27
+ end
28
+
29
+ module ClassMethods
30
+ def temple_dispatch(*bases)
31
+ bases.each do |base|
32
+ class_eval %{def on_#{base}(type, *args)
33
+ if respond_to?("on_" #{base.to_s.inspect} "_\#{type}")
34
+ send("on_" #{base.to_s.inspect} "_\#{type}", *args)
35
+ else
36
+ [:#{base}, type, *args]
37
+ end
38
+ end}
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ module Options
45
+ def self.included(base)
46
+ base.class_eval { extend ClassMethods }
47
+ end
48
+
49
+ attr_reader :options
50
+
51
+ def initialize(options = {})
52
+ @options = self.class.default_options.merge(options)
53
+ end
54
+
55
+ module ClassMethods
56
+ def set_default_options(opts)
57
+ default_options.merge!(opts)
58
+ end
59
+
60
+ def default_options(opts = nil)
61
+ @default_options ||= superclass.respond_to?(:default_options) ? superclass.default_options.dup : {}
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,35 @@
1
+ require 'tilt'
2
+
3
+ module Temple
4
+ # Tilt template implementation for Temple
5
+ class Template < Tilt::Template
6
+ class << self
7
+ def engine(engine = nil)
8
+ if engine
9
+ @engine = engine
10
+ elsif @engine
11
+ @engine
12
+ else
13
+ raise 'No engine configured'
14
+ end
15
+ end
16
+ end
17
+
18
+ # Prepare Temple template
19
+ #
20
+ # Called immediately after template data is loaded.
21
+ #
22
+ # @return [void]
23
+ def prepare
24
+ @src = self.class.engine.new(options.merge(:file => eval_file)).compile(data)
25
+ end
26
+
27
+ # A string containing the (Ruby) source code for the template.
28
+ #
29
+ # @param [Hash] locals Local variables
30
+ # @return [String] Compiled template ruby code
31
+ def precompiled_template(locals = {})
32
+ @src
33
+ end
34
+ end
35
+ end
data/lib/temple/utils.rb CHANGED
@@ -1,26 +1,62 @@
1
- require 'irb/ruby-lex'
2
- require 'stringio'
3
-
4
1
  module Temple
5
2
  module Utils
6
3
  extend self
7
-
8
- LITERAL_TOKENS = [RubyToken::TkSTRING, RubyToken::TkDSTRING]
9
-
10
- def literal_string?(str)
11
- lexer = RubyLex.new
12
- lexer.set_input(StringIO.new(str.strip))
13
-
14
- # The first token has to be a string.
15
- LITERAL_TOKENS.include?(lexer.token.class) and
16
- # That has to be the only token.
17
- lexer.token.nil?
4
+
5
+ # Returns an escaped copy of `html`.
6
+ # Strings which are declared as html_safe are not escaped.
7
+ #
8
+ # @param html [String] The string to escape
9
+ # @return [String] The escaped string
10
+ # @api public
11
+ def escape_html_safe(html)
12
+ html.html_safe? ? html : escape_html(html)
13
+ end
14
+
15
+ if defined?(EscapeUtils)
16
+ # Returns an escaped copy of `html`.
17
+ #
18
+ # @param html [String] The string to escape
19
+ # @return [String] The escaped string
20
+ # @api public
21
+ def escape_html(html)
22
+ EscapeUtils.escape_html(html.to_s)
23
+ end
24
+ elsif RUBY_VERSION > '1.9'
25
+ # Used by escape_html
26
+ # @api private
27
+ ESCAPE_HTML = {
28
+ '&' => '&amp;',
29
+ '"' => '&quot;',
30
+ '<' => '&lt;',
31
+ '>' => '&gt;',
32
+ '/' => '&#47;',
33
+ }.freeze
34
+
35
+ # Returns an escaped copy of `html`.
36
+ #
37
+ # @param html [String] The string to escape
38
+ # @return [String] The escaped string
39
+ # @api public
40
+ def escape_html(html)
41
+ html.to_s.gsub(/[&\"<>\/]/, ESCAPE_HTML)
42
+ end
43
+ else
44
+ # Returns an escaped copy of `html`.
45
+ #
46
+ # @param html [String] The string to escape
47
+ # @return [String] The escaped string
48
+ # @api public
49
+ def escape_html(html)
50
+ html.to_s.gsub(/&/n, '&amp;').gsub(/\"/n, '&quot;').gsub(/>/n, '&gt;').gsub(/</n, '&lt;').gsub(/\//, '&#47;')
51
+ end
18
52
  end
19
53
 
20
54
  def empty_exp?(exp)
21
55
  case exp[0]
22
56
  when :multi
23
- exp[1..-1].all? { |e| e[0] == :newline }
57
+ exp[1..-1].all? {|e| empty_exp?(e) }
58
+ when :newline
59
+ true
24
60
  else
25
61
  false
26
62
  end
@@ -0,0 +1,3 @@
1
+ module Temple
2
+ VERSION = '0.1.4'
3
+ end
data/temple.gemspec CHANGED
@@ -1,26 +1,21 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ require File.dirname(__FILE__) + "/lib/temple/version"
2
3
 
3
4
  Gem::Specification.new do |s|
4
5
  s.name = %q{temple}
5
- s.version = "0.1.3"
6
+ s.version = Temple::VERSION
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
- s.date = %q{2010-01-23}
9
+ s.date = %q{2010-11-03}
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/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
11
  s.homepage = %q{http://dojo.rubyforge.org/}
13
12
  s.require_paths = ["lib"]
14
13
  s.rubygems_version = %q{1.3.6}
15
- s.summary = %q{Template compilation framework in RUby}
14
+ s.summary = %q{Template compilation framework in Ruby}
16
15
 
17
- if s.respond_to? :specification_version then
18
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
19
- s.specification_version = 3
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
19
 
21
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
22
- else
23
- end
24
- else
25
- end
20
+ s.add_development_dependency('bacon')
26
21
  end
@@ -1,76 +1,66 @@
1
- require File.dirname(__FILE__) + '/../helper'
1
+ require 'helper'
2
2
 
3
- class TestTempleFiltersDynamicInliner < TestFilter(:DynamicInliner)
4
- def test_several_statics_into_dynamic
5
- exp = @filter.compile([:multi,
3
+ describe Temple::Filters::DynamicInliner do
4
+ before do
5
+ @filter = Temple::Filters::DynamicInliner.new
6
+ end
7
+
8
+ it 'should compile several statics into dynamic' do
9
+ @filter.compile([:multi,
6
10
  [:static, "Hello "],
7
11
  [:static, "World\n "],
8
12
  [:static, "Have a nice day"]
9
- ])
10
-
11
- assert_equal([:multi,
12
- [:dynamic, '"Hello World\n Have a nice day"']
13
- ], exp)
13
+ ]).should.equal [:multi, [:dynamic, '"Hello World\n Have a nice day"']]
14
14
  end
15
15
 
16
- def test_several_dynamics_into_dynamic
17
- exp = @filter.compile([:multi,
16
+ it 'should compile several dynamics into dynamic' do
17
+ @filter.compile([:multi,
18
18
  [:dynamic, "@hello"],
19
19
  [:dynamic, "@world"],
20
20
  [:dynamic, "@yeah"]
21
- ])
22
-
23
- assert_equal([:multi,
24
- [:dynamic, '"#{@hello}#{@world}#{@yeah}"']
25
- ], exp)
21
+ ]).should.equal [:multi, [:dynamic, '"#{@hello}#{@world}#{@yeah}"']]
26
22
  end
27
-
28
- def test_static_and_dynamic_into_dynamic
29
- exp = @filter.compile([:multi,
23
+
24
+ it 'should compile static and dynamic into dynamic' do
25
+ @filter.compile([:multi,
30
26
  [:static, "Hello"],
31
27
  [:dynamic, "@world"],
32
28
  [:dynamic, "@yeah"],
33
29
  [:static, "Nice"]
34
- ])
35
-
36
- assert_equal([:multi,
37
- [:dynamic, '"Hello#{@world}#{@yeah}Nice"']
38
- ], exp)
30
+ ]).should.equal [:multi, [:dynamic, '"Hello#{@world}#{@yeah}Nice"']]
39
31
  end
40
-
41
- def test_static_and_dynamic_around_blocks
32
+
33
+ it 'should merge statics and dynamics around a block' do
42
34
  exp = @filter.compile([:multi,
43
35
  [:static, "Hello "],
44
36
  [:dynamic, "@world"],
45
37
  [:block, "Oh yeah"],
46
38
  [:dynamic, "@yeah"],
47
39
  [:static, "Once more"]
48
- ])
49
-
50
- assert_equal([:multi,
40
+ ]).should.equal [:multi,
51
41
  [:dynamic, '"Hello #{@world}"'],
52
42
  [:block, "Oh yeah"],
53
43
  [:dynamic, '"#{@yeah}Once more"']
54
- ], exp)
44
+ ]
55
45
  end
56
-
57
- def test_keep_blocks_intact
46
+
47
+ it 'should keep blocks intact' do
58
48
  exp = [:multi, [:block, 'foo']]
59
- assert_equal(exp, @filter.compile(exp))
49
+ @filter.compile(exp).should.equal exp
60
50
  end
61
-
62
- def test_keep_single_static_intact
51
+
52
+ it 'should keep single statics intact' do
63
53
  exp = [:multi, [:static, 'foo']]
64
- assert_equal(exp, @filter.compile(exp))
54
+ @filter.compile(exp).should.equal exp
65
55
  end
66
56
 
67
- def test_keep_single_dynamic_intact
57
+ it 'should keep single dynamic intact' do
68
58
  exp = [:multi, [:dynamic, 'foo']]
69
- assert_equal(exp, @filter.compile(exp))
59
+ @filter.compile(exp).should.equal exp
70
60
  end
71
-
72
- def test_inline_inside_multi
73
- exp = @filter.compile([:multi,
61
+
62
+ it 'should inline inside multi' do
63
+ @filter.compile([:multi,
74
64
  [:static, "Hello "],
75
65
  [:dynamic, "@world"],
76
66
  [:multi,
@@ -78,39 +68,33 @@ class TestTempleFiltersDynamicInliner < TestFilter(:DynamicInliner)
78
68
  [:dynamic, "@world"]],
79
69
  [:static, "Hello "],
80
70
  [:dynamic, "@world"]
81
- ])
82
-
83
- assert_equal([:multi,
71
+ ]).should.equal [:multi,
84
72
  [:dynamic, '"Hello #{@world}"'],
85
73
  [:multi, [:dynamic, '"Hello #{@world}"']],
86
74
  [:dynamic, '"Hello #{@world}"']
87
- ], exp)
75
+ ]
88
76
  end
89
-
90
- def test_merge_across_newlines
77
+
78
+ it 'should merge across newlines' do
91
79
  exp = @filter.compile([:multi,
92
80
  [:static, "Hello \n"],
93
81
  [:newline],
94
82
  [:dynamic, "@world"],
95
83
  [:newline]
96
- ])
97
-
98
- assert_equal([:multi,
84
+ ]).should.equal [:multi,
99
85
  [:dynamic, ['"Hello \n"', '"#{@world}"', '""'].join("\\\n")]
100
- ], exp)
86
+ ]
101
87
  end
102
-
103
- def test_static_followed_by_newline
104
- exp = @filter.compile([:multi,
88
+
89
+ it 'should compile static followed by newline' do
90
+ @filter.compile([:multi,
105
91
  [:static, "Hello \n"],
106
92
  [:newline],
107
93
  [:block, "world"]
108
- ])
109
-
110
- assert_equal([:multi,
94
+ ]).should.equal [:multi,
111
95
  [:static, "Hello \n"],
112
96
  [:newline],
113
97
  [:block, "world"]
114
- ], exp)
98
+ ]
115
99
  end
116
100
  end