slim 1.2.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -11,20 +11,36 @@ task :bench, :iterations, :slow do
11
11
  ruby('benchmarks/run-benchmarks.rb')
12
12
  end
13
13
 
14
- Rake::TestTask.new('test') do |t|
15
- t.libs << 'lib' << 'test/slim'
16
- t.test_files = FileList['test/slim/test_*.rb']
17
- t.verbose = true
18
- end
14
+ task 'test' => %w(test:core test:logic_less test:translator)
19
15
 
20
- Rake::TestTask.new('test:rails') do |t|
21
- t.libs << 'lib'
22
- t.test_files = FileList['test/rails/test/test_*.rb']
23
- t.verbose = true
24
- end
16
+ namespace 'test' do
17
+ Rake::TestTask.new('core') do |t|
18
+ t.libs << 'lib' << 'test/slim'
19
+ t.test_files = FileList['test/slim/test_*.rb']
20
+ t.verbose = true
21
+ end
22
+
23
+ Rake::TestTask.new('logic_less') do |t|
24
+ t.libs << 'lib' << 'test/slim'
25
+ t.test_files = FileList['test/slim/logic_less/test_*.rb']
26
+ t.verbose = true
27
+ end
28
+
29
+ Rake::TestTask.new('translator') do |t|
30
+ t.libs << 'lib' << 'test/slim'
31
+ t.test_files = FileList['test/slim/translator/test_*.rb']
32
+ t.verbose = true
33
+ end
25
34
 
26
- task 'test:ci' do |t|
27
- Rake::Task[ENV['TASK']].execute
35
+ Rake::TestTask.new('rails') do |t|
36
+ t.libs << 'lib'
37
+ t.test_files = FileList['test/rails/test/test_*.rb']
38
+ t.verbose = true
39
+ end
40
+
41
+ task 'ci' do |t|
42
+ Rake::Task[ENV['TASK']].execute
43
+ end
28
44
  end
29
45
 
30
46
  begin
@@ -3,10 +3,10 @@
3
3
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'), File.dirname(__FILE__))
4
4
 
5
5
  require 'slim'
6
- require 'complex_view'
6
+ require 'context'
7
7
 
8
8
  content = File.read(File.dirname(__FILE__) + '/view.slim')
9
9
  slim = Slim::Template.new { content }
10
- view = ComplexView.new
10
+ context = Context.new
11
11
 
12
- 10000.times { slim.render(view) }
12
+ 10000.times { slim.render(context) }
@@ -6,6 +6,7 @@ require 'slim'
6
6
  require 'context'
7
7
 
8
8
  require 'benchmark'
9
+ require 'tilt'
9
10
  require 'erubis'
10
11
  require 'erb'
11
12
  require 'haml'
@@ -15,63 +16,101 @@ class SlimBenchmarks
15
16
  @iterations = (iterations || 1000).to_i
16
17
  @benches = []
17
18
 
18
- tpl_erb = File.read(File.dirname(__FILE__) + '/view.erb')
19
- tpl_haml = File.read(File.dirname(__FILE__) + '/view.haml')
20
- tpl_slim = File.read(File.dirname(__FILE__) + '/view.slim')
19
+ @erb_code = File.read(File.dirname(__FILE__) + '/view.erb')
20
+ @haml_code = File.read(File.dirname(__FILE__) + '/view.haml')
21
+ @slim_code = File.read(File.dirname(__FILE__) + '/view.slim')
21
22
 
22
- context = Context.new
23
- context_binding = context.instance_eval { binding }
23
+ init_compiled_benches
24
+ init_tilt_benches
25
+ init_cached_benches
26
+ init_parsing_benches if slow
27
+ end
24
28
 
25
- erb = ERB.new(tpl_erb)
26
- erubis = Erubis::Eruby.new(tpl_erb)
27
- fast_erubis = Erubis::FastEruby.new(tpl_erb)
28
- haml = Haml::Engine.new(tpl_haml, :format => :html5)
29
- haml_ugly = Haml::Engine.new(tpl_haml, :format => :html5, :ugly => true)
30
- slim = Slim::Template.new { tpl_slim }
29
+ def init_compiled_benches
30
+ erb = ERB.new(@erb_code)
31
+ erubis = Erubis::Eruby.new(@erb_code)
32
+ fast_erubis = Erubis::FastEruby.new(@erb_code)
33
+ haml_pretty = Haml::Engine.new(@haml_code, :format => :html5)
34
+ haml_ugly = Haml::Engine.new(@haml_code, :format => :html5, :ugly => true)
31
35
 
32
- tilt_erb = Tilt::ERBTemplate.new { tpl_erb }
33
- tilt_erubis = Tilt::ErubisTemplate.new { tpl_erb }
34
- tilt_haml = Tilt::HamlTemplate.new(:format => :html5){ tpl_haml }
35
- tilt_haml_ugly = Tilt::HamlTemplate.new(:format => :html5, :ugly => true){ tpl_haml }
36
- tilt_slim = Slim::Template.new { tpl_slim }
36
+ context = Context.new
37
37
 
38
- haml.def_method(context, :run_haml)
38
+ haml_pretty.def_method(context, :run_haml_pretty)
39
39
  haml_ugly.def_method(context, :run_haml_ugly)
40
40
  context.instance_eval %{
41
41
  def run_erb; #{erb.src}; end
42
42
  def run_erubis; #{erubis.src}; end
43
+ def run_temple_erb; #{Temple::ERB::Engine.new.call @erb_code}; end
43
44
  def run_fast_erubis; #{fast_erubis.src}; end
44
- def run_slim; #{slim.precompiled_template}; end
45
+ def run_slim_pretty; #{Slim::Engine.new(:pretty => true).call @slim_code}; end
46
+ def run_slim_ugly; #{Slim::Engine.new.call @slim_code}; end
45
47
  }
46
48
 
47
- if slow
48
- bench('(1) erb') { ERB.new(tpl_erb).result(context_binding) }
49
- bench('(1) erubis') { Erubis::Eruby.new(tpl_erb).result(context_binding) }
50
- bench('(1) fast erubis') { Erubis::Eruby.new(tpl_erb).result(context_binding) }
51
- bench('(1) slim') { Slim::Template.new { tpl_slim }.render(context) }
52
- bench('(1) haml') { Haml::Engine.new(tpl_haml, :format => :html5).render(context) }
53
- bench('(1) haml ugly') { Haml::Engine.new(tpl_haml, :format => :html5, :ugly => true).render(context) }
54
- end
49
+ bench('(1) erb') { context.run_erb }
50
+ bench('(1) erubis') { context.run_erubis }
51
+ bench('(1) fast erubis') { context.run_fast_erubis }
52
+ bench('(1) temple erb') { context.run_temple_erb }
53
+ bench('(1) slim pretty') { context.run_slim_pretty }
54
+ bench('(1) slim ugly') { context.run_slim_ugly }
55
+ bench('(1) haml pretty') { context.run_haml_pretty }
56
+ bench('(1) haml ugly') { context.run_haml_ugly }
57
+ end
55
58
 
56
- bench('(2) erb') { erb.result(context_binding) }
57
- bench('(2) erubis') { erubis.result(context_binding) }
58
- bench('(2) fast erubis') { fast_erubis.result(context_binding) }
59
- bench('(2) slim') { slim.render(context) }
60
- bench('(2) haml') { haml.render(context) }
61
- bench('(2) haml ugly') { haml_ugly.render(context) }
62
-
63
- bench('(3) erb') { context.run_erb }
64
- bench('(3) erubis') { context.run_erubis }
65
- bench('(3) fast erubis') { context.run_fast_erubis }
66
- bench('(3) slim') { context.run_slim }
67
- bench('(3) haml') { context.run_haml }
68
- bench('(3) haml ugly') { context.run_haml_ugly }
69
-
70
- bench('(4) erb') { tilt_erb.render(context) }
71
- bench('(4) erubis') { tilt_erubis.render(context) }
72
- bench('(4) slim') { tilt_slim.render(context) }
73
- bench('(4) haml') { tilt_haml.render(context) }
74
- bench('(4) haml ugly') { tilt_haml_ugly.render(context) }
59
+ def init_tilt_benches
60
+ tilt_erb = Tilt::ERBTemplate.new { @erb_code }
61
+ tilt_erubis = Tilt::ErubisTemplate.new { @erb_code }
62
+ tilt_temple_erb = Temple::ERB::Template.new { @erb_code }
63
+ tilt_haml_pretty= Tilt::HamlTemplate.new(:format => :html5){ @haml_code }
64
+ tilt_haml_ugly = Tilt::HamlTemplate.new(:format => :html5, :ugly => true){ @haml_code }
65
+ tilt_slim_pretty= Slim::Template.new(:pretty => true) { @slim_code }
66
+ tilt_slim_ugly = Slim::Template.new { @slim_code }
67
+
68
+ context = Context.new
69
+
70
+ bench('(2) erb') { tilt_erb.render(context) }
71
+ bench('(2) erubis') { tilt_erubis.render(context) }
72
+ bench('(2) temple erb') { tilt_temple_erb.render(context) }
73
+ bench('(2) slim pretty') { tilt_slim_pretty.render(context) }
74
+ bench('(2) slim ugly') { tilt_slim_ugly.render(context) }
75
+ bench('(2) haml pretty') { tilt_haml_pretty.render(context) }
76
+ bench('(2) haml ugly') { tilt_haml_ugly.render(context) }
77
+ end
78
+
79
+ def init_cached_benches
80
+ context = Context.new
81
+ context_binding = context.instance_eval { binding }
82
+
83
+ erb = ERB.new(@erb_code)
84
+ erubis = Erubis::Eruby.new(@erb_code)
85
+ fast_erubis = Erubis::FastEruby.new(@erb_code)
86
+ temple_erb = Temple::ERB::Template.new { @erb_code }
87
+ haml_pretty = Haml::Engine.new(@haml_code, :format => :html5)
88
+ haml_ugly = Haml::Engine.new(@haml_code, :format => :html5, :ugly => true)
89
+ slim_pretty = Slim::Template.new(:pretty => true) { @slim_code }
90
+ slim_ugly = Slim::Template.new { @slim_code }
91
+
92
+ bench('(3) erb') { erb.result(context_binding) }
93
+ bench('(3) erubis') { erubis.result(context_binding) }
94
+ bench('(3) fast erubis') { fast_erubis.result(context_binding) }
95
+ bench('(3) temple erb') { temple_erb.render(context) }
96
+ bench('(3) slim pretty') { slim_pretty.render(context) }
97
+ bench('(3) slim ugly') { slim_ugly.render(context) }
98
+ bench('(3) haml pretty') { haml_pretty.render(context) }
99
+ bench('(3) haml ugly') { haml_ugly.render(context) }
100
+ end
101
+
102
+ def init_parsing_benches
103
+ context = Context.new
104
+ context_binding = context.instance_eval { binding }
105
+
106
+ bench('(4) erb') { ERB.new(@erb_code).result(context_binding) }
107
+ bench('(4) erubis') { Erubis::Eruby.new(@erb_code).result(context_binding) }
108
+ bench('(4) fast erubis') { Erubis::FastEruby.new(@erb_code).result(context_binding) }
109
+ bench('(4) temple erb') { Temple::ERB::Template.new { @erb_code }.render(context) }
110
+ bench('(4) slim pretty') { Slim::Template.new(:pretty => true) { @slim_code }.render(context) }
111
+ bench('(4) slim ugly') { Slim::Template.new { @slim_code }.render(context) }
112
+ bench('(4) haml pretty') { Haml::Engine.new(@haml_code, :format => :html5).render(context) }
113
+ bench('(4) haml ugly') { Haml::Engine.new(@haml_code, :format => :html5, :ugly => true).render(context) }
75
114
  end
76
115
 
77
116
  def run
@@ -84,23 +123,26 @@ class SlimBenchmarks
84
123
  end
85
124
  end
86
125
  puts "
87
- 1. Uncached benchmark. Template is parsed every time.
88
- Activate this benchmark with 'rake bench slow=1'.
89
-
90
- 2. Cached benchmark. Template is parsed before the benchmark.
91
- The ruby code generated by the template engine might be evaluated every time.
92
- This benchmark uses the standard API of the template engine.
93
-
94
- 3. Compiled benchmark. Template is parsed before the benchmark and
95
- generated ruby code is compiled into a method.
96
- This is the fastest evaluation strategy because it benchmarks
97
- pure execution speed of the generated ruby code.
98
-
99
- 4. Compiled Tilt benchmark. Template is compiled with Tilt, which gives a more
100
- accurate result of the performance in production mode in frameworks like
101
- Sinatra, Ramaze and Camping. (Rails still uses its own template
102
- compilation.)
103
-
126
+ (1) Compiled benchmark. Template is parsed before the benchmark and
127
+ generated ruby code is compiled into a method.
128
+ This is the fastest evaluation strategy because it benchmarks
129
+ pure execution speed of the generated ruby code.
130
+
131
+ (2) Compiled Tilt benchmark. Template is compiled with Tilt, which gives a more
132
+ accurate result of the performance in production mode in frameworks like
133
+ Sinatra, Ramaze and Camping. (Rails still uses its own template
134
+ compilation.)
135
+
136
+ (3) Cached benchmark. Template is parsed before the benchmark.
137
+ The ruby code generated by the template engine might be evaluated every time.
138
+ This benchmark uses the standard API of the template engine.
139
+
140
+ (4) Parsing benchmark. Template is parsed every time.
141
+ This is not the recommended way to use the template engine
142
+ and Slim is not optimized for it. Activate this benchmark with 'rake bench slow=1'.
143
+
144
+ Temple ERB is the ERB implementation using the Temple framework. It shows the
145
+ overhead added by the Temple framework compared to ERB.
104
146
  "
105
147
  end
106
148
 
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'), File.dirname(__FILE__))
4
+
5
+ require 'slim'
6
+ require 'context'
7
+ require 'diffbench'
8
+
9
+ content = File.read(File.dirname(__FILE__) + '/view.slim')
10
+ engine = Slim::Engine.new
11
+ template = Slim::Template.new { content }
12
+ context = Context.new
13
+
14
+ DiffBench.bm do
15
+ report("Parse") do
16
+ 2000.times { engine.call(content) }
17
+ end
18
+ report("Render") do
19
+ 100000.times { template.render(context) }
20
+ end
21
+ end
data/bin/slimrb CHANGED
@@ -3,5 +3,4 @@
3
3
  $:.unshift File.dirname(__FILE__) + '/../lib'
4
4
  require 'slim/command'
5
5
 
6
- cmd = Slim::Command.new(ARGV)
7
- cmd.run
6
+ Slim::Command.new(ARGV).run
@@ -6,9 +6,7 @@ require 'slim/filter'
6
6
  require 'slim/end_inserter'
7
7
  require 'slim/embedded_engine'
8
8
  require 'slim/interpolation'
9
- require 'slim/sections'
10
9
  require 'slim/compiler'
11
10
  require 'slim/engine'
12
11
  require 'slim/template'
13
12
  require 'slim/version'
14
- require 'slim/wrapper'
@@ -1,4 +1,5 @@
1
- require 'slim'
1
+ require 'slim/logic_less'
2
+ require 'slim/translator'
2
3
  require 'optparse'
3
4
 
4
5
  module Slim
@@ -44,8 +45,12 @@ module Slim
44
45
  @options[:rails] = true
45
46
  end
46
47
 
47
- opts.on('-S', '--sections', :NONE, 'Logic-less sections mode') do
48
- @options[:sections] = true
48
+ opts.on('-t', '--translator', :NONE, 'Enable translator plugin') do
49
+ @options[:translator] = true
50
+ end
51
+
52
+ opts.on('-l', '--logic-less', :NONE, 'Enable logic-less plugin') do
53
+ @options[:logic_less] = true
49
54
  end
50
55
 
51
56
  opts.on('-p', '--pretty', :NONE, 'Produce pretty html') do
@@ -85,15 +90,17 @@ module Slim
85
90
  if @options[:compile]
86
91
  @options[:output].puts(Slim::Engine.new(:file => @options[:file],
87
92
  :pretty => @options[:pretty],
88
- :sections => @options[:sections],
93
+ :logic_less => @options[:logic_less],
89
94
  :disable_capture => @options[:rails],
95
+ :tr => @options[:translator],
90
96
  :generator => @options[:rails] ?
91
97
  Temple::Generators::RailsOutputBuffer :
92
98
  Temple::Generators::ArrayBuffer).call(@options[:input].read))
93
99
  else
94
100
  @options[:output].puts(Slim::Template.new(@options[:file],
95
101
  :pretty => @options[:pretty],
96
- :sections => @options[:sections]) { @options[:input].read }.render)
102
+ :tr => @options[:translator],
103
+ :logic_less => @options[:logic_less]) { @options[:input].read }.render)
97
104
  end
98
105
  end
99
106
  end
@@ -13,7 +13,7 @@ module Slim
13
13
 
14
14
  # Handle control expression `[:slim, :control, code, content]`
15
15
  #
16
- # @param [String] ruby code
16
+ # @param [String] code Ruby code
17
17
  # @param [Array] content Temple expression
18
18
  # @return [Array] Compiled temple expression
19
19
  def on_slim_control(code, content)
@@ -22,19 +22,6 @@ module Slim
22
22
  compile(content)]
23
23
  end
24
24
 
25
- # Handle conditional comment expression
26
- # `[:slim, :conditional_comment, conditional, content]`
27
- #
28
- # @param [Array] content Temple expression
29
- # @return [Array] Compiled temple expression
30
- def on_slim_condcomment(condition, content)
31
- [:html, :comment,
32
- [:multi,
33
- [:static, "[#{condition}]>"],
34
- compile(content),
35
- [:static, '<![endif]']]]
36
- end
37
-
38
25
  # Handle output expression `[:slim, :output, escape, code, content]`
39
26
  #
40
27
  # @param [Boolean] escape Escape html
@@ -67,6 +54,14 @@ module Slim
67
54
  end
68
55
  end
69
56
 
57
+ # Handle text expression `[:slim, :text, content]`
58
+ #
59
+ # @param [Array] content Temple expression
60
+ # @return [Array] Compiled temple expression
61
+ def on_slim_text(content)
62
+ compile(content)
63
+ end
64
+
70
65
  # Handle tag expression `[:slim, :tag, name, attrs, content]`
71
66
  #
72
67
  # @param [String] name Tag name
@@ -103,7 +98,7 @@ module Slim
103
98
 
104
99
  # Handle attributes expression `[:slim, :attrs, *attrs]`
105
100
  #
106
- # @param [Array] *attrs Array of temple expressions
101
+ # @param [Array] attrs Array of temple expressions
107
102
  # @return [Array] Compiled temple expression
108
103
  def on_slim_attrs(*attrs)
109
104
  if attrs.any? {|attr| attr[1] == :splat}
@@ -1,6 +1,6 @@
1
1
  module Slim
2
2
  # @api private
3
- class CollectText < Filter
3
+ class TextCollector < Filter
4
4
  def call(exp)
5
5
  @collected = ''
6
6
  super(exp)
@@ -14,7 +14,7 @@ module Slim
14
14
  end
15
15
 
16
16
  # @api private
17
- class CollectNewlines < Filter
17
+ class NewlineCollector < Filter
18
18
  def call(exp)
19
19
  @collected = [:multi]
20
20
  super(exp)
@@ -28,7 +28,7 @@ module Slim
28
28
  end
29
29
 
30
30
  # @api private
31
- class ProtectOutput < Filter
31
+ class OutputProtector < Filter
32
32
  def call(exp)
33
33
  @protect = []
34
34
  @collected = ''
@@ -87,18 +87,26 @@ module Slim
87
87
  engine.new(Temple::ImmutableHash.new(local_options, filtered_options)).on_slim_embedded(name, body)
88
88
  end
89
89
 
90
+ protected
91
+
92
+ def collect_text(body)
93
+ @text_collector ||= TextCollector.new
94
+ @text_collector.call(body)
95
+ end
96
+
90
97
  # Basic tilt engine
91
98
  class TiltEngine < EmbeddedEngine
92
99
  def on_slim_embedded(engine, body)
93
100
  tilt_engine = Tilt[engine] || raise("Tilt engine #{engine} is not available.")
94
101
  tilt_options = options[engine.to_sym] || {}
95
- [:multi, tilt_render(tilt_engine, tilt_options, collect_text(body)), CollectNewlines.new.call(body)]
102
+ [:multi, tilt_render(tilt_engine, tilt_options, collect_text(body)), collect_newlines(body)]
96
103
  end
97
104
 
98
105
  protected
99
106
 
100
- def collect_text(body)
101
- CollectText.new.call(body)
107
+ def collect_newlines(body)
108
+ @newline_collector ||= NewlineCollector.new
109
+ @newline_collector.call(body)
102
110
  end
103
111
  end
104
112
 
@@ -135,25 +143,35 @@ module Slim
135
143
 
136
144
  # Static template with interpolated ruby code
137
145
  class InterpolateTiltEngine < TiltEngine
138
- def initialize(opts = {})
139
- super
140
- @protect = ProtectOutput.new
141
- end
142
-
143
146
  def collect_text(body)
144
- text = Interpolation.new.call(body)
145
- @protect.call(text)
147
+ output_protector.call(interpolation.call(body))
146
148
  end
147
149
 
148
150
  def tilt_render(tilt_engine, tilt_options, text)
149
- @protect.unprotect(tilt_engine.new(tilt_options) { text }.render)
151
+ output_protector.unprotect(tilt_engine.new(tilt_options) { text }.render)
152
+ end
153
+
154
+ private
155
+
156
+ def interpolation
157
+ @interpolation ||= Interpolation.new
158
+ end
159
+
160
+ def output_protector
161
+ @output_protector ||= OutputProtector.new
150
162
  end
151
163
  end
152
164
 
153
165
  # ERB engine (uses the Temple ERB implementation)
154
166
  class ERBEngine < EmbeddedEngine
155
167
  def on_slim_embedded(engine, body)
156
- [:multi, [:newline], Temple::ERB::Parser.new.call(CollectText.new.call(body))]
168
+ [:multi, [:newline], erb_parser.call(collect_text(body))]
169
+ end
170
+
171
+ protected
172
+
173
+ def erb_parser
174
+ @erb_parser ||= Temple::ERB::Parser.new
157
175
  end
158
176
  end
159
177
 
@@ -169,7 +187,7 @@ module Slim
169
187
  # Embeds ruby code
170
188
  class RubyEngine < EmbeddedEngine
171
189
  def on_slim_embedded(engine, body)
172
- [:multi, [:newline], [:code, CollectText.new.call(body)]]
190
+ [:multi, [:newline], [:code, collect_text(body)]]
173
191
  end
174
192
  end
175
193