temple 0.4.0 → 0.4.1

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/CHANGES CHANGED
@@ -1,3 +1,10 @@
1
+ 0.4.1
2
+
3
+ * Generators: produce optimized code
4
+ * remove deprecated method EngineDSL#wildcard
5
+ * Set tilt template default_mime_type to text/html
6
+ * HTML: Support conditional comments [:html, :condcomment, ...]
7
+
1
8
  0.4.0
2
9
 
3
10
  * Split Temple::HTML::AttributeMerger in AttributeSorter,
@@ -210,6 +210,13 @@ Example:
210
210
  generates:
211
211
  <!--comment-->
212
212
 
213
+ ### [:html, :condcomment, condition, sexp]
214
+
215
+ Example:
216
+ [:html, :condcomment, 'IE', [:static, 'comment']]
217
+ generates:
218
+ <!--[if IE]>comment<![endif]-->
219
+
213
220
  ### [:html, :tag, identifier, attributes, optional-sexp]
214
221
 
215
222
  HTML tag abstraction. Identifier can be a String or a Symbol. If the optional content Sexp is omitted
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  Temple
2
2
  ======
3
3
 
4
+ [![Build Status](https://secure.travis-ci.org/judofyr/temple.png?branch=master)](http://travis-ci.org/judofyr/temple) [![Dependency Status](https://gemnasium.com/judofyr/temple.png?travis)](https://gemnasium.com/judofyr/temple) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/judofyr/temple)
5
+
4
6
  Temple is an abstraction and a framework for compiling templates to pure Ruby.
5
7
  It's all about making it easier to experiment, implement and optimize template
6
8
  languages. If you're interested in implementing your own template language, or
@@ -56,19 +56,7 @@ module Temple
56
56
  end
57
57
 
58
58
  def call_chain
59
- @call_chain ||= @chain.map do |e|
60
- name, filter, option_filter, local_options = e
61
- case filter
62
- when Class
63
- filtered_options = Hash[*option_filter.select {|k| options.include?(k) }.map {|k| [k, options[k]] }.flatten]
64
- filter.new(ImmutableHash.new(local_options, filtered_options))
65
- when UnboundMethod
66
- filter = filter.bind(self)
67
- filter.arity == 1 ? filter : filter.call
68
- else
69
- filter
70
- end
71
- end.compact
59
+ @call_chain ||= @chain.map {|name, constructor| constructor.call(self) }.compact
72
60
  end
73
61
  end
74
62
  end
@@ -64,7 +64,7 @@ module Temple
64
64
  result.concat(prev) if state == :single
65
65
  end
66
66
 
67
- result
67
+ result.size == 2 ? result[1] : result
68
68
  end
69
69
  end
70
70
  end
@@ -8,8 +8,7 @@ module Temple
8
8
  #
9
9
  # Compiles to:
10
10
  #
11
- # [:multi,
12
- # [:static, "Hello World!"]]
11
+ # [:static, "Hello World!"]
13
12
  #
14
13
  # @api public
15
14
  class StaticMerger < Filter
@@ -31,7 +30,7 @@ module Temple
31
30
  end
32
31
  end
33
32
 
34
- result
33
+ result.size == 2 ? result[1] : result
35
34
  end
36
35
  end
37
36
  end
@@ -65,7 +65,7 @@ module Temple
65
65
  # _buf = []
66
66
  # _buf << "static"
67
67
  # _buf << dynamic
68
- # _buf.join
68
+ # _buf
69
69
  #
70
70
  # @api public
71
71
  class Array < Generator
@@ -79,8 +79,25 @@ module Temple
79
79
  end
80
80
 
81
81
  # Just like Array, but calls #join on the array.
82
+ #
83
+ # _buf = []
84
+ # _buf << "static"
85
+ # _buf << dynamic
86
+ # _buf.join
87
+ #
82
88
  # @api public
83
89
  class ArrayBuffer < Array
90
+ def call(exp)
91
+ case exp.first
92
+ when :static
93
+ "#{buffer} = #{exp.last.inspect}"
94
+ when :dynamic
95
+ "#{buffer} = (#{exp.last}).to_s"
96
+ else
97
+ super
98
+ end
99
+ end
100
+
84
101
  def postamble
85
102
  "#{buffer} = #{buffer}.join"
86
103
  end
@@ -94,11 +111,15 @@ module Temple
94
111
  # _buf
95
112
  #
96
113
  # @api public
97
- class StringBuffer < Array
114
+ class StringBuffer < ArrayBuffer
98
115
  def preamble
99
116
  "#{buffer} = ''"
100
117
  end
101
118
 
119
+ def postamble
120
+ buffer
121
+ end
122
+
102
123
  def on_dynamic(code)
103
124
  concat("(#{code}).to_s")
104
125
  end
@@ -106,7 +127,7 @@ module Temple
106
127
 
107
128
  # Implements a rails output buffer.
108
129
  #
109
- # @output_buffer = ActionView::OutputBuffer
130
+ # @output_buffer = ActionView::SafeBuffer
110
131
  # @output_buffer.safe_concat "static"
111
132
  # @output_buffer.safe_concat dynamic.to_s
112
133
  # @output_buffer
@@ -118,6 +139,10 @@ module Temple
118
139
  # output_buffer is needed for Rails 3.1 Streaming support
119
140
  :capture_generator => RailsOutputBuffer
120
141
 
142
+ def call(exp)
143
+ [preamble, compile(exp), postamble].join('; ')
144
+ end
145
+
121
146
  def preamble
122
147
  if options[:streaming] && options[:buffer] == '@output_buffer'
123
148
  "#{buffer} = output_buffer || #{options[:buffer_class]}.new"
@@ -29,6 +29,7 @@ module Temple
29
29
  # HTML abstraction
30
30
  [:html, :doctype, String] |
31
31
  [:html, :comment, Expression] |
32
+ [:html, :condcomment, String, Expression]|
32
33
  [:html, :tag, HTMLIdentifier, Expression, 'Expression?'] |
33
34
  [:html, :attrs, 'HTMLAttr*'] |
34
35
  HTMLAttr
@@ -14,6 +14,10 @@ module Temple
14
14
  [:html, :comment, compile(content)]
15
15
  end
16
16
 
17
+ def on_html_condcomment(condition, content)
18
+ [:html, :condcomment, condition, compile(content)]
19
+ end
20
+
17
21
  def on_html_tag(name, attrs, content = nil)
18
22
  result = [:html, :tag, name, compile(attrs)]
19
23
  content ? (result << compile(content)) : result
@@ -65,6 +65,13 @@ module Temple
65
65
  [:static, '-->']]
66
66
  end
67
67
 
68
+ def on_html_condcomment(condition, content)
69
+ on_html_comment [:multi,
70
+ [:static, "[#{condition}]>"],
71
+ content,
72
+ [:static, '<![endif]']]
73
+ end
74
+
68
75
  def on_html_tag(name, attrs, content = nil)
69
76
  name = name.to_s
70
77
  closed = !content || (empty_exp?(content) && options[:autoclose].include?(name))
@@ -6,7 +6,7 @@ module Temple
6
6
  :pretty => true,
7
7
  :indent_tags => %w(article aside audio base body datalist dd div dl dt
8
8
  fieldset figure footer form head h1 h2 h3 h4 h5 h6
9
- header hgroup hr html input li link meta nav ol p
9
+ header hgroup hr html li link meta nav ol p
10
10
  rp rt ruby section script style table tbody td tfoot
11
11
  th thead title tr ul video).freeze,
12
12
  :pre_tags => %w(code pre textarea).freeze
@@ -60,15 +60,10 @@ module Temple
60
60
  dispatched_methods.each do |method|
61
61
  method.split('_')[1..-1].inject(tree) {|node, type| node[type.to_sym] }.method = method
62
62
  end
63
- self.class.class_eval %{
64
- def dispatcher(exp)
65
- if self.class == #{self.class}
66
- #{tree.compile}
67
- else
68
- replace_dispatcher(exp)
69
- end
70
- end
71
- }
63
+ self.class.class_eval %{def dispatcher(exp)
64
+ return replace_dispatcher(exp) if self.class != #{self.class}
65
+ #{tree.compile.gsub("\n", "\n ")}
66
+ end}
72
67
  dispatcher(exp)
73
68
  end
74
69
 
@@ -86,31 +81,19 @@ module Temple
86
81
  @method = nil
87
82
  end
88
83
 
89
- def compile(level = 0, parent = nil)
84
+ def compile(level = 0, call_parent = nil)
85
+ call_method = method ? (level == 0 ? "#{method}(*exp)" :
86
+ "#{method}(*exp[#{level}..-1])") : call_parent
90
87
  if empty?
91
- if method
92
- (' ' * level) + "#{method}(*exp[#{level}..-1])"
93
- elsif !parent
94
- 'exp'
95
- else
96
- raise 'Invalid dispatcher node'
97
- end
88
+ raise 'Invalid dispatcher node' unless method
89
+ call_method
98
90
  else
99
- code = [(' ' * level) + "case(exp[#{level}])"]
91
+ code = "case(exp[#{level}])\n"
100
92
  each do |key, child|
101
- code << (' ' * level) + "when #{key.inspect}"
102
- code << child.compile(level + 1, parent || method)
103
- end
104
- if method || !parent
105
- code << (' ' * level) + "else"
106
- if method
107
- code << (' ' * level) + " #{method}(*exp[#{level}..-1])"
108
- else
109
- code << (' ' * level) + " exp"
110
- end
93
+ code << "when #{key.inspect}\n " <<
94
+ child.compile(level + 1, call_method).gsub("\n", "\n ") << "\n"
111
95
  end
112
- code << (' ' * level) + "end"
113
- code.join("\n")
96
+ code << "else\n " << (call_method || 'exp') << "\nend"
114
97
  end
115
98
  end
116
99
  end
@@ -6,21 +6,24 @@ module Temple
6
6
  end
7
7
 
8
8
  def append(*args, &block)
9
- chain << element(args, block)
9
+ chain << chain_element(args, block)
10
10
  chain_modified!
11
11
  end
12
12
 
13
13
  def prepend(*args, &block)
14
- chain.unshift(element(args, block))
14
+ chain.unshift(chain_element(args, block))
15
15
  chain_modified!
16
16
  end
17
17
 
18
18
  def remove(name)
19
+ name = chain_name(name)
19
20
  found = false
20
21
  chain.reject! do |i|
21
- equal = i.first == name
22
- found = true if equal
23
- equal
22
+ if i.first == name
23
+ found = true
24
+ else
25
+ false
26
+ end
24
27
  end
25
28
  raise "#{name} not found" unless found
26
29
  chain_modified!
@@ -28,20 +31,9 @@ module Temple
28
31
 
29
32
  alias use append
30
33
 
31
- # DEPRECATED!
32
- #
33
- # wildcard(:FilterName) { FilterClass.new(options) }
34
- #
35
- # is replaced by
36
- #
37
- # use(:FilterName) { FilterClass.new(options) }
38
- #
39
- alias wildcard use
40
-
41
34
  def before(name, *args, &block)
42
- name = Class === name ? name.name.to_sym : name
43
- raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
44
- e = element(args, block)
35
+ name = chain_name(name)
36
+ e = chain_element(args, block)
45
37
  found, i = false, 0
46
38
  while i < chain.size
47
39
  if chain[i].first == name
@@ -57,9 +49,8 @@ module Temple
57
49
  end
58
50
 
59
51
  def after(name, *args, &block)
60
- name = Class === name ? name.name.to_sym : name
61
- raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
62
- e = element(args, block)
52
+ name = chain_name(name)
53
+ e = chain_element(args, block)
63
54
  found, i = false, 0
64
55
  while i < chain.size
65
56
  if chain[i].first == name
@@ -74,9 +65,8 @@ module Temple
74
65
  end
75
66
 
76
67
  def replace(name, *args, &block)
77
- name = Class === name ? name.name.to_sym : name
78
- raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
79
- e = element(args, block)
68
+ name = chain_name(name)
69
+ e = chain_element(args, block)
80
70
  found = false
81
71
  chain.each_with_index do |c, i|
82
72
  if c.first == name
@@ -99,23 +89,55 @@ module Temple
99
89
 
100
90
  private
101
91
 
102
- def define_chain_method(name, proc)
92
+ def chain_name(name)
93
+ name = Class === name ? name.name.to_sym : name
94
+ raise(ArgumentError, 'Name argument must be Class or Symbol') unless Symbol === name
95
+ name
96
+ end
97
+
98
+ def chain_class_constructor(filter, option_filter)
99
+ local_options = Hash === option_filter.last ? option_filter.pop : nil
100
+ raise(ArgumentError, 'Only symbols allowed in option filter') unless option_filter.all? {|o| Symbol === o }
101
+ proc do |engine|
102
+ filtered_options = Hash[*option_filter.select {|k| engine.options.include?(k) }.map {|k| [k, engine.options[k]] }.flatten]
103
+ filter.new(ImmutableHash.new(local_options, filtered_options))
104
+ end
105
+ end
106
+
107
+ def chain_proc_constructor(name, filter)
108
+ raise(ArgumentError, 'Proc or blocks must have arity 0 or 1') if filter.arity > 1
109
+ method_name = "FILTER #{name}"
103
110
  if Class === self
104
- define_method(name, &proc)
105
- instance_method(name)
111
+ define_method(method_name, &filter)
112
+ filter = instance_method(method_name)
113
+ if filter.arity == 1
114
+ proc {|engine| filter.bind(engine) }
115
+ else
116
+ proc do |engine|
117
+ f = filter.bind(engine).call
118
+ raise 'Constructor must return callable object' unless f.respond_to?(:call)
119
+ f
120
+ end
121
+ end
106
122
  else
107
- (class << self; self; end).class_eval { define_method(name, &proc) }
108
- method(name)
123
+ (class << self; self; end).class_eval { define_method(method_name, &filter) }
124
+ filter = method(method_name)
125
+ proc {|engine| filter }
109
126
  end
110
127
  end
111
128
 
112
- def element(args, block)
129
+ def chain_callable_constructor(filter)
130
+ raise(ArgumentError, 'Class or callable argument is required') unless filter.respond_to?(:call)
131
+ proc {|engine| filter }
132
+ end
133
+
134
+ def chain_element(args, block)
113
135
  name = args.shift
114
136
  if Class === name
115
137
  filter = name
116
138
  name = filter.name.to_sym
117
139
  else
118
- raise(ArgumentError, 'First argument must be Class or Symbol') unless Symbol === name
140
+ raise(ArgumentError, 'Name argument must be Class or Symbol') unless Symbol === name
119
141
  end
120
142
 
121
143
  if block
@@ -131,20 +153,16 @@ module Temple
131
153
  # The proc is converted to a method of the engine class.
132
154
  # The proc can then access the option hash of the engine.
133
155
  raise(ArgumentError, 'Too many arguments') unless args.empty?
134
- raise(ArgumentError, 'Proc or blocks must have arity 0 or 1') if filter.arity > 1
135
- [name, define_chain_method("FILTER #{name}", filter)]
156
+ [name, chain_proc_constructor(name, filter)]
136
157
  when Class
137
158
  # Class argument (e.g Filter class)
138
159
  # The options are passed to the classes constructor.
139
- local_options = Hash === args.last ? args.pop : nil
140
- raise(ArgumentError, 'Only symbols allowed in option filter') unless args.all? {|o| Symbol === o }
141
- [name, filter, args, local_options]
160
+ [name, chain_class_constructor(filter, args)]
142
161
  else
143
162
  # Other callable argument (e.g. Object of class which implements #call or Method)
144
163
  # The callable has no access to the option hash of the engine.
145
164
  raise(ArgumentError, 'Too many arguments') unless args.empty?
146
- raise(ArgumentError, 'Class or callable argument is required') unless filter.respond_to?(:call)
147
- [name, filter]
165
+ [name, chain_callable_constructor(filter)]
148
166
  end
149
167
  end
150
168
  end
@@ -33,7 +33,7 @@ module Temple
33
33
 
34
34
  def match(exp, unmatched)
35
35
  tmp = []
36
- @children.any? {|rule| rule.match(exp, tmp) } || (unmatched.push(*tmp) && false)
36
+ @children.any? {|rule| rule.match(exp, tmp) } || (unmatched.concat(tmp) && false)
37
37
  end
38
38
 
39
39
  def after_copy(source)
@@ -9,6 +9,23 @@ module Temple
9
9
  default_options[:engine]
10
10
  end
11
11
 
12
+ def init
13
+ # Overwrite this for class initialization
14
+ end
15
+
16
+ def register_as(name)
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def create(engine, options)
21
+ template = Class.new(self)
22
+ template.default_options[:engine] = engine
23
+ template.default_options.update(options)
24
+ template.init
25
+ template.register_as(options[:register_as]) if options[:register_as]
26
+ template
27
+ end
28
+
12
29
  def build_engine(*options)
13
30
  raise 'No engine configured' unless engine
14
31
  options << default_options
@@ -5,11 +5,7 @@ module Temple
5
5
  autoload :Rails, 'temple/templates/rails'
6
6
 
7
7
  def self.method_missing(name, engine, options = {})
8
- template = Class.new(const_get(name))
9
- template.default_options[:engine] = engine
10
- template.default_options.update(options)
11
- template.register_as(options[:register_as]) if options[:register_as]
12
- template
8
+ const_get(name).create(engine, options)
13
9
  end
14
10
  end
15
11
  end
@@ -23,6 +23,10 @@ module Temple
23
23
  @src
24
24
  end
25
25
 
26
+ def self.init
27
+ self.default_mime_type = default_options[:mime_type] || 'text/html'
28
+ end
29
+
26
30
  def self.register_as(name)
27
31
  ::Tilt.register name.to_s, self
28
32
  end
@@ -1,3 +1,3 @@
1
1
  module Temple
2
- VERSION = '0.4.0'
2
+ VERSION = '0.4.1'
3
3
  end
@@ -10,7 +10,7 @@ describe Temple::Filters::DynamicInliner do
10
10
  [:static, "Hello "],
11
11
  [:static, "World\n "],
12
12
  [:static, "Have a nice day"]
13
- ]).should.equal [:multi, [:dynamic, '"Hello World\n Have a nice day"']]
13
+ ]).should.equal [:dynamic, '"Hello World\n Have a nice day"']
14
14
  end
15
15
 
16
16
  it 'should compile several dynamics into dynamic' do
@@ -18,7 +18,7 @@ describe Temple::Filters::DynamicInliner do
18
18
  [:dynamic, "@hello"],
19
19
  [:dynamic, "@world"],
20
20
  [:dynamic, "@yeah"]
21
- ]).should.equal [:multi, [:dynamic, '"#{@hello}#{@world}#{@yeah}"']]
21
+ ]).should.equal [:dynamic, '"#{@hello}#{@world}#{@yeah}"']
22
22
  end
23
23
 
24
24
  it 'should compile static and dynamic into dynamic' do
@@ -27,7 +27,7 @@ describe Temple::Filters::DynamicInliner do
27
27
  [:dynamic, "@world"],
28
28
  [:dynamic, "@yeah"],
29
29
  [:static, "Nice"]
30
- ]).should.equal [:multi, [:dynamic, '"Hello#{@world}#{@yeah}Nice"']]
30
+ ]).should.equal [:dynamic, '"Hello#{@world}#{@yeah}Nice"']
31
31
  end
32
32
 
33
33
  it 'should merge statics and dynamics around a code' do
@@ -45,18 +45,15 @@ describe Temple::Filters::DynamicInliner do
45
45
  end
46
46
 
47
47
  it 'should keep codes intact' do
48
- exp = [:multi, [:code, 'foo']]
49
- @filter.call(exp).should.equal exp
48
+ @filter.call([:multi, [:code, 'foo']]).should.equal [:code, 'foo']
50
49
  end
51
50
 
52
51
  it 'should keep single statics intact' do
53
- exp = [:multi, [:static, 'foo']]
54
- @filter.call(exp).should.equal exp
52
+ @filter.call([:multi, [:static, 'foo']]).should.equal [:static, 'foo']
55
53
  end
56
54
 
57
55
  it 'should keep single dynamic intact' do
58
- exp = [:multi, [:dynamic, 'foo']]
59
- @filter.call(exp).should.equal exp
56
+ @filter.call([:multi, [:dynamic, 'foo']]).should.equal [:dynamic, 'foo']
60
57
  end
61
58
 
62
59
  it 'should inline inside multi' do
@@ -70,7 +67,7 @@ describe Temple::Filters::DynamicInliner do
70
67
  [:dynamic, "@world"]
71
68
  ]).should.equal [:multi,
72
69
  [:dynamic, '"Hello #{@world}"'],
73
- [:multi, [:dynamic, '"Hello #{@world}"']],
70
+ [:dynamic, '"Hello #{@world}"'],
74
71
  [:dynamic, '"Hello #{@world}"']
75
72
  ]
76
73
  end
@@ -81,9 +78,7 @@ describe Temple::Filters::DynamicInliner do
81
78
  [:newline],
82
79
  [:dynamic, "@world"],
83
80
  [:newline]
84
- ]).should.equal [:multi,
85
- [:dynamic, ['"Hello \n"', '"#{@world}"', '""'].join("\\\n")]
86
- ]
81
+ ]).should.equal [:dynamic, ['"Hello \n"', '"#{@world}"', '""'].join("\\\n")]
87
82
  end
88
83
 
89
84
  it 'should compile static followed by newline' do
@@ -10,9 +10,7 @@ describe Temple::Filters::StaticMerger do
10
10
  [:static, "Hello "],
11
11
  [:static, "World, "],
12
12
  [:static, "Good night"]
13
- ]).should.equal [:multi,
14
- [:static, "Hello World, Good night"]
15
- ]
13
+ ]).should.equal [:static, "Hello World, Good night"]
16
14
  end
17
15
 
18
16
  it 'should merge serveral statics around code' do
@@ -15,8 +15,16 @@ class FilterWithDispatcherMixin
15
15
  [:on_second_test, arg]
16
16
  end
17
17
 
18
- def on_seventh_level_level_level_level_level_test(arg)
19
- [:on_seventh_test, arg]
18
+ def on_a_b(*arg)
19
+ [:on_ab, *arg]
20
+ end
21
+
22
+ def on_a_b_test(arg)
23
+ [:on_ab_test, arg]
24
+ end
25
+
26
+ def on_a_b_c_d_test(arg)
27
+ [:on_abcd_test, arg]
20
28
  end
21
29
  end
22
30
 
@@ -47,8 +55,13 @@ describe Temple::Mixins::Dispatcher do
47
55
  @filter.call([:test, :check, 42]).should.equal [:on_check, 42]
48
56
  end
49
57
 
50
- it 'should dispatch seventh level' do
51
- @filter.call([:seventh, :level, :level, :level, :level, :level, :test, 42]).should == [:on_seventh_test, 42]
58
+ it 'should dispatch parent level' do
59
+ @filter.call([:a, 42]).should == [:a, 42]
60
+ @filter.call([:a, :b, 42]).should == [:on_ab, 42]
61
+ @filter.call([:a, :b, :test, 42]).should == [:on_ab_test, 42]
62
+ @filter.call([:a, :b, :c, 42]).should == [:on_ab, :c, 42]
63
+ @filter.call([:a, :b, :c, :d, 42]).should == [:on_ab, :c, :d, 42]
64
+ @filter.call([:a, :b, :c, :d, :test, 42]).should == [:on_abcd_test, 42]
52
65
  end
53
66
 
54
67
  it 'should dispatch zero level' do
@@ -32,32 +32,35 @@ describe Temple::Engine do
32
32
 
33
33
  TestEngine.chain[0].first.should.equal :Parser
34
34
  TestEngine.chain[0].size.should.equal 2
35
- TestEngine.chain[0].last.should.be.instance_of UnboundMethod
35
+ TestEngine.chain[0].last.should.be.instance_of Proc
36
36
 
37
37
  TestEngine.chain[1].first.should.equal :MyFilter1
38
38
  TestEngine.chain[1].size.should.equal 2
39
- TestEngine.chain[1].last.should.be.instance_of UnboundMethod
39
+ TestEngine.chain[1].last.should.be.instance_of Proc
40
40
 
41
41
  TestEngine.chain[2].first.should.equal :MyFilter2
42
42
  TestEngine.chain[2].size.should.equal 2
43
- TestEngine.chain[2].last.should.be.instance_of UnboundMethod
43
+ TestEngine.chain[2].last.should.be.instance_of Proc
44
44
 
45
- TestEngine.chain[3].size.should.equal 4
46
- TestEngine.chain[3].should.equal [:'Temple::HTML::Pretty', Temple::HTML::Pretty, [:format], {:pretty => true}]
45
+ TestEngine.chain[3].first.should.equal :'Temple::HTML::Pretty'
46
+ TestEngine.chain[3].size.should.equal 2
47
+ TestEngine.chain[3].last.should.be.instance_of Proc
47
48
 
48
- TestEngine.chain[4].size.should.equal 4
49
- TestEngine.chain[4].should.equal [:MultiFlattener, Temple::Filters::MultiFlattener, [], nil]
49
+ TestEngine.chain[4].first.should.equal :MultiFlattener
50
+ TestEngine.chain[4].size.should.equal 2
51
+ TestEngine.chain[4].last.should.be.instance_of Proc
50
52
 
51
- TestEngine.chain[5].size.should.equal 4
52
- TestEngine.chain[5].should.equal [:ArrayBuffer, Temple::Generators::ArrayBuffer, [], nil]
53
+ TestEngine.chain[5].first.should.equal :ArrayBuffer
54
+ TestEngine.chain[5].size.should.equal 2
55
+ TestEngine.chain[5].last.should.be.instance_of Proc
53
56
 
57
+ TestEngine.chain[6].first.should.equal :BeforeLast
54
58
  TestEngine.chain[6].size.should.equal 2
55
- TestEngine.chain[6][0].should.equal :BeforeLast
56
- TestEngine.chain[6][1].should.be.instance_of Callable1
59
+ TestEngine.chain[6].last.should.be.instance_of Proc
57
60
 
61
+ TestEngine.chain[7].first.should.equal :Last
58
62
  TestEngine.chain[7].size.should.equal 2
59
- TestEngine.chain[7][0].should.equal :Last
60
- TestEngine.chain[7][1].should.be.instance_of UnboundMethod
63
+ TestEngine.chain[7].last.should.be.instance_of Proc
61
64
  end
62
65
 
63
66
  it 'should instantiate chain' do
@@ -85,7 +88,7 @@ describe Temple::Engine do
85
88
  engine.chain.size.should.equal 9
86
89
  engine.chain[8].first.should.equal :MyFilter3
87
90
  engine.chain[8].size.should.equal 2
88
- engine.chain[8].last.should.be.instance_of Method
91
+ engine.chain[8].last.should.be.instance_of Proc
89
92
 
90
93
  call_chain = engine.send(:call_chain)
91
94
  call_chain.size.should.equal 9
@@ -105,7 +108,7 @@ describe Temple::Engine do
105
108
  engine.chain.size.should.equal 9
106
109
  engine.chain[0].first.should.equal :MyFilter0
107
110
  engine.chain[0].size.should.equal 2
108
- engine.chain[0].last.should.be.instance_of Method
111
+ engine.chain[0].last.should.be.instance_of Proc
109
112
  engine.chain[1].first.should.equal :Parser
110
113
 
111
114
  call_chain = engine.send(:call_chain)
@@ -81,24 +81,33 @@ describe Temple::Generators::Array do
81
81
  gen.call([:static, 'test']).should.equal '_buf = []; _buf << ("test"); _buf'
82
82
  gen.call([:dynamic, 'test']).should.equal '_buf = []; _buf << (test); _buf'
83
83
  gen.call([:code, 'test']).should.equal '_buf = []; test; _buf'
84
+
85
+ gen.call([:multi, [:static, 'a'], [:static, 'b']]).should.equal '_buf = []; _buf << ("a"); _buf << ("b"); _buf'
86
+ gen.call([:multi, [:static, 'a'], [:dynamic, 'b']]).should.equal '_buf = []; _buf << ("a"); _buf << (b); _buf'
84
87
  end
85
88
  end
86
89
 
87
90
  describe Temple::Generators::ArrayBuffer do
88
91
  it 'should compile simple expressions' do
89
92
  gen = Temple::Generators::ArrayBuffer.new
90
- gen.call([:static, 'test']).should.equal '_buf = []; _buf << ("test"); _buf = _buf.join'
91
- gen.call([:dynamic, 'test']).should.equal '_buf = []; _buf << (test); _buf = _buf.join'
93
+ gen.call([:static, 'test']).should.equal '_buf = "test"'
94
+ gen.call([:dynamic, 'test']).should.equal '_buf = (test).to_s'
92
95
  gen.call([:code, 'test']).should.equal '_buf = []; test; _buf = _buf.join'
96
+
97
+ gen.call([:multi, [:static, 'a'], [:static, 'b']]).should.equal '_buf = []; _buf << ("a"); _buf << ("b"); _buf = _buf.join'
98
+ gen.call([:multi, [:static, 'a'], [:dynamic, 'b']]).should.equal '_buf = []; _buf << ("a"); _buf << (b); _buf = _buf.join'
93
99
  end
94
100
  end
95
101
 
96
102
  describe Temple::Generators::StringBuffer do
97
103
  it 'should compile simple expressions' do
98
104
  gen = Temple::Generators::StringBuffer.new
99
- gen.call([:static, 'test']).should.equal '_buf = \'\'; _buf << ("test"); _buf'
100
- gen.call([:dynamic, 'test']).should.equal '_buf = \'\'; _buf << ((test).to_s); _buf'
105
+ gen.call([:static, 'test']).should.equal '_buf = "test"'
106
+ gen.call([:dynamic, 'test']).should.equal '_buf = (test).to_s'
101
107
  gen.call([:code, 'test']).should.equal '_buf = \'\'; test; _buf'
108
+
109
+ gen.call([:multi, [:static, 'a'], [:static, 'b']]).should.equal '_buf = \'\'; _buf << ("a"); _buf << ("b"); _buf'
110
+ gen.call([:multi, [:static, 'a'], [:dynamic, 'b']]).should.equal '_buf = \'\'; _buf << ("a"); _buf << ((b).to_s); _buf'
102
111
  end
103
112
  end
104
113
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: temple
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-02-26 00:00:00.000000000 Z
13
+ date: 2012-09-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: tilt
17
- requirement: &18003800 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,15 @@ dependencies:
22
22
  version: '0'
23
23
  type: :development
24
24
  prerelease: false
25
- version_requirements: *18003800
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
26
31
  - !ruby/object:Gem::Dependency
27
32
  name: bacon
28
- requirement: &18002180 !ruby/object:Gem::Requirement
33
+ requirement: !ruby/object:Gem::Requirement
29
34
  none: false
30
35
  requirements:
31
36
  - - ! '>='
@@ -33,10 +38,15 @@ dependencies:
33
38
  version: '0'
34
39
  type: :development
35
40
  prerelease: false
36
- version_requirements: *18002180
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
37
47
  - !ruby/object:Gem::Dependency
38
48
  name: rake
39
- requirement: &18000780 !ruby/object:Gem::Requirement
49
+ requirement: !ruby/object:Gem::Requirement
40
50
  none: false
41
51
  requirements:
42
52
  - - ! '>='
@@ -44,7 +54,12 @@ dependencies:
44
54
  version: '0'
45
55
  type: :development
46
56
  prerelease: false
47
- version_requirements: *18000780
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
48
63
  description:
49
64
  email:
50
65
  - judofyr@gmail.com
@@ -138,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
153
  version: '0'
139
154
  requirements: []
140
155
  rubyforge_project:
141
- rubygems_version: 1.8.15
156
+ rubygems_version: 1.8.24
142
157
  signing_key:
143
158
  specification_version: 3
144
159
  summary: Template compilation framework in Ruby
@@ -164,3 +179,4 @@ test_files:
164
179
  - test/test_grammar.rb
165
180
  - test/test_hash.rb
166
181
  - test/test_utils.rb
182
+ has_rdoc: