slim 0.9.2 → 0.9.3

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/extra/test.slim ADDED
@@ -0,0 +1,49 @@
1
+ doctype html
2
+ html
3
+ head
4
+ title Slim Test
5
+ meta name="keywords" content="slim, syntax"
6
+
7
+ javascript:
8
+ $(function() {
9
+ alert('Hello World');
10
+ });
11
+
12
+ haml:
13
+ #someid.someclass{:this => 'test'} Content in haml
14
+
15
+ erb:
16
+ <%= some_method(@request) %>
17
+
18
+ body
19
+ / comment block
20
+ with multiple lines
21
+ This is another line
22
+ h1 = @page_title
23
+ p#notice.message
24
+ | Welcome to the the syntax test.
25
+ This file is to exercise the various markup.
26
+ This is another line
27
+ - unless @users.empty?
28
+ table
29
+ - for user in users do
30
+ tr
31
+ td.user id=some_ruby('ere', @rme) data-test="some text #{with @ruby}" = @post.name
32
+ - else
33
+ p There are no users.
34
+
35
+ / Single comment line
36
+ #content Hello #{@user.name}! Welcome to the test page!
37
+ Try out Slim!
38
+
39
+ = function_with_many_parameters(:a, @variable, :option => 1)
40
+
41
+ p.text
42
+ ' Another text block
43
+ with multiple lines
44
+
45
+ = link_to('Test', @site)
46
+
47
+ .text#footer
48
+ ' Footer text block
49
+ with multiple lines
data/lib/slim/command.rb CHANGED
@@ -52,10 +52,6 @@ module Slim
52
52
  @options[:pretty] = true
53
53
  end
54
54
 
55
- opts.on('-d', '--debug', :NONE, 'Debugging output') do
56
- @options[:debug] = true
57
- end
58
-
59
55
  opts.on_tail('-h', '--help', 'Show this message') do
60
56
  puts opts
61
57
  exit
@@ -91,14 +87,12 @@ module Slim
91
87
  :pretty => @options[:pretty],
92
88
  :sections => @options[:sections],
93
89
  :disable_capture => @options[:rails],
94
- :debug => @options[:debug],
95
90
  :generator => @options[:rails] ?
96
91
  Temple::Generators::RailsOutputBuffer :
97
92
  Temple::Generators::ArrayBuffer).call(@options[:input].read))
98
93
  else
99
94
  @options[:output].puts(Slim::Template.new(@options[:file],
100
95
  :pretty => @options[:pretty],
101
- :debug => @options[:debug],
102
96
  :sections => @options[:sections]) { @options[:input].read }.render)
103
97
  end
104
98
  end
data/lib/slim/compiler.rb CHANGED
@@ -2,7 +2,7 @@ module Slim
2
2
  # Compiles Slim expressions into Temple::HTML expressions.
3
3
  # @api private
4
4
  class Compiler < Filter
5
- set_default_options :auto_escape => true
5
+ set_default_options :bool_attrs => %w(selected)
6
6
 
7
7
  # Handle control expression `[:slim, :control, code, content]`
8
8
  #
@@ -11,16 +11,17 @@ module Slim
11
11
  # @return [Array] Compiled temple expression
12
12
  def on_slim_control(code, content)
13
13
  [:multi,
14
- [:block, code],
14
+ [:code, code],
15
15
  compile(content)]
16
16
  end
17
17
 
18
- # Handle comment expression `[:slim, :comment, content]`
18
+ # Handle conditional comment expression
19
+ # `[:slim, :conditional_comment, conditional, content]`
19
20
  #
20
21
  # @param [Array] content Temple expression
21
22
  # @return [Array] Compiled temple expression
22
- def on_slim_comment(content)
23
- [:html, :comment, compile(content)]
23
+ def on_slim_condcomment(condition, content)
24
+ [:multi, [:static, "<!--[#{condition}]>"], compile(content), [:static, '<![endif]-->']]
24
25
  end
25
26
 
26
27
  # Handle output expression `[:slim, :output, escape, code, content]`
@@ -31,42 +32,28 @@ module Slim
31
32
  # @return [Array] Compiled temple expression
32
33
  def on_slim_output(escape, code, content)
33
34
  if empty_exp?(content)
34
- [:multi, [:escape, escape && options[:auto_escape], [:dynamic, code]], content]
35
+ [:multi, [:escape, escape, [:dynamic, code]], content]
35
36
  else
36
- on_slim_output_block(escape, code, content)
37
- end
38
- end
39
-
40
- # Handle output expression `[:slim, :output, escape, code, content]`
41
- # if content is not empty.
42
- #
43
- # @param [Boolean] escape Escape html
44
- # @param [String] code Ruby code
45
- # @param [Array] content Temple expression
46
- # @return [Array] Compiled temple expression
47
- def on_slim_output_block(escape, code, content)
48
- tmp = tmp_var(:output)
49
-
50
- [:multi,
51
- # Capture the result of the code in a variable. We can't do
52
- # `[:dynamic, code]` because it's probably not a complete
53
- # expression (which is a requirement for Temple).
54
- [:block, "#{tmp} = #{code}"],
37
+ tmp = unique_name
55
38
 
56
- # Capture the content of a block in a separate buffer. This means
57
- # that `yield` will not output the content to the current buffer,
58
- # but rather return the output.
59
- #
60
- # The capturing can be disabled with the option :disable_capture.
61
- # Output code in the block writes directly to the output buffer then.
62
- # Rails handles this by replacing the output buffer for helpers (with_output_buffer - braindead!).
63
- options[:disable_capture] ? compile(content) : [:capture, tmp_var(:output), compile(content)],
39
+ [:multi,
40
+ # Capture the result of the code in a variable. We can't do
41
+ # `[:dynamic, code]` because it's probably not a complete
42
+ # expression (which is a requirement for Temple).
43
+ [:block, "#{tmp} = #{code}",
64
44
 
65
- # Close the block.
66
- [:block, 'end'],
45
+ # Capture the content of a block in a separate buffer. This means
46
+ # that `yield` will not output the content to the current buffer,
47
+ # but rather return the output.
48
+ #
49
+ # The capturing can be disabled with the option :disable_capture.
50
+ # Output code in the block writes directly to the output buffer then.
51
+ # Rails handles this by replacing the output buffer for helpers.
52
+ options[:disable_capture] ? compile(content) : [:capture, unique_name, compile(content)]],
67
53
 
68
- # Output the content.
69
- on_slim_output(escape, tmp, [:multi])]
54
+ # Output the content.
55
+ [:escape, escape, [:dynamic, tmp]]]
56
+ end
70
57
  end
71
58
 
72
59
  # Handle directive expression `[:slim, :directive, type, args]`
@@ -82,22 +69,24 @@ module Slim
82
69
  end
83
70
  end
84
71
 
85
- # Handle tag expression `[:slim, :tag, name, attrs, closed, content]`
86
- #
87
- # @param [String] name Tag name
88
- # @param [Array] attrs Attributes
89
- # @param [Array] content Temple expression
90
- # @return [Array] Compiled temple expression
91
- def on_slim_tag(name, attrs, closed, content)
92
- [:html, :tag, name, compile(attrs), closed, compile(content)]
93
- end
94
-
95
- # Handle tag attributes expression `[:slim, :attrs, *attrs]`
72
+ # Handle attribute expression `[:slim, :attr, escape, code]`
96
73
  #
97
- # @param [Array] attrs Attributes
74
+ # @param [Boolean] escape Escape html
75
+ # @param [String] code Ruby code
98
76
  # @return [Array] Compiled temple expression
99
- def on_slim_attrs(*attrs)
100
- [:html, :staticattrs, *attrs.map {|k, v| [k.to_s, compile(v)] }]
77
+ def on_slim_attr(name, escape, code)
78
+ if options[:bool_attrs].include?(name)
79
+ escape = false
80
+ value = [:dynamic, "(#{code}) ? #{name.inspect} : nil"]
81
+ elsif delimiter = options[:attr_delimiter][name]
82
+ tmp = unique_name
83
+ value = [:multi,
84
+ [:code, "#{tmp} = #{code}"],
85
+ [:dynamic, "#{tmp}.respond_to?(:join) ? #{tmp}.flatten.compact.join(#{delimiter.inspect}) : #{tmp}"]]
86
+ else
87
+ value = [:dynamic, code]
88
+ end
89
+ [:html, :attr, name, [:escape, escape, value]]
101
90
  end
102
91
  end
103
92
  end
@@ -7,96 +7,124 @@ module Slim
7
7
  class << self
8
8
  attr_reader :engines
9
9
 
10
+ # Register embedded engine
11
+ #
12
+ # @param [String] name Name of the engine
13
+ # @param [Class] klass Engine class
14
+ # @param option_filter List of options to pass to engine.
15
+ # Last argument can be default option hash.
10
16
  def register(name, klass, *option_filter)
11
17
  local_options = Hash === option_filter.last ? option_filter.pop : nil
12
18
  @engines[name.to_s] = [klass, option_filter, local_options]
13
19
  end
14
20
  end
15
21
 
22
+ def on_slim_embedded(name, body)
23
+ new_engine(name).on_slim_embedded(name, body)
24
+ end
25
+
26
+ protected
27
+
16
28
  def new_engine(name)
17
29
  name = name.to_s
18
30
  raise "Embedded engine #{name} is disabled" if (options[:enable_engines] && !options[:enable_engines].include?(name)) ||
19
31
  (options[:disable_engines] && options[:disable_engines].include?(name))
20
32
  engine, option_filter, local_options = self.class.engines[name] || raise("Embedded engine #{name} not found")
21
33
  filtered_options = Hash[*option_filter.select {|k| options.include?(k) }.map {|k| [k, options[k]] }.flatten]
22
- engine.new(Temple::Utils::ImmutableHash.new(local_options, filtered_options))
34
+ engine.new(Temple::ImmutableHash.new(local_options, filtered_options))
23
35
  end
24
36
 
25
- def on_slim_embedded(name, *body)
26
- new_engine(name).on_slim_embedded(name, *body)
37
+ def collect_text(body)
38
+ body[1..-1].inject('') do |text, exp|
39
+ exp[0] == :slim && exp[1] == :interpolate ? (text << exp[2]) : text
40
+ end
27
41
  end
28
42
 
29
- def collect_text(body)
30
- body.inject('') do |text, exp|
31
- text << exp[2] if exp[0] == :slim && exp[1] == :text
32
- text
43
+ def collect_newlines(body)
44
+ body[1..-1].inject([:multi]) do |multi, exp|
45
+ exp[0] == :newline ? (multi << exp) : multi
33
46
  end
34
47
  end
35
48
 
49
+ # Basic tilt engine
36
50
  class TiltEngine < EmbeddedEngine
37
- def on_slim_embedded(engine, *body)
38
- text = collect_text(body)
51
+ def on_slim_embedded(engine, body)
39
52
  engine = Tilt[engine] || raise("Tilt engine #{engine} is not available.")
40
- tilt_render(engine, text)
53
+ [:multi, render(engine, collect_text(body)), collect_newlines(body)]
41
54
  end
55
+ end
56
+
57
+ # Tilt-based static template (evaluated at compile-time)
58
+ class StaticTiltEngine < TiltEngine
59
+ protected
42
60
 
43
- def tilt_render(engine, text)
44
- # Static template
61
+ def render(engine, text)
45
62
  [:static, engine.new { text }.render]
46
63
  end
47
64
  end
48
65
 
49
- class SassEngine < TiltEngine
50
- def tilt_render(engine, text)
51
- text = engine.new(:style => (options[:pretty] ? :expanded : :compressed)) { text }.render
66
+ # Sass engine which supports :pretty option
67
+ class SassEngine < StaticTiltEngine
68
+ protected
69
+
70
+ def render(engine, text)
71
+ text = engine.new(:style => (options[:pretty] ? :expanded : :compressed), :cache => false) { text }.render
52
72
  text.chomp!
53
73
  [:static, options[:pretty] ? "\n#{text}\n" : text]
54
74
  end
55
75
  end
56
76
 
57
- class DynamicTiltEngine < TiltEngine
77
+ # Tilt-based engine which is fully dynamically evaluated during runtime (Slow and uncached)
78
+ class DynamicTiltEngine < StaticTiltEngine
79
+ protected
80
+
58
81
  # Code to collect local variables
59
82
  COLLECT_LOCALS = %q{eval('{' + local_variables.select {|v| v[0] != ?_ }.map {|v| ":#{v}=>#{v}" }.join(',') + '}')}
60
83
 
61
- def tilt_render(engine, text)
62
- # Fully dynamic evaluation of the template during runtime (Slow and uncached)
84
+ def render(engine, text)
63
85
  [:dynamic, "#{engine.name}.new { #{text.inspect} }.render(self, #{COLLECT_LOCALS})"]
64
86
  end
65
87
  end
66
88
 
67
- class PrecompiledTiltEngine < TiltEngine
68
- def tilt_render(engine, text)
69
- # Wrap precompiled code in proc, local variables from out the proc are accessible
89
+ # Tilt-based engine which is precompiled
90
+ class PrecompiledTiltEngine < StaticTiltEngine
91
+ protected
92
+
93
+ def render(engine, text)
70
94
  # WARNING: This is a bit of a hack. Tilt::Engine#precompiled is protected
71
- precompiled = engine.new { text }.send(:precompiled, {}).first
72
- [:dynamic, "proc { #{precompiled} }.call"]
95
+ [:dynamic, engine.new { text }.send(:precompiled, {}).first]
73
96
  end
74
97
  end
75
98
 
76
- class InterpolateTiltEngine < TiltEngine
77
- def tilt_render(engine, text)
78
- # Static template with interpolated ruby code
79
- [:slim, :text, engine.new { text }.render]
99
+ # Static template with interpolated ruby code
100
+ class InterpolateTiltEngine < StaticTiltEngine
101
+ protected
102
+
103
+ def render(engine, text)
104
+ [:slim, :interpolate, engine.new { text }.render]
80
105
  end
81
106
  end
82
107
 
108
+ # ERB engine (uses the Temple ERB implementation)
83
109
  class ERBEngine < EmbeddedEngine
84
- def on_slim_embedded(engine, *body)
85
- text = collect_text(body)
86
- Temple::ERB::Parser.new(:auto_escape => true).call(text)
110
+ def on_slim_embedded(engine, body)
111
+ Temple::ERB::Parser.new.call(collect_text(body))
87
112
  end
88
113
  end
89
114
 
115
+ # Tag wrapper engine
116
+ # Generates a html tag and wraps another engine (specified via :engine option)
90
117
  class TagEngine < EmbeddedEngine
91
- def on_slim_embedded(engine, *body)
92
- content = options[:engine] ? options[:engine].new(options).on_slim_embedded(engine, *body) : [:multi, *body]
93
- [:slim, :tag, options[:tag], [:slim, :attrs, *options[:attributes].map {|k, v| [k, [:static, v]] }], false, content]
118
+ def on_slim_embedded(engine, body)
119
+ content = options[:engine] ? options[:engine].new(options).on_slim_embedded(engine, body) : [:multi, body]
120
+ [:html, :tag, options[:tag], [:html, :attrs, *options[:attributes].map {|k, v| [:html, :attr, k, [:static, v]] }], content]
94
121
  end
95
122
  end
96
123
 
124
+ # Embeds ruby code
97
125
  class RubyEngine < EmbeddedEngine
98
- def on_slim_embedded(engine, *body)
99
- [:block, collect_text(body)]
126
+ def on_slim_embedded(engine, body)
127
+ [:code, "\n" + collect_text(body)]
100
128
  end
101
129
  end
102
130
 
@@ -107,10 +135,10 @@ module Slim
107
135
  register :creole, InterpolateTiltEngine
108
136
 
109
137
  # These engines are executed at compile time
110
- register :coffee, TagEngine, :tag => 'script', :attributes => { :type => 'text/javascript' }, :engine => TiltEngine
111
- register :less, TagEngine, :tag => 'style', :attributes => { :type => 'text/css' }, :engine => TiltEngine
112
- register :sass, TagEngine, :pretty, :tag => 'style', :attributes => { :type => 'text/css' }, :engine => SassEngine
113
- register :scss, TagEngine, :pretty, :tag => 'style', :attributes => { :type => 'text/css' }, :engine => SassEngine
138
+ register :coffee, TagEngine, :tag => :script, :attributes => { :type => 'text/javascript' }, :engine => StaticTiltEngine
139
+ register :less, TagEngine, :tag => :style, :attributes => { :type => 'text/css' }, :engine => StaticTiltEngine
140
+ register :sass, TagEngine, :pretty, :tag => :style, :attributes => { :type => 'text/css' }, :engine => SassEngine
141
+ register :scss, TagEngine, :pretty, :tag => :style, :attributes => { :type => 'text/css' }, :engine => SassEngine
114
142
 
115
143
  # These engines are precompiled, code is embedded
116
144
  register :erb, ERBEngine
@@ -124,8 +152,8 @@ module Slim
124
152
  register :markaby, DynamicTiltEngine
125
153
 
126
154
  # Embedded javascript/css
127
- register :javascript, TagEngine, :tag => 'script', :attributes => { :type => 'text/javascript' }
128
- register :css, TagEngine, :tag => 'style', :attributes => { :type => 'text/css' }
155
+ register :javascript, TagEngine, :tag => :script, :attributes => { :type => 'text/javascript' }
156
+ register :css, TagEngine, :tag => :style, :attributes => { :type => 'text/css' }
129
157
 
130
158
  # Embedded ruby code
131
159
  register :ruby, RubyEngine
@@ -14,6 +14,8 @@ module Slim
14
14
  END_REGEX = /^end\b/
15
15
 
16
16
  # Handle multi expression `[:multi, *exps]`
17
+ #
18
+ # @return [Array] Corrected Temple expression with ends inserted
17
19
  def on_multi(*exps)
18
20
  result = [:multi]
19
21
  # This variable is true if the previous line was
@@ -46,12 +48,12 @@ module Slim
46
48
 
47
49
  private
48
50
 
49
- # Appends an end.
51
+ # Appends an end
50
52
  def append_end(result)
51
- result << [:block, 'end']
53
+ result << [:code, 'end']
52
54
  end
53
55
 
54
- # Checks if an expression is a Slim control code.
56
+ # Checks if an expression is a Slim control code
55
57
  def control?(exp)
56
58
  exp[0] == :slim && exp[1] == :control
57
59
  end
data/lib/slim/engine.rb CHANGED
@@ -11,7 +11,7 @@ module Slim
11
11
  set_default_options :pretty => false,
12
12
  :attr_wrapper => '"',
13
13
  :format => :html5,
14
- :id_delimiter => nil,
14
+ :attr_delimiter => {'class' => ' '},
15
15
  :generator => Temple::Generators::ArrayBuffer
16
16
 
17
17
  #
@@ -28,12 +28,12 @@ module Slim
28
28
  # String | :dictionary | "self" | Name of dictionary variable in sections mode
29
29
  # Symbol | :dictionary_access | :wrapped | Access mode of dictionary variable (:wrapped, :symbol, :string)
30
30
  # Boolean | :disable_capture | false (true in Rails) | Disable capturing in blocks (blocks write to the default buffer then)
31
- # Boolean | :auto_escape | true | Enable automatic escaping of strings
32
- # Boolean | :use_html_safe | false (true in Rails) | Use String#html_safe? from ActiveSupport (Works together with :auto_escape)
33
- # Boolean | :debug | false | Enable debug outputs (Temple internals)
31
+ # Boolean | :disable_escape | false | Disable automatic escaping of strings
32
+ # Boolean | :use_html_safe | false (true in Rails) | Use String#html_safe? from ActiveSupport (Works together with :disable_escape)
34
33
  # Symbol | :format | :html5 | HTML output format
35
34
  # String | :attr_wrapper | '"' | Character to wrap attributes in html (can be ' or ")
36
- # String | :id_delimiter | '_' | Joining character used if multiple html ids are supplied (e.g. #id1#id2)
35
+ # Hash | :attr_delimiter | {'class' => ' '} | Joining character used if multiple html attributes are supplied (e.g. id1_id2)
36
+ # String list | :bool_attrs | %w(selected) | List of boolean attributes
37
37
  # Boolean | :pretty | false | Pretty html indenting (This is slower!)
38
38
  # Class | :generator | ArrayBuffer/RailsOutputBuffer | Temple code generator (default generator generates array buffer)
39
39
  #
@@ -58,14 +58,12 @@ module Slim
58
58
  use Slim::Interpolation
59
59
  use Slim::Sections, :sections, :dictionary, :dictionary_access
60
60
  use Slim::EndInserter
61
- use Slim::Compiler, :disable_capture, :auto_escape
62
- filter :EscapeHTML, :use_html_safe
63
- filter :Debugger, :debug, :debug_prefix => 'After Slim'
64
- use Temple::HTML::Pretty, :format, :attr_wrapper, :id_delimiter, :pretty
61
+ use Slim::Compiler, :disable_capture, :attr_delimiter, :bool_attrs
62
+ use Temple::HTML::Pretty, :format, :attr_wrapper, :attr_delimiter, :pretty
63
+ filter :Escapable, :use_html_safe, :disable_escape
64
+ filter :ControlFlow
65
65
  filter :MultiFlattener
66
- filter :StaticMerger
67
66
  filter :DynamicInliner
68
- filter :Debugger, :debug, :debug_prefix => 'Optimized code'
69
67
  use(:Generator) {|exp| options[:generator].new(options).call(exp) }
70
68
  end
71
69
  end