temple 0.2.0 → 0.3.0
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/.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',
|