temple 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +2 -1
- data/CHANGES +63 -0
- data/EXPRESSIONS.md +250 -0
- data/README.md +24 -12
- data/lib/temple.rb +34 -18
- data/lib/temple/engine.rb +11 -7
- data/lib/temple/erb/engine.rb +5 -3
- data/lib/temple/erb/parser.rb +5 -2
- data/lib/temple/erb/template.rb +11 -0
- data/lib/temple/erb/trimming.rb +9 -1
- data/lib/temple/filter.rb +2 -0
- data/lib/temple/filters/control_flow.rb +43 -0
- data/lib/temple/filters/dynamic_inliner.rb +29 -32
- data/lib/temple/filters/eraser.rb +22 -0
- data/lib/temple/filters/escapable.rb +39 -0
- data/lib/temple/filters/multi_flattener.rb +4 -1
- data/lib/temple/filters/static_merger.rb +11 -10
- data/lib/temple/filters/validator.rb +15 -0
- data/lib/temple/generators.rb +41 -100
- data/lib/temple/grammar.rb +56 -0
- data/lib/temple/hash.rb +48 -0
- data/lib/temple/html/dispatcher.rb +10 -4
- data/lib/temple/html/fast.rb +50 -38
- data/lib/temple/html/filter.rb +8 -0
- data/lib/temple/html/pretty.rb +25 -14
- data/lib/temple/mixins/dispatcher.rb +103 -0
- data/lib/temple/{mixins.rb → mixins/engine_dsl.rb} +10 -95
- data/lib/temple/mixins/grammar_dsl.rb +166 -0
- data/lib/temple/mixins/options.rb +28 -0
- data/lib/temple/mixins/template.rb +25 -0
- data/lib/temple/templates.rb +2 -0
- data/lib/temple/utils.rb +11 -57
- data/lib/temple/version.rb +1 -1
- data/test/filters/test_control_flow.rb +92 -0
- data/test/filters/test_dynamic_inliner.rb +7 -7
- data/test/filters/test_eraser.rb +55 -0
- data/test/filters/{test_escape_html.rb → test_escapable.rb} +13 -6
- data/test/filters/test_multi_flattener.rb +1 -1
- data/test/filters/test_static_merger.rb +3 -3
- data/test/helper.rb +8 -0
- data/test/html/test_fast.rb +42 -57
- data/test/html/test_pretty.rb +10 -7
- data/test/mixins/test_dispatcher.rb +31 -0
- data/test/mixins/test_grammar_dsl.rb +86 -0
- data/test/test_engine.rb +73 -57
- data/test/test_erb.rb +0 -7
- data/test/test_filter.rb +26 -0
- data/test/test_generator.rb +57 -36
- data/test/test_grammar.rb +52 -0
- data/test/test_hash.rb +39 -0
- data/test/test_utils.rb +11 -38
- metadata +34 -10
- data/lib/temple/filters/debugger.rb +0 -26
- data/lib/temple/filters/escape_html.rb +0 -33
data/lib/temple/engine.rb
CHANGED
@@ -20,12 +20,14 @@ module Temple
|
|
20
20
|
#
|
21
21
|
# class SpecialEngine < MyEngine
|
22
22
|
# append MyCodeOptimizer
|
23
|
-
#
|
23
|
+
# before :ArrayBuffer, Temple::Filters::Validator
|
24
|
+
# replace :ArrayBuffer, Temple::Generators::RailsOutputBuffer
|
24
25
|
# end
|
25
26
|
#
|
26
27
|
# engine = MyEngine.new(:strict => "For MyParser")
|
27
28
|
# engine.call(something)
|
28
29
|
#
|
30
|
+
# @api public
|
29
31
|
class Engine
|
30
32
|
include Mixins::Options
|
31
33
|
include Mixins::EngineDSL
|
@@ -40,24 +42,26 @@ module Temple
|
|
40
42
|
def initialize(o = {})
|
41
43
|
super
|
42
44
|
@chain = self.class.chain.dup
|
43
|
-
yield(self) if block_given?
|
44
45
|
[*options[:chain]].compact.each {|block| block.call(self) }
|
45
|
-
@chain = build_chain
|
46
46
|
end
|
47
47
|
|
48
48
|
def call(input)
|
49
|
-
|
49
|
+
call_chain.inject(input) {|m, e| e.call(m) }
|
50
50
|
end
|
51
51
|
|
52
52
|
protected
|
53
53
|
|
54
|
-
def
|
55
|
-
|
54
|
+
def chain_modified!
|
55
|
+
@call_chain = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def call_chain
|
59
|
+
@call_chain ||= @chain.map do |e|
|
56
60
|
name, filter, option_filter, local_options = e
|
57
61
|
case filter
|
58
62
|
when Class
|
59
63
|
filtered_options = Hash[*option_filter.select {|k| options.include?(k) }.map {|k| [k, options[k]] }.flatten]
|
60
|
-
filter.new(
|
64
|
+
filter.new(ImmutableHash.new(local_options, filtered_options))
|
61
65
|
when UnboundMethod
|
62
66
|
filter.bind(self)
|
63
67
|
else
|
data/lib/temple/erb/engine.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
module Temple
|
2
2
|
module ERB
|
3
|
+
# Example ERB engine implementation
|
4
|
+
#
|
5
|
+
# @api public
|
3
6
|
class Engine < Temple::Engine
|
4
|
-
use Temple::ERB::Parser
|
5
|
-
filter :EscapeHTML, :use_html_safe
|
7
|
+
use Temple::ERB::Parser
|
6
8
|
use Temple::ERB::Trimming, :trim_mode
|
9
|
+
filter :Escapable, :use_html_safe, :disable_escape
|
7
10
|
filter :MultiFlattener
|
8
|
-
filter :StaticMerger
|
9
11
|
filter :DynamicInliner
|
10
12
|
generator :ArrayBuffer
|
11
13
|
end
|
data/lib/temple/erb/parser.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Temple
|
2
2
|
module ERB
|
3
|
+
# Example ERB parser
|
4
|
+
#
|
5
|
+
# @api public
|
3
6
|
class Parser
|
4
7
|
include Mixins::Options
|
5
8
|
|
@@ -25,9 +28,9 @@ module Temple
|
|
25
28
|
when '#'
|
26
29
|
code.count("\n").times { result << [:newline] }
|
27
30
|
when /=/
|
28
|
-
result << [:escape, indicator.
|
31
|
+
result << [:escape, indicator.size <= 1, [:dynamic, code]]
|
29
32
|
else
|
30
|
-
result << [:
|
33
|
+
result << [:code, code]
|
31
34
|
end
|
32
35
|
end
|
33
36
|
end
|
data/lib/temple/erb/trimming.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
module Temple
|
2
2
|
module ERB
|
3
|
+
# ERB trimming
|
4
|
+
# Set option :trim_mode to
|
5
|
+
# <> - omit newline for lines starting with <% and ending in %>
|
6
|
+
# > - omit newline for lines ending in %>
|
7
|
+
#
|
8
|
+
# @api public
|
3
9
|
class Trimming < Filter
|
4
10
|
def on_multi(*exps)
|
5
11
|
case options[:trim_mode]
|
@@ -21,8 +27,10 @@ module Temple
|
|
21
27
|
[:multi, *exps]
|
22
28
|
end
|
23
29
|
|
30
|
+
protected
|
31
|
+
|
24
32
|
def code?(exp)
|
25
|
-
exp[0] == :
|
33
|
+
exp[0] == :escape || exp[0] == :code
|
26
34
|
end
|
27
35
|
|
28
36
|
def static?(exp)
|
data/lib/temple/filter.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Temple
|
2
|
+
module Filters
|
3
|
+
# Control flow filter which processes [:if, condition, yes-exp, no-exp]
|
4
|
+
# and [:block, code, content] expressions.
|
5
|
+
# This is useful for ruby code generation with lots of conditionals.
|
6
|
+
#
|
7
|
+
# @api public
|
8
|
+
class ControlFlow < Filter
|
9
|
+
def on_if(condition, yes, no = nil)
|
10
|
+
result = [:multi, [:code, "if #{condition}"], compile(yes)]
|
11
|
+
while no && no.first == :if
|
12
|
+
result << [:code, "elsif #{no[1]}"] << compile(no[2])
|
13
|
+
no = no[3]
|
14
|
+
end
|
15
|
+
result << [:code, 'else'] << compile(no) if no
|
16
|
+
result << [:code, 'end']
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_case(arg, *cases)
|
21
|
+
result = [:multi, [:code, arg ? "case (#{arg})" : 'case']]
|
22
|
+
cases.map do |c|
|
23
|
+
condition, *exps = c
|
24
|
+
result << [:code, condition == :else ? 'else' : "when #{condition}"]
|
25
|
+
exps.each {|e| result << compile(e) }
|
26
|
+
end
|
27
|
+
result << [:code, 'end']
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_cond(*cases)
|
32
|
+
on_case(nil, *cases)
|
33
|
+
end
|
34
|
+
|
35
|
+
def on_block(code, exp)
|
36
|
+
[:multi,
|
37
|
+
[:code, code],
|
38
|
+
compile(exp),
|
39
|
+
[:code, 'end']]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,24 +1,24 @@
|
|
1
1
|
module Temple
|
2
2
|
module Filters
|
3
3
|
# Inlines several static/dynamic into a single dynamic.
|
4
|
+
#
|
5
|
+
# @api public
|
4
6
|
class DynamicInliner < Filter
|
5
7
|
def on_multi(*exps)
|
6
|
-
|
8
|
+
result = [:multi]
|
7
9
|
curr = nil
|
8
10
|
prev = []
|
9
11
|
state = :looking
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
head, arg = exp
|
13
|
+
exps.each do |exp|
|
14
|
+
type, arg = exp
|
14
15
|
|
15
|
-
case
|
16
|
+
case type
|
16
17
|
when :newline
|
17
|
-
|
18
|
-
when :looking
|
18
|
+
if state == :looking
|
19
19
|
# We haven't found any static/dynamic, so let's just add it
|
20
|
-
|
21
|
-
|
20
|
+
result << exp
|
21
|
+
else
|
22
22
|
# We've found something, so let's make sure the generated
|
23
23
|
# dynamic contains a newline by escaping a newline and
|
24
24
|
# starting a new string:
|
@@ -31,43 +31,40 @@ module Temple
|
|
31
31
|
when :dynamic, :static
|
32
32
|
case state
|
33
33
|
when :looking
|
34
|
-
# Found a single static/dynamic.
|
34
|
+
# Found a single static/dynamic. We don't want to turn this
|
35
35
|
# into a dynamic yet. Instead we store it, and if we find
|
36
36
|
# another one, we add both then.
|
37
37
|
state = :single
|
38
38
|
prev = [exp]
|
39
|
-
curr = [:dynamic, '"'
|
39
|
+
curr = [:dynamic, '"']
|
40
40
|
when :single
|
41
|
-
# Yes! We found another one.
|
42
|
-
# dynamic and add it to the result.
|
43
|
-
curr[1] << send(head, arg)
|
44
|
-
res << curr
|
41
|
+
# Yes! We found another one. Add the current dynamic to the result.
|
45
42
|
state = :several
|
46
|
-
|
47
|
-
# Yet another dynamic/single. Just add it now.
|
48
|
-
curr[1] << send(head, arg)
|
43
|
+
result << curr
|
49
44
|
end
|
45
|
+
curr[1] << (type == :static ? arg.inspect[1..-2] : "\#{#{arg}}")
|
50
46
|
else
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
47
|
+
if state != :looking
|
48
|
+
# We need to add the closing quote.
|
49
|
+
curr[1] << '"'
|
50
|
+
# If we found a single exp last time, let's add it.
|
51
|
+
result.concat(prev) if state == :single
|
52
|
+
end
|
53
|
+
# Compile the current exp
|
54
|
+
result << compile(exp)
|
57
55
|
# Now we're looking for more!
|
58
56
|
state = :looking
|
59
57
|
end
|
60
58
|
end
|
61
59
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
60
|
+
if state != :looking
|
61
|
+
# We need to add the closing quote.
|
62
|
+
curr[1] << '"'
|
63
|
+
# If we found a single exp last time, let's add it.
|
64
|
+
result.concat(prev) if state == :single
|
65
|
+
end
|
68
66
|
|
69
|
-
|
70
|
-
'#{%s}' % str
|
67
|
+
result
|
71
68
|
end
|
72
69
|
end
|
73
70
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Temple
|
2
|
+
module Filters
|
3
|
+
# Erase expressions with a certain type
|
4
|
+
#
|
5
|
+
# @api public
|
6
|
+
class Eraser < Filter
|
7
|
+
# [] is the empty type => keep all
|
8
|
+
default_options[:keep] = [[]]
|
9
|
+
|
10
|
+
def compile(exp)
|
11
|
+
exp.first == :multi || (do?(:keep, exp) && !do?(:erase, exp)) ?
|
12
|
+
super(exp) : [:multi]
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def do?(list, exp)
|
18
|
+
options[list].to_a.map {|type| [*type] }.any? {|type| exp[0,type.size] == type }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Temple
|
2
|
+
module Filters
|
3
|
+
# Escape dynamic or static expressions.
|
4
|
+
# This filter must be used after Temple::HTML::* and before the generators.
|
5
|
+
# It can be enclosed with Temple::Filters::DynamicInliner filters to
|
6
|
+
# reduce calls to Temple::Utils#escape_html.
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
class Escapable < Filter
|
10
|
+
# Activate the usage of html_safe? if it is available (for Rails 3 for example)
|
11
|
+
set_default_options :use_html_safe => ''.respond_to?(:html_safe?),
|
12
|
+
:disable_escape => false
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
super
|
16
|
+
@escape_code = options[:escape_code] ||
|
17
|
+
"Temple::Utils.escape_html#{options[:use_html_safe] ? '_safe' : ''}((%s))"
|
18
|
+
@escaper = eval("proc {|v| #{@escape_code % 'v'} }")
|
19
|
+
@escape = false
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_escape(flag, exp)
|
23
|
+
old = @escape
|
24
|
+
@escape = flag && !options[:disable_escape]
|
25
|
+
compile(exp)
|
26
|
+
ensure
|
27
|
+
@escape = old
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_static(value)
|
31
|
+
[:static, @escape ? @escaper[value] : value]
|
32
|
+
end
|
33
|
+
|
34
|
+
def on_dynamic(value)
|
35
|
+
[:dynamic, @escape ? @escape_code % value : value]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,9 +1,12 @@
|
|
1
1
|
module Temple
|
2
2
|
module Filters
|
3
|
+
# Flattens nested multi expressions
|
4
|
+
#
|
5
|
+
# @api public
|
3
6
|
class MultiFlattener < Filter
|
4
7
|
def on_multi(*exps)
|
5
8
|
# If the multi contains a single element, just return the element
|
6
|
-
return compile(exps.first) if exps.
|
9
|
+
return compile(exps.first) if exps.size == 1
|
7
10
|
result = [:multi]
|
8
11
|
|
9
12
|
exps.each do |exp|
|
@@ -10,27 +10,28 @@ module Temple
|
|
10
10
|
#
|
11
11
|
# [:multi,
|
12
12
|
# [:static, "Hello World!"]]
|
13
|
+
#
|
14
|
+
# @api public
|
13
15
|
class StaticMerger < Filter
|
14
16
|
def on_multi(*exps)
|
15
|
-
|
16
|
-
|
17
|
-
state = :looking
|
17
|
+
result = [:multi]
|
18
|
+
text = nil
|
18
19
|
|
19
20
|
exps.each do |exp|
|
20
21
|
if exp.first == :static
|
21
|
-
if
|
22
|
-
|
23
|
-
state = :static
|
22
|
+
if text
|
23
|
+
text << exp.last
|
24
24
|
else
|
25
|
-
|
25
|
+
text = exp.last.dup
|
26
|
+
result << [:static, text]
|
26
27
|
end
|
27
28
|
else
|
28
|
-
|
29
|
-
|
29
|
+
result << compile(exp)
|
30
|
+
text = nil unless exp.first == :newline
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
+
result
|
34
35
|
end
|
35
36
|
end
|
36
37
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Temple
|
2
|
+
module Filters
|
3
|
+
# Validates temple expression with given grammar
|
4
|
+
#
|
5
|
+
# @api public
|
6
|
+
class Validator < Filter
|
7
|
+
default_options[:grammar] = Temple::Grammar
|
8
|
+
|
9
|
+
def compile(exp)
|
10
|
+
options[:grammar].validate!(exp)
|
11
|
+
exp
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/temple/generators.rb
CHANGED
@@ -1,101 +1,56 @@
|
|
1
1
|
module Temple
|
2
|
-
#
|
2
|
+
# Exception raised if invalid temple expression is found
|
3
3
|
#
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# make exceptions report correct line numbers, which is very convenient.
|
12
|
-
#
|
13
|
-
# Then there's the result. This is what your engine (from the user's point
|
14
|
-
# of view) spits out. It's what happens if you evaluate the generated code.
|
15
|
-
#
|
16
|
-
# === [:multi, *sexp]
|
17
|
-
#
|
18
|
-
# Multi is what glues everything together. It's simply a sexp which combines
|
19
|
-
# several others sexps:
|
20
|
-
#
|
21
|
-
# [:multi,
|
22
|
-
# [:static, "Hello "],
|
23
|
-
# [:dynamic, "@world"]]
|
24
|
-
#
|
25
|
-
# === [:static, string]
|
26
|
-
#
|
27
|
-
# Static indicates that the given string should be appended to the result.
|
28
|
-
#
|
29
|
-
# Example:
|
30
|
-
#
|
31
|
-
# [:static, "Hello World"]
|
32
|
-
# # is the same as:
|
33
|
-
# _buf << "Hello World"
|
34
|
-
#
|
35
|
-
# [:static, "Hello \n World"]
|
36
|
-
# # is the same as
|
37
|
-
# _buf << "Hello\nWorld"
|
38
|
-
#
|
39
|
-
# === [:dynamic, ruby]
|
40
|
-
#
|
41
|
-
# Dynamic indicates that the given Ruby code should be evaluated and then
|
42
|
-
# appended to the result.
|
43
|
-
#
|
44
|
-
# The Ruby code must be a complete expression in the sense that you can pass
|
45
|
-
# it to eval() and it would not raise SyntaxError.
|
46
|
-
#
|
47
|
-
# === [:block, ruby]
|
48
|
-
#
|
49
|
-
# Block indicates that the given Ruby code should be evaluated, and may
|
50
|
-
# change the control flow. Any \n causes a newline in the generated code.
|
51
|
-
#
|
52
|
-
# === [:newline]
|
53
|
-
#
|
54
|
-
# Newline causes a newline in the generated code, but not in the result.
|
55
|
-
#
|
56
|
-
# === [:capture, variable_name, sexp]
|
57
|
-
#
|
58
|
-
# Evaluates the Sexp using the rules above, but instead of appending to the
|
59
|
-
# result, it sets the content to the variable given.
|
60
|
-
#
|
61
|
-
# Example:
|
4
|
+
# @api public
|
5
|
+
class InvalidExpression < RuntimeError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Abstract generator base class
|
9
|
+
# Generators should inherit this class and
|
10
|
+
# compile the Core Abstraction to ruby code.
|
62
11
|
#
|
63
|
-
#
|
64
|
-
# [:static, "Some content"],
|
65
|
-
# [:capture, "foo", [:static, "More content"]],
|
66
|
-
# [:dynamic, "foo.downcase"]]
|
67
|
-
# # is the same as:
|
68
|
-
# _buf << "Some content"
|
69
|
-
# foo = "More content"
|
70
|
-
# _buf << foo.downcase
|
12
|
+
# @api public
|
71
13
|
class Generator
|
72
14
|
include Mixins::Options
|
73
15
|
|
74
16
|
default_options[:buffer] = '_buf'
|
75
17
|
|
76
18
|
def call(exp)
|
77
|
-
[preamble, compile(exp), postamble].join('
|
19
|
+
[preamble, compile(exp), postamble].join('; ')
|
78
20
|
end
|
79
21
|
|
80
22
|
def compile(exp)
|
81
23
|
type, *args = exp
|
82
|
-
|
83
|
-
|
24
|
+
method = "on_#{type}"
|
25
|
+
if respond_to?(method)
|
26
|
+
send(method, *args)
|
84
27
|
else
|
85
|
-
raise "Generator supports only core expressions - found #{exp.inspect}"
|
28
|
+
raise InvalidExpression, "Generator supports only core expressions - found #{exp.inspect}"
|
86
29
|
end
|
87
30
|
end
|
88
31
|
|
89
32
|
def on_multi(*exp)
|
90
|
-
exp.map {
|
33
|
+
exp.map {|e| compile(e) }.join('; ')
|
91
34
|
end
|
92
35
|
|
93
36
|
def on_newline
|
94
37
|
"\n"
|
95
38
|
end
|
96
39
|
|
97
|
-
def on_capture(name,
|
98
|
-
options[:capture_generator].new(:buffer => name).call(
|
40
|
+
def on_capture(name, exp)
|
41
|
+
options[:capture_generator].new(:buffer => name).call(exp)
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_static(text)
|
45
|
+
concat(text.inspect)
|
46
|
+
end
|
47
|
+
|
48
|
+
def on_dynamic(code)
|
49
|
+
concat(code)
|
50
|
+
end
|
51
|
+
|
52
|
+
def on_code(code)
|
53
|
+
code
|
99
54
|
end
|
100
55
|
|
101
56
|
protected
|
@@ -115,36 +70,24 @@ module Temple
|
|
115
70
|
# _buf = []
|
116
71
|
# _buf << "static"
|
117
72
|
# _buf << dynamic
|
118
|
-
# block do
|
119
|
-
# _buf << "more static"
|
120
|
-
# end
|
121
73
|
# _buf.join
|
122
|
-
|
74
|
+
#
|
75
|
+
# @api public
|
76
|
+
class Array < Generator
|
123
77
|
def preamble
|
124
78
|
"#{buffer} = []"
|
125
79
|
end
|
126
80
|
|
127
81
|
def postamble
|
128
|
-
|
129
|
-
end
|
130
|
-
|
131
|
-
def on_static(text)
|
132
|
-
concat(text.inspect)
|
133
|
-
end
|
134
|
-
|
135
|
-
def on_dynamic(code)
|
136
|
-
concat(code)
|
137
|
-
end
|
138
|
-
|
139
|
-
def on_block(code)
|
140
|
-
code
|
82
|
+
buffer
|
141
83
|
end
|
142
84
|
end
|
143
85
|
|
144
|
-
# Just like
|
145
|
-
|
86
|
+
# Just like Array, but calls #join on the array.
|
87
|
+
# @api public
|
88
|
+
class ArrayBuffer < Array
|
146
89
|
def postamble
|
147
|
-
buffer
|
90
|
+
"#{buffer} = #{buffer}.join"
|
148
91
|
end
|
149
92
|
end
|
150
93
|
|
@@ -153,10 +96,9 @@ module Temple
|
|
153
96
|
# _buf = ''
|
154
97
|
# _buf << "static"
|
155
98
|
# _buf << dynamic.to_s
|
156
|
-
# block do
|
157
|
-
# _buf << "more static"
|
158
|
-
# end
|
159
99
|
# _buf
|
100
|
+
#
|
101
|
+
# @api public
|
160
102
|
class StringBuffer < Array
|
161
103
|
def preamble
|
162
104
|
"#{buffer} = ''"
|
@@ -172,10 +114,9 @@ module Temple
|
|
172
114
|
# @output_buffer = ActionView::OutputBuffer
|
173
115
|
# @output_buffer.safe_concat "static"
|
174
116
|
# @output_buffer.safe_concat dynamic.to_s
|
175
|
-
# block do
|
176
|
-
# @output_buffer << "more static"
|
177
|
-
# end
|
178
117
|
# @output_buffer
|
118
|
+
#
|
119
|
+
# @api public
|
179
120
|
class RailsOutputBuffer < StringBuffer
|
180
121
|
set_default_options :buffer_class => 'ActionView::OutputBuffer',
|
181
122
|
:buffer => '@output_buffer',
|