slim 0.6.1 → 0.7.0.beta.2
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/.gitignore +8 -0
- data/Gemfile +1 -6
- data/Gemfile.lock +20 -16
- data/README.md +137 -90
- data/Rakefile +9 -37
- data/benchmarks/run.rb +63 -0
- data/benchmarks/src/complex.erb +23 -0
- data/benchmarks/src/complex.haml +18 -0
- data/benchmarks/src/complex.slim +18 -0
- data/benchmarks/src/complex_view.rb +17 -0
- data/lib/slim.rb +15 -11
- data/lib/slim/compiler.rb +71 -137
- data/lib/slim/embedded_engine.rb +108 -0
- data/lib/slim/end_inserter.rb +57 -0
- data/lib/slim/engine.rb +16 -14
- data/lib/slim/filter.rb +44 -0
- data/lib/slim/helpers.rb +37 -0
- data/lib/slim/parser.rb +355 -0
- data/lib/slim/rails.rb +2 -2
- data/lib/slim/template.rb +18 -0
- data/lib/slim/version.rb +3 -0
- data/slim.gemspec +26 -66
- data/test/helper.rb +32 -4
- data/test/slim/test_code_blocks.rb +33 -0
- data/test/slim/test_code_escaping.rb +69 -0
- data/test/slim/test_code_evaluation.rb +199 -0
- data/test/slim/test_code_helpers.rb +12 -0
- data/test/slim/test_code_output.rb +116 -0
- data/test/slim/test_code_structure.rb +84 -0
- data/test/slim/test_embedded_engines.rb +55 -0
- data/test/slim/test_html_escaping.rb +32 -0
- data/test/slim/test_html_structure.rb +181 -0
- data/test/slim/test_parser_errors.rb +98 -0
- data/test/slim/test_slim_template.rb +128 -0
- data/vim/slim.vim +33 -0
- data/vim/test.slim +27 -0
- metadata +127 -34
- data/lib/slim/optimizer.rb +0 -70
- data/readme.html +0 -159
- data/test/slim/test_compiler.rb +0 -389
- data/test/slim/test_engine.rb +0 -458
- data/test/test_slim.rb +0 -4
data/lib/slim/rails.rb
CHANGED
@@ -6,10 +6,10 @@ module ActionView
|
|
6
6
|
include Compilable
|
7
7
|
|
8
8
|
def compile(template)
|
9
|
-
return Slim::Engine.new(template.source).
|
9
|
+
return Slim::Engine.new(template.source, use_html_safe: true).prepare
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
Template.register_default_template_handler :slim, TemplateHandlers::SlimHandler
|
15
|
-
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Slim
|
2
|
+
class Template < Tilt::Template
|
3
|
+
def prepare
|
4
|
+
@src = Engine.new(options).compile(data)
|
5
|
+
end
|
6
|
+
|
7
|
+
def evaluate(scope, locals, &block)
|
8
|
+
scope.instance_eval { extend Slim::Helpers } if options[:helpers]
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def precompiled_template(locals)
|
13
|
+
@src
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Tilt.register 'slim', Template
|
18
|
+
end
|
data/lib/slim/version.rb
ADDED
data/slim.gemspec
CHANGED
@@ -1,73 +1,33 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
require File.dirname(__FILE__) + "/lib/slim/version"
|
5
3
|
|
6
4
|
Gem::Specification.new do |s|
|
7
|
-
s.name
|
8
|
-
s.version
|
5
|
+
s.name = "slim"
|
6
|
+
s.version = Slim::VERSION
|
7
|
+
s.date = Date.today.to_s
|
8
|
+
s.authors = ["Andrew Stone", "Fred Wu"]
|
9
|
+
s.email = ["andy@stonean.com", "ifredwu@gmail.com"]
|
10
|
+
s.summary = %q{Slim is a template language.}
|
11
|
+
s.description = %q{Slim is a template language whose goal is reduce the syntax to the essential parts without becoming cryptic.}
|
12
|
+
s.homepage = %q{http://github.com/stonean/slim}
|
13
|
+
s.extra_rdoc_files = ["README.md"]
|
14
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
s.rubyforge_project = s.name
|
9
17
|
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.
|
13
|
-
s.description = %q{Slim is a template language whose goal is reduce the syntax to the essential parts without becoming cryptic.}
|
14
|
-
s.email = ["andy@stonean.com", "ifredwu@gmail.com"]
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"README.md"
|
17
|
-
]
|
18
|
-
s.files = [
|
19
|
-
"Gemfile",
|
20
|
-
"Gemfile.lock",
|
21
|
-
"README.md",
|
22
|
-
"Rakefile",
|
23
|
-
"lib/slim.rb",
|
24
|
-
"lib/slim/compiler.rb",
|
25
|
-
"lib/slim/engine.rb",
|
26
|
-
"lib/slim/optimizer.rb",
|
27
|
-
"lib/slim/rails.rb",
|
28
|
-
"readme.html",
|
29
|
-
"slim.gemspec",
|
30
|
-
"test/helper.rb",
|
31
|
-
"test/slim/test_compiler.rb",
|
32
|
-
"test/slim/test_engine.rb",
|
33
|
-
"test/test_slim.rb"
|
34
|
-
]
|
35
|
-
s.homepage = %q{http://github.com/stonean/slim}
|
36
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
37
21
|
s.require_paths = ["lib"]
|
38
|
-
s.rubyforge_project = %q{slim}
|
39
|
-
s.rubygems_version = %q{1.3.7}
|
40
|
-
s.summary = %q{Slim is a template language.}
|
41
|
-
s.test_files = [
|
42
|
-
"test/helper.rb",
|
43
|
-
"test/test_slim.rb",
|
44
|
-
"test/slim/test_engine.rb",
|
45
|
-
"test/slim/test_compiler.rb"
|
46
|
-
]
|
47
22
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
else
|
59
|
-
s.add_dependency(%q<escape_utils>, [">= 0"])
|
60
|
-
s.add_dependency(%q<rake>, [">= 0"])
|
61
|
-
s.add_dependency(%q<jeweler>, [">= 0"])
|
62
|
-
s.add_dependency(%q<haml>, [">= 0"])
|
63
|
-
s.add_dependency(%q<erubis>, [">= 0"])
|
64
|
-
end
|
65
|
-
else
|
66
|
-
s.add_dependency(%q<escape_utils>, [">= 0"])
|
67
|
-
s.add_dependency(%q<rake>, [">= 0"])
|
68
|
-
s.add_dependency(%q<jeweler>, [">= 0"])
|
69
|
-
s.add_dependency(%q<haml>, [">= 0"])
|
70
|
-
s.add_dependency(%q<erubis>, [">= 0"])
|
71
|
-
end
|
23
|
+
s.add_runtime_dependency(%q<escape_utils>, [">= 0.1.9"]) unless RUBY_PLATFORM == "java"
|
24
|
+
s.add_runtime_dependency(%q<temple>, ["~> 0.1.2"])
|
25
|
+
s.add_runtime_dependency(%q<tilt>, ["~> 1.1"])
|
26
|
+
s.add_development_dependency(%q<rake>, [">= 0.8.7"])
|
27
|
+
s.add_development_dependency(%q<haml>, [">= 0"])
|
28
|
+
s.add_development_dependency(%q<erubis>, [">= 0"])
|
29
|
+
s.add_development_dependency(%q<minitest>, [">= 0"])
|
30
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
31
|
+
s.add_development_dependency(%q<rdiscount>, [">= 0"])
|
32
|
+
s.add_development_dependency(%q<liquid>, [">= 0"])
|
72
33
|
end
|
73
|
-
|
data/test/helper.rb
CHANGED
@@ -1,12 +1,33 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require 'rubygems'
|
3
4
|
require 'minitest/unit'
|
4
5
|
|
5
6
|
MiniTest::Unit.autorun
|
6
7
|
|
7
|
-
|
8
|
+
require File.dirname(__FILE__) + '/../lib/slim'
|
8
9
|
|
9
|
-
|
10
|
+
class TestSlim < MiniTest::Unit::TestCase
|
11
|
+
def setup
|
12
|
+
@env = Env.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
String.send(:undef_method, :html_safe?) if String.method_defined?(:html_safe?)
|
17
|
+
Slim::Filter::DEFAULT_OPTIONS.delete(:use_html_safe)
|
18
|
+
end
|
19
|
+
|
20
|
+
def assert_html(expected, source, options = {})
|
21
|
+
assert_equal expected, Slim::Engine.new(source, options).render(@env)
|
22
|
+
end
|
23
|
+
|
24
|
+
def assert_syntax_error(message, source, options = {})
|
25
|
+
Slim::Engine.new(source, options).render(@env)
|
26
|
+
raise 'Syntax error expected'
|
27
|
+
rescue Slim::Parser::SyntaxError => ex
|
28
|
+
assert_equal ex.message, message
|
29
|
+
end
|
30
|
+
end
|
10
31
|
|
11
32
|
class Env
|
12
33
|
def id_helper
|
@@ -23,8 +44,15 @@ class Env
|
|
23
44
|
|
24
45
|
def hello_world(text = "Hello World from @env", opts = {})
|
25
46
|
text << opts.to_a * " " if opts.any?
|
26
|
-
|
27
|
-
|
47
|
+
if block_given?
|
48
|
+
"#{text} #{yield} #{text}"
|
49
|
+
else
|
50
|
+
text
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def action_path(*args)
|
55
|
+
"/action-#{args.join('-')}"
|
28
56
|
end
|
29
57
|
|
30
58
|
def in_keyword
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestSlimCodeBlocks < TestSlim
|
4
|
+
def test_render_with_output_code_block
|
5
|
+
source = %q{
|
6
|
+
p
|
7
|
+
= hello_world "Hello Ruby!" do
|
8
|
+
| Hello from within a block!
|
9
|
+
}
|
10
|
+
|
11
|
+
assert_html '<p>Hello Ruby! Hello from within a block! Hello Ruby!</p>', source
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_render_with_output_code_within_block
|
15
|
+
source = %q{
|
16
|
+
p
|
17
|
+
= hello_world "Hello Ruby!" do
|
18
|
+
= hello_world "Hello from within a block! "
|
19
|
+
}
|
20
|
+
|
21
|
+
assert_html '<p>Hello Ruby! Hello from within a block! Hello Ruby!</p>', source
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_render_with_control_code_loop
|
25
|
+
source = %q{
|
26
|
+
p
|
27
|
+
- 3.times do
|
28
|
+
| Hey!
|
29
|
+
}
|
30
|
+
|
31
|
+
assert_html '<p>Hey!Hey!Hey!</p>', source
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestSlimCodeEscaping < TestSlim
|
4
|
+
def test_escaping_evil_method
|
5
|
+
source = %q{
|
6
|
+
p = evil_method
|
7
|
+
}
|
8
|
+
|
9
|
+
assert_html '<p><script>do_something_evil();</script></p>', source
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_escape_interpolation
|
13
|
+
source = %q{
|
14
|
+
p \\#{hello_world}
|
15
|
+
}
|
16
|
+
|
17
|
+
assert_html '<p>#{hello_world}</p>', source
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_render_without_html_safe
|
21
|
+
source = %q{
|
22
|
+
p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
|
23
|
+
}
|
24
|
+
|
25
|
+
assert_html "<p><strong>Hello World\n, meet \"Slim\"</strong>.</p>", source
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_render_with_html_safe_false
|
29
|
+
String.send(:define_method, :html_safe?) { false }
|
30
|
+
|
31
|
+
source = %q{
|
32
|
+
p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
|
33
|
+
}
|
34
|
+
|
35
|
+
assert_html "<p><strong>Hello World\n, meet \"Slim\"</strong>.</p>", source, :use_html_safe => true
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_render_with_html_safe_true
|
39
|
+
String.send(:define_method, :html_safe?) { true }
|
40
|
+
|
41
|
+
source = %q{
|
42
|
+
p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
|
43
|
+
}
|
44
|
+
|
45
|
+
assert_html "<p><strong>Hello World\n, meet \"Slim\"</strong>.</p>", source, :use_html_safe => true
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_render_with_global_html_safe_false
|
49
|
+
String.send(:define_method, :html_safe?) { false }
|
50
|
+
Slim::Filter::DEFAULT_OPTIONS[:use_html_safe] = false
|
51
|
+
|
52
|
+
source = %q{
|
53
|
+
p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
|
54
|
+
}
|
55
|
+
|
56
|
+
assert_html "<p><strong>Hello World\n, meet \"Slim\"</strong>.</p>", source
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_render_with_global_html_safe_true
|
60
|
+
String.send(:define_method, :html_safe?) { true }
|
61
|
+
Slim::Filter::DEFAULT_OPTIONS[:use_html_safe] = true
|
62
|
+
|
63
|
+
source = %q{
|
64
|
+
p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
|
65
|
+
}
|
66
|
+
|
67
|
+
assert_html "<p><strong>Hello World\n, meet \"Slim\"</strong>.</p>", source
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestSlimCodeEvaluation < TestSlim
|
4
|
+
def test_render_with_call_to_set_attributes
|
5
|
+
source = %q{
|
6
|
+
p id="#{id_helper}" class="hello world" = hello_world
|
7
|
+
}
|
8
|
+
|
9
|
+
assert_html '<p id="notice" class="hello world">Hello World from @env</p>', source
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_render_with_call_to_set_custom_attributes
|
13
|
+
source = %q{
|
14
|
+
p data-id="#{id_helper}" data-class="hello world"
|
15
|
+
= hello_world
|
16
|
+
}
|
17
|
+
|
18
|
+
assert_html '<p data-id="notice" data-class="hello world">Hello World from @env</p>', source
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_render_with_call_to_set_attributes_and_call_to_set_content
|
22
|
+
source = %q{
|
23
|
+
p id="#{id_helper}" class="hello world" = hello_world
|
24
|
+
}
|
25
|
+
|
26
|
+
assert_html '<p id="notice" class="hello world">Hello World from @env</p>', source
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_render_with_parameterized_call_to_set_attributes_and_call_to_set_content
|
30
|
+
source = %q{
|
31
|
+
p id="#{id_helper}" class="hello world" = hello_world("Hello Ruby!")
|
32
|
+
}
|
33
|
+
|
34
|
+
assert_html '<p id="notice" class="hello world">Hello Ruby!</p>', source
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_render_with_spaced_parameterized_call_to_set_attributes_and_call_to_set_content
|
38
|
+
source = %q{
|
39
|
+
p id="#{id_helper}" class="hello world" = hello_world "Hello Ruby!"
|
40
|
+
}
|
41
|
+
|
42
|
+
assert_html '<p id="notice" class="hello world">Hello Ruby!</p>', source
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_render_with_spaced_parameterized_call_to_set_attributes_and_call_to_set_content_2
|
46
|
+
source = %q{
|
47
|
+
p id="#{id_helper}" class="hello world" = hello_world "Hello Ruby!", :dummy => "value"
|
48
|
+
}
|
49
|
+
|
50
|
+
assert_html '<p id="notice" class="hello world">Hello Ruby!dummy value</p>', source
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_hash_call_in_attribute
|
54
|
+
source = %q{
|
55
|
+
p id="#{hash[:a]}" Test it
|
56
|
+
}
|
57
|
+
|
58
|
+
assert_html '<p id="The letter a">Test it</p>', source
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_method_call_in_attribute_without_quotes
|
62
|
+
source = %q{
|
63
|
+
form action=action_path(:page, :save) method='post'
|
64
|
+
}
|
65
|
+
|
66
|
+
assert_html '<form action="/action-page-save" method="post"></form>', source
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_method_call_in_delimited_attribute_without_quotes
|
70
|
+
source = %q{
|
71
|
+
form(action=action_path(:page, :save) method='post')
|
72
|
+
}
|
73
|
+
|
74
|
+
assert_html '<form action="/action-page-save" method="post"></form>', source
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_method_call_in_delimited_attribute_without_quotes2
|
78
|
+
source = %q{
|
79
|
+
form(method='post' action=action_path(:page, :save))
|
80
|
+
}
|
81
|
+
|
82
|
+
assert_html '<form method="post" action="/action-page-save"></form>', source
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_hash_call_in_attribute_without_quotes
|
86
|
+
source = %q{
|
87
|
+
p id=hash[:a] Test it
|
88
|
+
}
|
89
|
+
|
90
|
+
assert_html '<p id="The letter a">Test it</p>', source
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_hash_call_in_delimited_attribute
|
94
|
+
source = %q{
|
95
|
+
p(id=hash[:a]) Test it
|
96
|
+
}
|
97
|
+
|
98
|
+
assert_html '<p id="The letter a">Test it</p>', source
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_hash_call_in_attribute_with_ruby_evaluation
|
102
|
+
source = %q{
|
103
|
+
p id={hash[:a] + hash[:a]} Test it
|
104
|
+
}
|
105
|
+
|
106
|
+
assert_html '<p id="The letter aThe letter a">Test it</p>', source
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_hash_call_in_delimited_attribute_with_ruby_evaluation
|
110
|
+
source = %q{
|
111
|
+
p(id=(hash[:a] + hash[:a])) Test it
|
112
|
+
}
|
113
|
+
|
114
|
+
assert_html '<p id="The letter aThe letter a">Test it</p>', source
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_hash_call_in_delimited_attribute_with_ruby_evaluation_2
|
118
|
+
source = %q{
|
119
|
+
p[id=(hash[:a] + hash[:a])] Test it
|
120
|
+
}
|
121
|
+
|
122
|
+
assert_html '<p id="The letter aThe letter a">Test it</p>', source
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_hash_call_in_delimited_attribute_with_ruby_evaluation_3
|
126
|
+
source = %q{
|
127
|
+
p(id=[hash[:a] + hash[:a]]) Test it
|
128
|
+
}
|
129
|
+
|
130
|
+
assert_html '<p id="The letter aThe letter a">Test it</p>', source
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_hash_call_in_delimited_attribute_with_ruby_evaluation_4
|
134
|
+
source = %q{
|
135
|
+
p(id=[hash[:a] + hash[:a]] class=[hash[:a]]) Test it
|
136
|
+
}
|
137
|
+
|
138
|
+
assert_html '<p id="The letter aThe letter a" class="The letter a">Test it</p>', source
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_hash_call_in_delimited_attribute_with_ruby_evaluation_5
|
142
|
+
source = %q{
|
143
|
+
p(id=hash[:a] class=[hash[:a]]) Test it
|
144
|
+
}
|
145
|
+
|
146
|
+
assert_html '<p id="The letter a" class="The letter a">Test it</p>', source
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_computation_in_attribute
|
150
|
+
source = %q{
|
151
|
+
p id=(1 + 1)*5 Test it
|
152
|
+
}
|
153
|
+
|
154
|
+
assert_html '<p id="10">Test it</p>', source
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_interpolation_in_text
|
158
|
+
source = %q{
|
159
|
+
p
|
160
|
+
| #{hello_world}
|
161
|
+
p
|
162
|
+
|
|
163
|
+
A message from the compiler: #{hello_world}
|
164
|
+
}
|
165
|
+
|
166
|
+
assert_html '<p>Hello World from @env</p><p>A message from the compiler: Hello World from @env</p>', source
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_interpolation_in_tag
|
170
|
+
source = %q{
|
171
|
+
p #{hello_world}
|
172
|
+
}
|
173
|
+
|
174
|
+
assert_html '<p>Hello World from @env</p>', source
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_number_type_interpolation
|
178
|
+
source = %q{
|
179
|
+
p = output_number
|
180
|
+
}
|
181
|
+
|
182
|
+
assert_html '<p>1337</p>', source
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_ternary_operation_in_attribute
|
186
|
+
source = %q{
|
187
|
+
p id="#{(false ? 'notshown' : 'shown')}" = output_number
|
188
|
+
}
|
189
|
+
|
190
|
+
assert_html '<p id="shown">1337</p>', source
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_class_attribute_merging
|
194
|
+
source = %{
|
195
|
+
.alpha class="beta" Test it
|
196
|
+
}
|
197
|
+
assert_html '<div class="alpha beta">Test it</div>', source
|
198
|
+
end
|
199
|
+
end
|