temple 0.7.6 → 0.7.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -0
- data/CHANGES +5 -0
- data/Gemfile +1 -1
- data/lib/temple.rb +2 -0
- data/lib/temple/filters/remove_bom.rb +1 -1
- data/lib/temple/filters/static_analyzer.rb +87 -0
- data/lib/temple/filters/string_splitter.rb +130 -0
- data/lib/temple/generator.rb +1 -1
- data/lib/temple/generators/array_buffer.rb +3 -2
- data/lib/temple/generators/erb.rb +1 -1
- data/lib/temple/generators/rails_output_buffer.rb +1 -1
- data/lib/temple/html/attribute_merger.rb +5 -10
- data/lib/temple/html/pretty.rb +2 -2
- data/lib/temple/mixins/dispatcher.rb +8 -6
- data/lib/temple/utils.rb +15 -4
- data/lib/temple/version.rb +1 -1
- data/test/filters/test_static_analyzer.rb +23 -0
- data/test/filters/test_string_splitter.rb +18 -0
- data/test/test_generator.rb +4 -4
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70234f9ea5cb84da4b1a8cdcfc8f63056d8af5ce
|
4
|
+
data.tar.gz: 4b76d19c5643183eb268c83dffc968f777c8d97a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c7ec6543f4fc8d3d95fc5046a606135605886b5e0ab67deb50e311ae50b5ff7b3030971173ca42d1ca8b67a45c33427b2b2cbaaac0b071f02d17dfcae0ef274
|
7
|
+
data.tar.gz: a8fb82e723319e0b4f1b11cd33c7b155f1cebda73345bf418b22626bd23b566b85904e45474535c8406fdd9693c6e1a7d75547b9c9d323d8b298cb9bffa86c50
|
data/.travis.yml
CHANGED
data/CHANGES
CHANGED
data/Gemfile
CHANGED
data/lib/temple.rb
CHANGED
@@ -43,7 +43,9 @@ module Temple
|
|
43
43
|
autoload :CodeMerger, 'temple/filters/code_merger'
|
44
44
|
autoload :ControlFlow, 'temple/filters/control_flow'
|
45
45
|
autoload :MultiFlattener, 'temple/filters/multi_flattener'
|
46
|
+
autoload :StaticAnalyzer, 'temple/filters/static_analyzer'
|
46
47
|
autoload :StaticMerger, 'temple/filters/static_merger'
|
48
|
+
autoload :StringSplitter, 'temple/filters/string_splitter'
|
47
49
|
autoload :DynamicInliner, 'temple/filters/dynamic_inliner'
|
48
50
|
autoload :Escapable, 'temple/filters/escapable'
|
49
51
|
autoload :Eraser, 'temple/filters/eraser'
|
@@ -0,0 +1,87 @@
|
|
1
|
+
begin
|
2
|
+
require 'ripper'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
module Temple
|
7
|
+
module Filters
|
8
|
+
# Convert [:dynamic, code] to [:static, text] if code is static Ruby expression.
|
9
|
+
class StaticAnalyzer < Filter
|
10
|
+
STATIC_TOKENS = [
|
11
|
+
:on_tstring_beg, :on_tstring_end, :on_tstring_content,
|
12
|
+
:on_embexpr_beg, :on_embexpr_end,
|
13
|
+
:on_lbracket, :on_rbracket,
|
14
|
+
:on_qwords_beg, :on_words_sep, :on_qwords_sep,
|
15
|
+
:on_lparen, :on_rparen,
|
16
|
+
:on_lbrace, :on_rbrace, :on_label,
|
17
|
+
:on_int, :on_float, :on_imaginary,
|
18
|
+
:on_comma, :on_sp,
|
19
|
+
].freeze
|
20
|
+
|
21
|
+
DYNAMIC_TOKENS = [
|
22
|
+
:on_ident, :on_period,
|
23
|
+
].freeze
|
24
|
+
|
25
|
+
STATIC_KEYWORDS = [
|
26
|
+
'true', 'false', 'nil',
|
27
|
+
].freeze
|
28
|
+
|
29
|
+
STATIC_OPERATORS = [
|
30
|
+
'=>',
|
31
|
+
].freeze
|
32
|
+
|
33
|
+
if defined?(Ripper)
|
34
|
+
def self.static?(code)
|
35
|
+
return false if code.nil? || code.strip.empty?
|
36
|
+
return false if SyntaxChecker.syntax_error?(code)
|
37
|
+
|
38
|
+
Ripper.lex(code).each do |(_, col), token, str|
|
39
|
+
case token
|
40
|
+
when *STATIC_TOKENS
|
41
|
+
# noop
|
42
|
+
when :on_kw
|
43
|
+
return false unless STATIC_KEYWORDS.include?(str)
|
44
|
+
when :on_op
|
45
|
+
return false unless STATIC_OPERATORS.include?(str)
|
46
|
+
when *DYNAMIC_TOKENS
|
47
|
+
return false
|
48
|
+
else
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
def on_dynamic(code)
|
56
|
+
if StaticAnalyzer.static?(code)
|
57
|
+
[:static, eval(code).to_s]
|
58
|
+
else
|
59
|
+
[:dynamic, code]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class SyntaxChecker < Ripper
|
64
|
+
class ParseError < StandardError; end
|
65
|
+
|
66
|
+
def self.syntax_error?(code)
|
67
|
+
self.new(code).parse
|
68
|
+
false
|
69
|
+
rescue ParseError
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def on_parse_error(*)
|
76
|
+
raise ParseError
|
77
|
+
end
|
78
|
+
end
|
79
|
+
else
|
80
|
+
# Do nothing if ripper is unavailable
|
81
|
+
def call(ast)
|
82
|
+
ast
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
begin
|
2
|
+
require 'ripper'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
module Temple
|
7
|
+
module Filters
|
8
|
+
# Compile [:dynamic, "foo#{bar}"] to [:multi, [:static, 'foo'], [:dynamic, 'bar']]
|
9
|
+
class StringSplitter < Filter
|
10
|
+
if defined?(Ripper) && RUBY_VERSION >= "2.0.0"
|
11
|
+
class << self
|
12
|
+
# `code` param must be valid string literal
|
13
|
+
def compile(code)
|
14
|
+
[].tap do |exps|
|
15
|
+
tokens = Ripper.lex(code.strip)
|
16
|
+
tokens.pop while tokens.last && [:on_comment, :on_sp].include?(tokens.last[1])
|
17
|
+
|
18
|
+
if tokens.size < 2
|
19
|
+
raise "Expected token size >= 2 but got: #{tokens.size}"
|
20
|
+
end
|
21
|
+
compile_tokens!(exps, tokens)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def strip_quotes!(tokens)
|
28
|
+
_, type, beg_str = tokens.shift
|
29
|
+
if type != :on_tstring_beg
|
30
|
+
raise "Expected :on_tstring_beg but got: #{type}"
|
31
|
+
end
|
32
|
+
|
33
|
+
_, type, end_str = tokens.pop
|
34
|
+
if type != :on_tstring_end
|
35
|
+
raise "Expected :on_tstring_end but got: #{type}"
|
36
|
+
end
|
37
|
+
|
38
|
+
[beg_str, end_str]
|
39
|
+
end
|
40
|
+
|
41
|
+
def compile_tokens!(exps, tokens)
|
42
|
+
beg_str, end_str = strip_quotes!(tokens)
|
43
|
+
|
44
|
+
until tokens.empty?
|
45
|
+
_, type, str = tokens.shift
|
46
|
+
|
47
|
+
case type
|
48
|
+
when :on_tstring_content
|
49
|
+
exps << [:static, eval("#{beg_str}#{str}#{end_str}").to_s]
|
50
|
+
when :on_embexpr_beg
|
51
|
+
embedded = shift_balanced_embexpr(tokens)
|
52
|
+
exps << [:dynamic, embedded] unless embedded.empty?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def shift_balanced_embexpr(tokens)
|
58
|
+
String.new.tap do |embedded|
|
59
|
+
embexpr_open = 1
|
60
|
+
|
61
|
+
until tokens.empty?
|
62
|
+
_, type, str = tokens.shift
|
63
|
+
case type
|
64
|
+
when :on_embexpr_beg
|
65
|
+
embexpr_open += 1
|
66
|
+
when :on_embexpr_end
|
67
|
+
embexpr_open -= 1
|
68
|
+
break if embexpr_open == 0
|
69
|
+
end
|
70
|
+
|
71
|
+
embedded << str
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def on_dynamic(code)
|
78
|
+
return [:dynamic, code] unless string_literal?(code)
|
79
|
+
return [:dynamic, code] if code.include?("\n")
|
80
|
+
|
81
|
+
temple = [:multi]
|
82
|
+
StringSplitter.compile(code).each do |type, content|
|
83
|
+
case type
|
84
|
+
when :static
|
85
|
+
temple << [:static, content]
|
86
|
+
when :dynamic
|
87
|
+
temple << on_dynamic(content)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
temple
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def string_literal?(code)
|
96
|
+
return false if SyntaxChecker.syntax_error?(code)
|
97
|
+
|
98
|
+
type, instructions = Ripper.sexp(code)
|
99
|
+
return false if type != :program
|
100
|
+
return false if instructions.size > 1
|
101
|
+
|
102
|
+
type, _ = instructions.first
|
103
|
+
type == :string_literal
|
104
|
+
end
|
105
|
+
|
106
|
+
class SyntaxChecker < Ripper
|
107
|
+
class ParseError < StandardError; end
|
108
|
+
|
109
|
+
def self.syntax_error?(code)
|
110
|
+
self.new(code).parse
|
111
|
+
false
|
112
|
+
rescue ParseError
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def on_parse_error(*)
|
119
|
+
raise ParseError
|
120
|
+
end
|
121
|
+
end
|
122
|
+
else
|
123
|
+
# Do nothing if ripper is unavailable
|
124
|
+
def call(ast)
|
125
|
+
ast
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/lib/temple/generator.rb
CHANGED
@@ -5,7 +5,7 @@ module Temple
|
|
5
5
|
# _buf = []
|
6
6
|
# _buf << "static"
|
7
7
|
# _buf << dynamic
|
8
|
-
# _buf.join
|
8
|
+
# _buf.join("")
|
9
9
|
#
|
10
10
|
# @api public
|
11
11
|
class ArrayBuffer < Array
|
@@ -21,7 +21,8 @@ module Temple
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def return_buffer
|
24
|
-
|
24
|
+
freeze = options[:freeze_static] ? '.freeze' : ''
|
25
|
+
"#{buffer} = #{buffer}.join(\"\"#{freeze})"
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
@@ -6,40 +6,35 @@ module Temple
|
|
6
6
|
define_options merge_attrs: {'id' => '_', 'class' => ' '}
|
7
7
|
|
8
8
|
def on_html_attrs(*attrs)
|
9
|
-
names = []
|
10
9
|
values = {}
|
11
10
|
|
12
|
-
attrs.each do |
|
13
|
-
name
|
11
|
+
attrs.each do |_, _, name, value|
|
12
|
+
name = name.to_s
|
14
13
|
if values[name]
|
15
14
|
raise(FilterError, "Multiple #{name} attributes specified") unless options[:merge_attrs][name]
|
16
15
|
values[name] << value
|
17
16
|
else
|
18
17
|
values[name] = [value]
|
19
|
-
names << name
|
20
18
|
end
|
21
19
|
end
|
22
20
|
|
23
|
-
attrs =
|
24
|
-
value = values[name]
|
21
|
+
attrs = values.map do |name, value|
|
25
22
|
if (delimiter = options[:merge_attrs][name]) && value.size > 1
|
26
23
|
exp = [:multi]
|
27
24
|
if value.all? {|v| contains_nonempty_static?(v) }
|
28
25
|
exp << value.first
|
29
26
|
value[1..-1].each {|v| exp << [:static, delimiter] << v }
|
30
|
-
[:html, :attr, name, exp]
|
31
27
|
else
|
32
28
|
captures = unique_name
|
33
29
|
exp << [:code, "#{captures} = []"]
|
34
30
|
value.each_with_index {|v, i| exp << [:capture, "#{captures}[#{i}]", v] }
|
35
31
|
exp << [:dynamic, "#{captures}.reject(&:empty?).join(#{delimiter.inspect})"]
|
36
32
|
end
|
37
|
-
[:html, :attr, name, exp]
|
38
33
|
else
|
39
|
-
|
34
|
+
exp = value.first
|
40
35
|
end
|
36
|
+
[:html, :attr, name, exp]
|
41
37
|
end
|
42
|
-
|
43
38
|
[:html, :attrs, *attrs]
|
44
39
|
end
|
45
40
|
end
|
data/lib/temple/html/pretty.rb
CHANGED
@@ -26,8 +26,8 @@ module Temple
|
|
26
26
|
def on_static(content)
|
27
27
|
return [:static, content] unless @pretty
|
28
28
|
unless @pre_tags && @pre_tags =~ content
|
29
|
-
content = content.sub(/\A\s*\n?/, "\n") if @indent_next
|
30
|
-
content = content.gsub("\n", indent)
|
29
|
+
content = content.sub(/\A\s*\n?/, "\n".freeze) if @indent_next
|
30
|
+
content = content.gsub("\n".freeze, indent)
|
31
31
|
end
|
32
32
|
@indent_next = false
|
33
33
|
[:static, content]
|
@@ -58,12 +58,14 @@ module Temple
|
|
58
58
|
def replace_dispatcher(exp)
|
59
59
|
tree = DispatchNode.new
|
60
60
|
dispatched_methods.each do |method|
|
61
|
-
method.split('_')[1..-1].inject(tree) {|node, type| node[type.to_sym] }.method = method
|
61
|
+
method.split('_'.freeze)[1..-1].inject(tree) {|node, type| node[type.to_sym] }.method = method
|
62
62
|
end
|
63
|
-
self.class.class_eval
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
64
|
+
def dispatcher(exp)
|
65
|
+
return replace_dispatcher(exp) if self.class != #{self.class}
|
66
|
+
#{tree.compile.gsub("\n", "\n ")}
|
67
|
+
end
|
68
|
+
RUBY
|
67
69
|
dispatcher(exp)
|
68
70
|
end
|
69
71
|
|
@@ -91,7 +93,7 @@ end}
|
|
91
93
|
code = "case(exp[#{level}])\n"
|
92
94
|
each do |key, child|
|
93
95
|
code << "when #{key.inspect}\n " <<
|
94
|
-
child.compile(level + 1, call_method).gsub("\n", "\n ") << "\n"
|
96
|
+
child.compile(level + 1, call_method).gsub("\n".freeze, "\n ".freeze) << "\n".freeze
|
95
97
|
end
|
96
98
|
code << "else\n " << (call_method || 'exp') << "\nend"
|
97
99
|
end
|
data/lib/temple/utils.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
begin
|
2
2
|
require 'escape_utils'
|
3
3
|
rescue LoadError
|
4
|
-
|
4
|
+
begin
|
5
|
+
require 'cgi/escape'
|
6
|
+
rescue LoadError
|
7
|
+
end
|
5
8
|
end
|
6
9
|
|
7
10
|
module Temple
|
@@ -26,6 +29,14 @@ module Temple
|
|
26
29
|
def escape_html(html)
|
27
30
|
EscapeUtils.escape_html(html.to_s, false)
|
28
31
|
end
|
32
|
+
elsif defined?(CGI.escapeHTML)
|
33
|
+
# Returns an escaped copy of `html`.
|
34
|
+
#
|
35
|
+
# @param html [String] The string to escape
|
36
|
+
# @return [String] The escaped string
|
37
|
+
def escape_html(html)
|
38
|
+
CGI.escapeHTML(html.to_s)
|
39
|
+
end
|
29
40
|
else
|
30
41
|
# Used by escape_html
|
31
42
|
# @api private
|
@@ -54,7 +65,7 @@ module Temple
|
|
54
65
|
# @return [String] Variable name
|
55
66
|
def unique_name(prefix = nil)
|
56
67
|
@unique_name ||= 0
|
57
|
-
prefix ||= (@unique_prefix ||= self.class.name.gsub('::', '_').downcase)
|
68
|
+
prefix ||= (@unique_prefix ||= self.class.name.gsub('::'.freeze, '_'.freeze).downcase)
|
58
69
|
"_#{prefix}#{@unique_name += 1}"
|
59
70
|
end
|
60
71
|
|
@@ -81,8 +92,8 @@ module Temple
|
|
81
92
|
level = text.scan(/^\s*/).map(&:size).min
|
82
93
|
text = text.gsub(/(?!\A)^\s{#{level}}/, '') if level > 0
|
83
94
|
|
84
|
-
text = text.sub(/\A\s*\n?/, "\n") if indent_next
|
85
|
-
text = text.gsub("\n", indent)
|
95
|
+
text = text.sub(/\A\s*\n?/, "\n".freeze) if indent_next
|
96
|
+
text = text.gsub("\n".freeze, indent)
|
86
97
|
|
87
98
|
safe ? text.html_safe : text
|
88
99
|
end
|
data/lib/temple/version.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'helper'
|
2
|
+
begin
|
3
|
+
require 'ripper'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
if defined?(Ripper)
|
8
|
+
describe Temple::Filters::StaticAnalyzer do
|
9
|
+
before do
|
10
|
+
@filter = Temple::Filters::StaticAnalyzer.new
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should convert :dynamic to :static if code is static' do
|
14
|
+
@filter.call([:dynamic, '"#{"hello"}#{100}"']
|
15
|
+
).should.equal [:static, 'hello100']
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should not convert :dynamic if code is dynamic' do
|
19
|
+
exp = [:dynamic, '"#{hello}#{100}"']
|
20
|
+
@filter.call(exp).should.equal(exp)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'helper'
|
2
|
+
begin
|
3
|
+
require 'ripper'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
if defined?(Ripper) && RUBY_VERSION >= "2.0.0"
|
8
|
+
describe Temple::Filters::StringSplitter do
|
9
|
+
before do
|
10
|
+
@filter = Temple::Filters::StringSplitter.new
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should split :dynamic with string literal' do
|
14
|
+
@filter.call([:dynamic, '"static#{dynamic}"']
|
15
|
+
).should.equal [:multi, [:static, 'static'], [:dynamic, 'dynamic']]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/test/test_generator.rb
CHANGED
@@ -97,16 +97,16 @@ describe Temple::Generators::ArrayBuffer do
|
|
97
97
|
gen = Temple::Generators::ArrayBuffer.new(freeze_static: false)
|
98
98
|
gen.call([:static, 'test']).should.equal '_buf = "test"'
|
99
99
|
gen.call([:dynamic, 'test']).should.equal '_buf = (test).to_s'
|
100
|
-
gen.call([:code, 'test']).should.equal '_buf = []; test; _buf = _buf.join'
|
100
|
+
gen.call([:code, 'test']).should.equal '_buf = []; test; _buf = _buf.join("")'
|
101
101
|
|
102
|
-
gen.call([:multi, [:static, 'a'], [:static, 'b']]).should.equal '_buf = []; _buf << ("a"); _buf << ("b"); _buf = _buf.join'
|
103
|
-
gen.call([:multi, [:static, 'a'], [:dynamic, 'b']]).should.equal '_buf = []; _buf << ("a"); _buf << (b); _buf = _buf.join'
|
102
|
+
gen.call([:multi, [:static, 'a'], [:static, 'b']]).should.equal '_buf = []; _buf << ("a"); _buf << ("b"); _buf = _buf.join("")'
|
103
|
+
gen.call([:multi, [:static, 'a'], [:dynamic, 'b']]).should.equal '_buf = []; _buf << ("a"); _buf << (b); _buf = _buf.join("")'
|
104
104
|
end
|
105
105
|
|
106
106
|
it 'should freeze static' do
|
107
107
|
gen = Temple::Generators::ArrayBuffer.new(freeze_static: true)
|
108
108
|
gen.call([:static, 'test']).should.equal '_buf = "test"'
|
109
|
-
gen.call([:multi, [:dynamic, '1'], [:static, 'test']]).should.equal '_buf = []; _buf << (1); _buf << ("test".freeze); _buf = _buf.join'
|
109
|
+
gen.call([:multi, [:dynamic, '1'], [:static, 'test']]).should.equal '_buf = []; _buf << (1); _buf << ("test".freeze); _buf = _buf.join("".freeze)'
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
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.7.
|
4
|
+
version: 0.7.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Magnus Holm
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-05-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: tilt
|
@@ -100,7 +100,9 @@ files:
|
|
100
100
|
- lib/temple/filters/escapable.rb
|
101
101
|
- lib/temple/filters/multi_flattener.rb
|
102
102
|
- lib/temple/filters/remove_bom.rb
|
103
|
+
- lib/temple/filters/static_analyzer.rb
|
103
104
|
- lib/temple/filters/static_merger.rb
|
105
|
+
- lib/temple/filters/string_splitter.rb
|
104
106
|
- lib/temple/filters/validator.rb
|
105
107
|
- lib/temple/generator.rb
|
106
108
|
- lib/temple/generators/array.rb
|
@@ -136,7 +138,9 @@ files:
|
|
136
138
|
- test/filters/test_eraser.rb
|
137
139
|
- test/filters/test_escapable.rb
|
138
140
|
- test/filters/test_multi_flattener.rb
|
141
|
+
- test/filters/test_static_analyzer.rb
|
139
142
|
- test/filters/test_static_merger.rb
|
143
|
+
- test/filters/test_string_splitter.rb
|
140
144
|
- test/helper.rb
|
141
145
|
- test/html/test_attribute_merger.rb
|
142
146
|
- test/html/test_attribute_remover.rb
|
@@ -177,4 +181,3 @@ signing_key:
|
|
177
181
|
specification_version: 4
|
178
182
|
summary: Template compilation framework in Ruby
|
179
183
|
test_files: []
|
180
|
-
has_rdoc:
|