slim 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -555,7 +555,7 @@ This is the same as
555
555
  div class="content"
556
556
  = show_content
557
557
 
558
- ## Helpers and capturing
558
+ ## Helpers, capturing and includes
559
559
 
560
560
  If you use Slim you might want to extend your template with some helpers. Assume that you have the following helper
561
561
 
@@ -574,7 +574,7 @@ module Helpers
574
574
  end
575
575
  ~~~
576
576
 
577
- which can be used in Slim as follows
577
+ which is included in the scope that executes the Slim template code. The helper can then be used in the Slim template as follows
578
578
 
579
579
  p
580
580
  = headline do
@@ -589,6 +589,25 @@ sugar you can omit the `do` keyword and write only
589
589
  ' Hello
590
590
  = user.name
591
591
 
592
+ It has been requested many times to support includes of subtemplates in Slim. Up to now this has not been implemented as a core feature
593
+ but you can easily get it by writing your own helper. The includes will be executed at runtime.
594
+
595
+ ~~~ruby
596
+ module Helpers
597
+ def include_slim(name, options = {}, &block)
598
+ Slim::Template.new("#{name}.slim", options).render(self, &block)
599
+ end
600
+ end
601
+ ~~~
602
+
603
+ This helper can then be used as follows
604
+
605
+ nav= include_slim 'menu'
606
+ section= include_slim 'content'
607
+
608
+ However this helper doesn't do any caching. You should therefore implement a more intelligent version of the helper which
609
+ fits your purposes. You should also be aware that most frameworks already bring their own include helper, e.g. Rails has `render`.
610
+
592
611
  ## Text interpolation
593
612
 
594
613
  Use standard Ruby interpolation. The text will be html escaped by default.
@@ -754,7 +773,8 @@ Slim uses [Tilt](https://github.com/rtomayko/tilt) to compile the generated code
754
773
  Slim::Template.new('template.slim', optional_option_hash).render(scope)
755
774
  Slim::Template.new(optional_option_hash) { source }.render(scope)
756
775
 
757
- The optional option hash can have to options which were documented in the section above.
776
+ The optional option hash can have to options which were documented in the section above. The scope is the object in which the template
777
+ code is executed.
758
778
 
759
779
  ### Sinatra
760
780
 
@@ -805,7 +825,7 @@ Usage: slimrb [options]
805
825
  -v, --version Print version
806
826
  </pre>
807
827
 
808
- Start 'slimrb', type your code and press Ctrl-d to send EOF. Example usage:
828
+ Start 'slimrb', type your code and press Ctrl-d to send EOF. In Windows Command Prompt press Ctrl-z, Enter to send EOF. Example usage:
809
829
 
810
830
  <pre>
811
831
  $ slimrb
@@ -930,6 +950,7 @@ Syntax highlighting:
930
950
  * [Textmate / Sublime Text](https://github.com/slim-template/ruby-slim.tmbundle)
931
951
  * [Espresso text editor](https://github.com/slim-template/Slim-Sugar)
932
952
  * [Coda](https://github.com/slim-template/Coda-2-Slim.mode)
953
+ * [Atom](https://github.com/slim-template/language-slim)
933
954
 
934
955
  Template Converters (HAML, ERB, ...):
935
956
 
@@ -37,7 +37,7 @@ module Slim
37
37
  else
38
38
  # Attribute with merging
39
39
  @attr = name
40
- return super
40
+ super
41
41
  end
42
42
  end
43
43
 
@@ -17,13 +17,6 @@ module Slim
17
17
  @opts = OptionParser.new(&method(:set_opts))
18
18
  @opts.parse!(@args)
19
19
  process
20
- exit 0
21
- rescue Exception => ex
22
- raise ex if @options[:trace] || SystemExit === ex
23
- $stderr.print "#{ex.class}: " if ex.class != RuntimeError
24
- $stderr.puts ex.message
25
- $stderr.puts ' Use --trace for backtrace.'
26
- exit 1
27
20
  end
28
21
 
29
22
  private
@@ -93,11 +86,6 @@ module Slim
93
86
  end
94
87
  end
95
88
 
96
- unless @options[:output]
97
- file = args.shift
98
- @options[:output] = file ? File.open(file, 'w') : $stdout
99
- end
100
-
101
89
  result =
102
90
  if @options[:erb]
103
91
  require 'slim/erb_converter'
@@ -108,7 +96,19 @@ module Slim
108
96
  Template.new(@options[:file]) { @options[:input].read }.render
109
97
  end
110
98
 
111
- @options[:output].puts(result)
99
+ rescue Exception => ex
100
+ raise ex if @options[:trace] || SystemExit === ex
101
+ $stderr.print "#{ex.class}: " if ex.class != RuntimeError
102
+ $stderr.puts ex.message
103
+ $stderr.puts ' Use --trace for backtrace.'
104
+ exit 1
105
+ else
106
+ unless @options[:output]
107
+ file = args.shift
108
+ @options[:output] = file ? File.open(file, 'w') : $stdout
109
+ end
110
+ @options[:output].puts(result)
111
+ exit 0
112
112
  end
113
113
  end
114
114
  end
@@ -3,6 +3,8 @@ module Slim
3
3
  class Controls < Filter
4
4
  define_options :disable_capture
5
5
 
6
+ IF_RE = /\A(if|unless)\b|do\s*(\|[^\|]*\|)?\s*$/
7
+
6
8
  # Handle control expression `[:slim, :control, code, content]`
7
9
  #
8
10
  # @param [String] code Ruby code
@@ -21,9 +23,7 @@ module Slim
21
23
  # @param [Array] content Temple expression
22
24
  # @return [Array] Compiled temple expression
23
25
  def on_slim_output(escape, code, content)
24
- if empty_exp?(content)
25
- [:multi, [:escape, escape, [:dynamic, code]], content]
26
- else
26
+ if code =~ IF_RE
27
27
  tmp = unique_name
28
28
 
29
29
  [:multi,
@@ -43,6 +43,8 @@ module Slim
43
43
 
44
44
  # Output the content.
45
45
  [:escape, escape, [:dynamic, tmp]]]
46
+ else
47
+ [:multi, [:escape, escape, [:dynamic, code]], content]
46
48
  end
47
49
  end
48
50
 
@@ -10,8 +10,9 @@ module Slim
10
10
  #
11
11
  # @api private
12
12
  class EndInserter < Filter
13
- BLOCK_REGEX = /\A(else|elsif|when|rescue|ensure)\b/
14
- END_REGEX = /\Aend\b/
13
+ IF_RE = /\A(if|unless|else|elsif|when|rescue|ensure)\b|do\s*(\|[^\|]*\|)?\s*$/
14
+ ELSE_RE = /\A(else|elsif|when|rescue|ensure)\b/
15
+ END_RE = /\Aend\b/
15
16
 
16
17
  # Handle multi expression `[:multi, *exps]`
17
18
  #
@@ -24,14 +25,14 @@ module Slim
24
25
 
25
26
  exps.each do |exp|
26
27
  if control?(exp)
27
- raise(Temple::FilterError, 'Explicit end statements are forbidden') if exp[2] =~ END_REGEX
28
+ raise(Temple::FilterError, 'Explicit end statements are forbidden') if exp[2] =~ END_RE
28
29
 
29
30
  # Two control code in a row. If this one is *not*
30
31
  # an else block, we should close the previous one.
31
- append_end(result) if prev_indent && exp[2] !~ BLOCK_REGEX
32
+ append_end(result) if prev_indent && exp[2] !~ ELSE_RE
32
33
 
33
- # Indent if the control code contains something.
34
- prev_indent = !empty_exp?(exp[3])
34
+ # Indent if the control code starts a block.
35
+ prev_indent = exp[2] =~ IF_RE
35
36
  elsif exp[0] != :newline && prev_indent
36
37
  # This is *not* a control code, so we should close the previous one.
37
38
  # Ignores newlines because they will be inserted after each line.
@@ -7,6 +7,7 @@ module Slim
7
7
  # `define_options` when you have to override some default settings.
8
8
  define_options :pretty => false,
9
9
  :sort_attrs => true,
10
+ :format => :xhtml,
10
11
  :attr_quote => '"',
11
12
  :merge_attrs => {'class' => ' '},
12
13
  :generator => Temple::Generators::ArrayBuffer,
@@ -17,7 +18,7 @@ module Slim
17
18
  use Slim::Parser, :file, :tabsize, :shortcut, :default_tag, :attr_delims
18
19
  use Slim::Embedded, :enable_engines, :disable_engines, :pretty
19
20
  use Slim::Interpolation
20
- use Slim::Splat::Filter, :merge_attrs, :attr_quote, :sort_attrs, :default_tag, :hyphen_attrs
21
+ use Slim::Splat::Filter, :merge_attrs, :attr_quote, :sort_attrs, :default_tag, :hyphen_attrs, :format
21
22
  use Slim::DoInserter
22
23
  use Slim::EndInserter
23
24
  use Slim::Controls, :disable_capture
@@ -58,7 +58,7 @@ module Slim
58
58
  end
59
59
  end
60
60
  keys = Regexp.union @attr_shortcut.keys.sort_by {|k| -k.size }
61
- @attr_shortcut_re = /\A(#{keys}+)(#{WORD_RE}(?:#{WORD_RE}|-)*#{WORD_RE}|#{WORD_RE}+)/
61
+ @attr_shortcut_re = /\A(#{keys}+)((?:#{WORD_RE}|-)*)/
62
62
  keys = Regexp.union @tag_shortcut.keys.sort_by {|k| -k.size }
63
63
  @tag_re = /\A(?:#{keys}|\*(?=[^\s]+)|(#{WORD_RE}(?:#{WORD_RE}|:|-)*#{WORD_RE}|#{WORD_RE}+))/
64
64
  keys = Regexp.escape options[:attr_delims].keys.join
@@ -338,8 +338,9 @@ module Slim
338
338
  # Handle output code
339
339
  @line = $'
340
340
  trailing_ws2 = $2.include?('\'') || $2.include?('>')
341
+ leading_ws2 = $2.include?('<')
341
342
  block = [:multi]
342
- @stacks.last << [:static, ' '] if !leading_ws && $2.include?('<')
343
+ @stacks.last.insert(-2, [:static, ' ']) if !leading_ws && $2.include?('<')
343
344
  tag << [:slim, :output, $1 != '=', parse_broken_line, block]
344
345
  @stacks.last << [:static, ' '] if !trailing_ws && trailing_ws2
345
346
  @stacks << block
@@ -397,7 +398,7 @@ module Slim
397
398
  when boolean_attr_re
398
399
  # Boolean attribute
399
400
  @line = $'
400
- attributes << [:html, :attr, $1, [:slim, :attrvalue, false, 'true']]
401
+ attributes << [:html, :attr, $1, [:multi]]
401
402
  when end_re
402
403
  # Find ending delimiter
403
404
  @line = $'
@@ -13,18 +13,8 @@ module Slim
13
13
  attr(name, escape ? Temple::Utils.escape_html(value) : value) unless value.empty?
14
14
  elsif @options[:hyphen_attrs].include?(name) && Hash === value
15
15
  hyphen_attr(name, escape, value)
16
- else
17
- case value
18
- when false, nil
19
- # Boolean false attribute
20
- return
21
- when true
22
- # Boolean true attribute
23
- value = ''
24
- else
25
- value = value.to_s
26
- end
27
- attr(name, escape ? Temple::Utils.escape_html(value) : value)
16
+ elsif value != false && value != nil
17
+ attr(name, value != true && escape ? Temple::Utils.escape_html(value) : value)
28
18
  end
29
19
  end
30
20
 
@@ -37,7 +27,7 @@ module Slim
37
27
  def attr(name, value)
38
28
  if @attrs[name]
39
29
  if delim = @options[:merge_attrs][name]
40
- @attrs[name] << delim << value
30
+ @attrs[name] << delim << value.to_s
41
31
  else
42
32
  raise("Multiple #{name} attributes specified")
43
33
  end
@@ -59,7 +49,15 @@ module Slim
59
49
  def build_attrs
60
50
  attrs = @options[:sort_attrs] ? @attrs.sort_by(&:first) : @attrs
61
51
  attrs.map do |k, v|
62
- " #{k}=#{@options[:attr_quote]}#{v}#{@options[:attr_quote]}"
52
+ if v == true
53
+ if @options[:format] == :xhtml
54
+ " #{k}=#{@options[:attr_quote]}#{@options[:attr_quote]}"
55
+ else
56
+ " #{k}"
57
+ end
58
+ else
59
+ " #{k}=#{@options[:attr_quote]}#{v}#{@options[:attr_quote]}"
60
+ end
63
61
  end.join
64
62
  end
65
63
 
@@ -71,7 +69,7 @@ module Slim
71
69
  hyphen_attr("#{name}-#{n.to_s.gsub('_', '-')}", escape, v)
72
70
  end
73
71
  else
74
- attr(name, escape ? Temple::Utils.escape_html(value) : value.to_s)
72
+ attr(name, value != true && escape ? Temple::Utils.escape_html(value) : value)
75
73
  end
76
74
  end
77
75
  end
@@ -2,7 +2,7 @@ module Slim
2
2
  module Splat
3
3
  # @api private
4
4
  class Filter < ::Slim::Filter
5
- OPTIONS = [:merge_attrs, :attr_quote, :sort_attrs, :default_tag, :hyphen_attrs]
5
+ OPTIONS = [:merge_attrs, :attr_quote, :sort_attrs, :default_tag, :hyphen_attrs, :format]
6
6
  define_options OPTIONS
7
7
  default_options[:hyphen_attrs] = %w(data aria)
8
8
 
@@ -1,5 +1,5 @@
1
1
  module Slim
2
2
  # Slim version string
3
3
  # @api public
4
- VERSION = '2.0.2'
4
+ VERSION = '2.0.3'
5
5
  end
@@ -116,4 +116,57 @@ p
116
116
 
117
117
  assert_html 'Hello Ruby! Hello from within a block! Hello Ruby!', source
118
118
  end
119
+
120
+ def test_if_without_content
121
+ source = %q{
122
+ - if true
123
+ }
124
+ assert_html '', source
125
+ end
126
+
127
+ def test_unless_without_content
128
+ source = %q{
129
+ - unless true
130
+ }
131
+ assert_html '', source
132
+ end
133
+
134
+ def test_if_with_comment
135
+ source = %q{
136
+ - if true
137
+ / comment
138
+ }
139
+ assert_html '', source
140
+ end
141
+
142
+ def test_control_do_with_comment
143
+ source = %q{
144
+ - hello_world "Hello"
145
+ / comment
146
+ }
147
+ assert_html '', source
148
+ end
149
+
150
+ def test_output_do_with_comment
151
+ source = %q{
152
+ = hello_world "Hello"
153
+ / comment
154
+ }
155
+ assert_html 'Hello', source
156
+ end
157
+
158
+ def test_output_if_without_content
159
+ source = %q{
160
+ = if true
161
+ }
162
+ assert_html '', source
163
+ end
164
+
165
+ def test_output_if_with_comment
166
+ source = %q{
167
+ = if true
168
+ / comment
169
+ }
170
+ assert_html '', source
171
+ end
119
172
  end
@@ -1,4 +1,5 @@
1
1
  require 'helper'
2
+ require 'erb' #asciidoctor fail to load it randomly
2
3
 
3
4
  class TestSlimEmbeddedEngines < TestSlim
4
5
  def test_render_with_erb
@@ -410,6 +410,16 @@ renders as
410
410
  49
411
411
  ~~~
412
412
 
413
+ ~~~ slim
414
+ =< 7*7
415
+ ~~~
416
+
417
+ renders as
418
+
419
+ ~~~ html
420
+ 49
421
+ ~~~
422
+
413
423
  The legacy syntax `='` is also supported.
414
424
 
415
425
  ~~~ slim
@@ -705,13 +715,14 @@ You can force a trailing whitespace behind a tag by adding `>`. The legacy synta
705
715
  a#closed> class="test" /
706
716
  a#closed> class="test"/
707
717
  a> href='url1' Link1
718
+ a< href='url1' Link1
708
719
  a' href='url2' Link2
709
720
  ~~~
710
721
 
711
722
  renders as
712
723
 
713
724
  ~~~ html
714
- <a class="test" id="closed" /> <a class="test" id="closed" /> <a href="url1">Link1</a> <a href="url2">Link2</a>
725
+ <a class="test" id="closed" /> <a class="test" id="closed" /> <a href="url1">Link1</a> <a href="url1">Link1</a><a href="url2">Link2</a>
715
726
  ~~~
716
727
 
717
728
  If you combine > and =' only one trailing whitespace is added.
@@ -721,12 +732,15 @@ a> =' 'Text1'
721
732
  a =' 'Text2'
722
733
  a> = 'Text3'
723
734
  a>= 'Text4'
735
+ a=> 'Text5'
736
+ a<= 'Text6'
737
+ a=< 'Text7'
724
738
  ~~~
725
739
 
726
740
  renders as
727
741
 
728
742
  ~~~ html
729
- <a>Text1</a> <a>Text2</a> <a>Text3</a> <a>Text4</a>
743
+ <a>Text1</a> <a>Text2</a> <a>Text3</a> <a>Text4</a> <a>Text5</a> <a>Text6</a> <a>Text7</a>
730
744
  ~~~
731
745
 
732
746
  You can force a leading whitespace before a tag by adding `<`.
@@ -1008,6 +1022,28 @@ renders as
1008
1022
  <input type="text" /><input type="text" /><input type="text" /><input type="text" /><input type="text" />
1009
1023
  ~~~
1010
1024
 
1025
+ If html5 is activated the attributes are written as standalone.
1026
+
1027
+ ~~~ options
1028
+ :format => :html
1029
+ ~~~
1030
+
1031
+ ~~~ slim
1032
+ - true_value1 = ""
1033
+ - true_value2 = true
1034
+ input type="text" disabled=true_value1
1035
+ input type="text" disabled=true_value2
1036
+ input type="text" disabled="disabled"
1037
+ input type="text" disabled=true
1038
+ input(type="text" disabled)
1039
+ ~~~
1040
+
1041
+ renders as
1042
+
1043
+ ~~~ html
1044
+ <input disabled="" type="text"><input disabled type="text"><input disabled="disabled" type="text"><input disabled type="text"><input disabled type="text">
1045
+ ~~~
1046
+
1011
1047
  #### Attribute merging
1012
1048
 
1013
1049
  You can configure attributes to be merged if multiple are given (See option `:merge_attrs`). In the default configuration
@@ -1160,6 +1196,32 @@ renders to
1160
1196
 
1161
1197
  #### ID shortcut and class shortcut `.`
1162
1198
 
1199
+ ID and class shortcuts can contain dashes.
1200
+
1201
+ ~~~ slim
1202
+ .-test text
1203
+ #test- text
1204
+ .--a#b- text
1205
+ .a--test-123#--b text
1206
+ ~~~
1207
+
1208
+ renders as
1209
+
1210
+ ~~~ html
1211
+ <div class="-test">
1212
+ text
1213
+ </div>
1214
+ <div id="test-">
1215
+ text
1216
+ </div>
1217
+ <div class="--a" id="b-">
1218
+ text
1219
+ </div>
1220
+ <div class="a--test-123" id="--b">
1221
+ text
1222
+ </div>
1223
+ ~~~
1224
+
1163
1225
  ## Text interpolation
1164
1226
 
1165
1227
  Use standard Ruby interpolation. The text will be html escaped by default.