slim 2.0.2 → 2.0.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/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.