slim 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,6 +4,7 @@ rvm:
4
4
  - ruby-head
5
5
  - jruby
6
6
  - rbx-18mode
7
+ - rbx-19mode
7
8
  env:
8
9
  - "TASK=test"
9
10
  - "TASK=test TEMPLE=master"
data/CHANGES CHANGED
@@ -1,3 +1,15 @@
1
+ 1.2.0
2
+
3
+ * Add option :shortcut which configures attribute shortcuts
4
+ Default setting:
5
+ Slim::Parser.default_options[:shortcut] = {'#' => 'id', '.' => 'class', '*' => '*'}
6
+ Define custom shortcut attribute (e.g. a@ajax-link renders <a role="ajax-link"></a>)
7
+ Slim::Parser.default_options[:shortcut] = {'@' => 'role'}
8
+ Define custom shortcut attribute with tag (e.g. @ajax-link renders <a role="ajax-link"></a>)
9
+ Slim::Parser.default_options[:shortcut] = {'@' => 'a role'}
10
+ * Add syntax for splat attributes (#109)
11
+ * Support for dynamic tags, e.g. *{:tag => 'img', :src => 'image.jpg'}
12
+
1
13
  1.1.1
2
14
 
3
15
  * Evaluating a html attribute now happens only once (#219)
data/README.md CHANGED
@@ -41,11 +41,16 @@ If you want to use the Slim template directly, you can use the Tilt interface:
41
41
 
42
42
  ## Syntax Highlighters
43
43
 
44
- Syntax highlight support for __Emacs__ is included in the `extra` folder. There are also [Vim](https://github.com/bbommarito/vim-slim) and [Textmate](https://github.com/fredwu/ruby-slim-tmbundle) plugins.
44
+ There are plugins for Vim, Emacs, Textmate and Espresso text editor:
45
+
46
+ * [Vim](https://github.com/bbommarito/vim-slim)
47
+ * [Textmate](https://github.com/fredwu/ruby-slim-tmbundle)
48
+ * [Emacs](https://github.com/minad/emacs-slim)
49
+ * [Espresso text editor](https://github.com/CiiDub/Slim-Sugar)
45
50
 
46
51
  ## Template Converters
47
52
 
48
- For Haml, there is a [Haml2Slim converter](https://github.com/fredwu/haml2slim). Please check out the [issue tracker](https://github.com/stonean/slim/issues) to see the status of the varies converters.
53
+ For Haml, there is a [Haml2Slim converter](https://github.com/fredwu/haml2slim). For HTML, there is a [HTML2Slim converter](https://github.com/joaomilho/html2slim).
49
54
 
50
55
  ## The syntax
51
56
 
@@ -124,7 +129,7 @@ Here's a quick example to demonstrate what a Slim template looks like:
124
129
 
125
130
  #### `/!`
126
131
 
127
- > Use the forward slash immediately followed by an exclamation mark for html comments (`<!-- -->`).
132
+ > Use the forward slash immediately followed by an exclamation mark for html comments (` <!-- --> `).
128
133
 
129
134
 
130
135
  ### Things to know
@@ -388,8 +393,19 @@ This project is released under the MIT license.
388
393
 
389
394
  ## Slim related projects
390
395
 
391
- * [Vim files](https://github.com/bbommarito/vim-slim)
396
+ * [Temple](https://github.com/judofyr/slim)
397
+
398
+ * [Vim syntax highlighting](https://github.com/bbommarito/vim-slim)
399
+ * [Emacs syntax highlighting](https://github.com/minad/emacs-slim)
392
400
  * [Textmate bundle](https://github.com/fredwu/ruby-slim-tmbundle)
401
+ * [Slim support for the Espresso text editor from MacRabbits](https://github.com/CiiDub/Slim-Sugar)
402
+
393
403
  * [Haml2Slim converter](https://github.com/fredwu/haml2slim)
404
+ * [Html2Slim converter](https://github.com/joaomilho/html2slim)
405
+
394
406
  * [Rails 3 Generators](https://github.com/leogalmeida/slim-rails)
407
+
408
+ * [Skim (Slim for Javascript)](https://github.com/jfirebaugh/skim)
395
409
  * [Slim for Clojure](https://github.com/chaslemley/slim.clj)
410
+ * [Hamlet.rb (Similar template language)](https://github.com/gregwebs/hamlet.rb)
411
+ * [Coffee script plugin for Slim](https://github.com/yury/coffee-views)
@@ -1,7 +1,16 @@
1
1
  module Slim
2
- # Compiles Slim expressions into Temple::HTML expressions.
3
2
  # @api private
4
3
  class Compiler < Filter
4
+ def call(exp)
5
+ @attr_delimiter, @splat_used = unique_name, false
6
+ exp = compile(exp)
7
+ if @splat_used
8
+ [:multi, [:code, "#{@attr_delimiter} = #{@options[:attr_delimiter].inspect}"], exp]
9
+ else
10
+ exp
11
+ end
12
+ end
13
+
5
14
  # Handle control expression `[:slim, :control, code, content]`
6
15
  #
7
16
  # @param [String] ruby code
@@ -19,7 +28,11 @@ module Slim
19
28
  # @param [Array] content Temple expression
20
29
  # @return [Array] Compiled temple expression
21
30
  def on_slim_condcomment(condition, content)
22
- [:html, :comment, [:multi, [:static, "[#{condition}]>"], compile(content), [:static, '<![endif]']]]
31
+ [:html, :comment,
32
+ [:multi,
33
+ [:static, "[#{condition}]>"],
34
+ compile(content),
35
+ [:static, '<![endif]']]]
23
36
  end
24
37
 
25
38
  # Handle output expression `[:slim, :output, escape, code, content]`
@@ -54,6 +67,53 @@ module Slim
54
67
  end
55
68
  end
56
69
 
70
+ # Handle tag expression `[:slim, :tag, name, attrs, content]`
71
+ #
72
+ # @param [String] name Tag name
73
+ # @param [Array] attrs Temple expression
74
+ # @param [Array] content Temple expression
75
+ # @return [Array] Compiled temple expression
76
+ def on_slim_tag(name, attrs, content = nil)
77
+ if name == '*'
78
+ hash, merger, formatter = splat_attributes(attrs[2..-1])
79
+ tmp = unique_name
80
+ tag = [:multi,
81
+ merger,
82
+ [:code, "#{tmp} = #{hash}.delete('tag').to_s"],
83
+ [:if, "#{tmp}.empty?",
84
+ [:code, "#{tmp} = #{@options[:default_tag].inspect}"]],
85
+ [:static, '<'],
86
+ [:dynamic, "#{tmp}"],
87
+ formatter]
88
+ tag << if content
89
+ [:multi,
90
+ [:static, '>'],
91
+ compile(content),
92
+ [:static, '</'],
93
+ [:dynamic, "#{tmp}"],
94
+ [:static, '>']]
95
+ else
96
+ [:static, '/>']
97
+ end
98
+ else
99
+ tag = [:html, :tag, name, compile(attrs)]
100
+ content ? (tag << compile(content)) : tag
101
+ end
102
+ end
103
+
104
+ # Handle attributes expression `[:slim, :attrs, *attrs]`
105
+ #
106
+ # @param [Array] *attrs Array of temple expressions
107
+ # @return [Array] Compiled temple expression
108
+ def on_slim_attrs(*attrs)
109
+ if attrs.any? {|attr| attr[1] == :splat}
110
+ hash, merger, formatter = splat_attributes(attrs)
111
+ [:multi, merger, formatter]
112
+ else
113
+ [:html, :attrs, *attrs.map {|a| compile(a) }]
114
+ end
115
+ end
116
+
57
117
  # Handle attribute expression `[:slim, :attr, escape, code]`
58
118
  #
59
119
  # @param [Boolean] escape Escape html
@@ -62,10 +122,8 @@ module Slim
62
122
  def on_slim_attr(name, escape, code)
63
123
  value = case code
64
124
  when 'true'
65
- escape = false
66
125
  [:static, name]
67
126
  when 'false', 'nil'
68
- escape = false
69
127
  [:multi]
70
128
  else
71
129
  tmp = unique_name
@@ -75,15 +133,67 @@ module Slim
75
133
  ['true', [:static, name]],
76
134
  ['false, nil', [:multi]],
77
135
  [:else,
78
- [:dynamic,
136
+ [:escape, escape, [:dynamic,
79
137
  if delimiter = options[:attr_delimiter][name]
80
138
  "#{tmp}.respond_to?(:join) ? #{tmp}.flatten.compact.join(#{delimiter.inspect}) : #{tmp}"
81
139
  else
82
140
  tmp
83
141
  end
84
- ]]]]
142
+ ]]]]]
85
143
  end
86
- [:html, :attr, name, [:escape, escape, value]]
144
+ [:html, :attr, name, value]
145
+ end
146
+
147
+ protected
148
+
149
+ def splat_attributes(attrs)
150
+ @splat_used = true
151
+
152
+ hash, name, value, tmp = unique_name, unique_name, unique_name, unique_name
153
+
154
+ merger = [:multi, [:code, "#{hash} = {}"]]
155
+ attrs.each do |attr|
156
+ merger << if attr[0] == :html && attr[1] == :attr
157
+ [:multi,
158
+ [:capture, tmp, compile(attr[3])],
159
+ [:code, "(#{hash}[#{attr[2].inspect}] ||= []) << #{tmp}"]]
160
+ elsif attr[0] == :slim
161
+ if attr[1] == :attr
162
+ [:code, "(#{hash}[#{attr[2].inspect}] ||= []) << (#{attr[4]})"]
163
+ elsif attr[1] == :splat
164
+ [:code, "(#{attr[2]}).each {|#{name},#{value}| (#{hash}[#{name}.to_s] ||= []) << (#{value}) }"]
165
+ else
166
+ attr
167
+ end
168
+ else
169
+ attr
170
+ end
171
+ end
172
+
173
+ merger << [:block, "#{hash}.keys.each do |#{name}|",
174
+ [:multi,
175
+ [:code, "#{value} = #{hash}[#{name}]"],
176
+ [:code, "#{value}.flatten!"],
177
+ [:block, "#{value}.map! do |#{tmp}|",
178
+ [:case, tmp,
179
+ ['true', [:code, name]],
180
+ ['false, nil', [:multi]],
181
+ [:else, [:code, tmp]]]],
182
+ [:if, "#{value}.size > 1 && !#{@attr_delimiter}[#{name}]",
183
+ [:code, "raise(\"Multiple #\{#{name}\} attributes specified\")"]],
184
+ [:code, "#{hash}[#{name}] = #{value}.compact.join(#{@attr_delimiter}[#{name}].to_s)"]]]
185
+
186
+ attr = [:multi,
187
+ [:static, ' '],
188
+ [:dynamic, name],
189
+ [:static, "=#{options[:attr_wrapper]}"],
190
+ [:escape, true, [:dynamic, value]],
191
+ [:static, options[:attr_wrapper]]]
192
+ attr = [:if, "!#{value}.empty?", attr] if options[:remove_empty_attrs]
193
+ enumerator = options[:sort_attrs] ? "#{hash}.sort_by {|#{name},#{value}| #{name} }" : hash
194
+ formatter = [:block, "#{enumerator}.each do |#{name},#{value}|", attr]
195
+
196
+ return hash, merger, formatter
87
197
  end
88
198
  end
89
199
  end
@@ -179,6 +179,7 @@ module Slim
179
179
  register :rdoc, InterpolateTiltEngine
180
180
  register :creole, InterpolateTiltEngine
181
181
  register :wiki, InterpolateTiltEngine
182
+ register :mediawiki, InterpolateTiltEngine
182
183
 
183
184
  # These engines are executed at compile time
184
185
  register :coffee, TagEngine, :tag => :script, :attributes => { :type => 'text/javascript' }, :engine => StaticTiltEngine
@@ -9,10 +9,12 @@ module Slim
9
9
  #
10
10
  # This overwrites some temple default options.
11
11
  set_default_options :pretty => false,
12
+ :sort_attrs => true,
12
13
  :attr_wrapper => '"',
13
14
  :attr_delimiter => {'class' => ' '},
14
- :generator => Temple::Generators::ArrayBuffer
15
-
15
+ :remove_empty_attrs => true,
16
+ :generator => Temple::Generators::ArrayBuffer,
17
+ :default_tag => 'div'
16
18
  #
17
19
  # Document all supported options with purpose, type etc.
18
20
  #
@@ -22,6 +24,7 @@ module Slim
22
24
  # Integer | :tabsize | 4 | Number of whitespaces per tab (used by the parser)
23
25
  # String | :encoding | "utf-8" | Set encoding of template
24
26
  # String | :default_tag | "div" | Default tag to be used if tag name is omitted
27
+ # Hash | :shortcut | {'.' => 'class', ...} | Attribute shortcuts
25
28
  # String list | :enable_engines | All enabled | List of enabled embedded engines (whitelist)
26
29
  # String list | :disable_engines | None disabled | List of disabled embedded engines (blacklist)
27
30
  # Boolean | :sections | false | Enable sections mode (logic-less)
@@ -56,12 +59,12 @@ module Slim
56
59
  # It is recommended to set the default settings only once in the code and avoid duplication. Only use
57
60
  # `set_default_options` when you have to override some default settings.
58
61
  #
59
- use Slim::Parser, :file, :tabsize, :encoding, :default_tag
62
+ use Slim::Parser, :file, :tabsize, :encoding, :shortcut, :default_tag
60
63
  use Slim::EmbeddedEngine, :enable_engines, :disable_engines, :pretty
61
64
  use Slim::Interpolation
62
65
  use Slim::Sections, :sections, :dictionary, :dictionary_access
63
66
  use Slim::EndInserter
64
- use Slim::Compiler, :disable_capture, :attr_delimiter
67
+ use Slim::Compiler, :disable_capture, :attr_delimiter, :attr_wrapper, :sort_attrs, :remove_empty_attrs, :default_tag
65
68
  html :AttributeMerger, :attr_delimiter
66
69
  html :AttributeSorter, :sort_attrs
67
70
  html :AttributeRemover, :remove_empty_attrs
@@ -26,5 +26,16 @@ module Slim
26
26
  def on_slim_output(code, escape, content)
27
27
  [:slim, :output, code, escape, compile(content)]
28
28
  end
29
+
30
+ # Pass-through handler
31
+ def on_slim_attrs(*attrs)
32
+ [:slim, :attrs, *attrs.map {|a| compile(a) }]
33
+ end
34
+
35
+ # Pass-through handler
36
+ def on_slim_tag(name, attrs, content = nil)
37
+ tag = [:slim, :tag, name, compile(attrs)]
38
+ content ? (tag << compile(content)) : tag
39
+ end
29
40
  end
30
41
  end
@@ -5,14 +5,19 @@ module Slim
5
5
  extend Temple::Grammar
6
6
 
7
7
  Expression <<
8
- [:slim, :control, String, Expression] |
9
- [:slim, :condcomment, String, Expression] |
10
- [:slim, :output, Bool, String, Expression] |
11
- [:slim, :interpolate, String] |
12
- [:slim, :embedded, String, Expression]
8
+ [:slim, :control, String, Expression] |
9
+ [:slim, :condcomment, String, Expression] |
10
+ [:slim, :output, Bool, String, Expression] |
11
+ [:slim, :interpolate, String] |
12
+ [:slim, :embedded, String, Expression] |
13
+ [:slim, :tag, String, SlimAttrs, 'Expression?']
13
14
 
14
- HTMLAttr <<
15
- [:slim, :attr, String, Bool, String]
15
+ SlimAttrs <<
16
+ [:slim, :attrs, 'SlimAttr*']
16
17
 
18
+ SlimAttr <<
19
+ HTMLAttr |
20
+ [:slim, :attr, String, Bool, String] |
21
+ [:slim, :splat, String]
17
22
  end
18
23
  end
@@ -16,7 +16,7 @@ module Slim
16
16
  case string
17
17
  when /\A\\#\{/
18
18
  # Escaped interpolation
19
- # HACK: Use :slim :output because this is used by InterpolateTiltEngine
19
+ # Use [:slim, :output] because this is used by InterpolateTiltEngine
20
20
  # to filter out protected strings (Issue #141).
21
21
  block << [:slim, :output, false, '\'#{\'', [:multi]]
22
22
  string = $'
@@ -4,9 +4,12 @@ module Slim
4
4
  class Parser
5
5
  include Temple::Mixins::Options
6
6
 
7
- set_default_options :tabsize => 4,
7
+ set_default_options :tabsize => 4,
8
8
  :encoding => 'utf-8',
9
- :default_tag => 'div'
9
+ :shortcut => {
10
+ '#' => 'id',
11
+ '.' => 'class'
12
+ }
10
13
 
11
14
  class SyntaxError < StandardError
12
15
  attr_reader :error, :file, :line, :lineno, :column
@@ -33,6 +36,17 @@ module Slim
33
36
  def initialize(options = {})
34
37
  super
35
38
  @tab = ' ' * @options[:tabsize]
39
+ @shortcut = {}
40
+ @options[:shortcut].each do |k,v|
41
+ @shortcut[k] = if v =~ /\A([^\s]+)\s+([^\s]+)\Z/
42
+ [$1, $2]
43
+ else
44
+ [@options[:default_tag], v]
45
+ end
46
+ end
47
+ shortcut = "[#{Regexp.escape @shortcut.keys.join}]"
48
+ @shortcut_regex = /\A(#{shortcut})(\w[\w-]*\w|\w+)/
49
+ @tag_regex = /\A(?:#{shortcut}|\*(?=[^\s]+)|(\w[\w:-]*\w|\w+))/
36
50
  end
37
51
 
38
52
  # Compile string to Temple expression
@@ -66,15 +80,10 @@ module Slim
66
80
  '{' => '}',
67
81
  }.freeze
68
82
 
69
- ATTR_SHORTCUT = {
70
- '#' => 'id',
71
- '.' => 'class',
72
- }.freeze
73
-
74
- DELIMITER_REGEX = /\A[\(\[\{]/
75
- ATTR_NAME_REGEX = '\A\s*(\w[:\w-]*)'
76
- CLASS_ID_REGEX = /\A(#|\.)(\w[\w-]*\w|\w+)/
77
- TAG_REGEX = /\A([#\.]|\w[\w:-]*\w|\w+)/
83
+ DELIMITER_REGEX = /\A[#{Regexp.escape DELIMITERS.keys.join}]/
84
+ ATTR_NAME = '\A\s*(\w[:\w-]*)'
85
+ QUOTED_ATTR_REGEX = /#{ATTR_NAME}=("|')/
86
+ CODE_ATTR_REGEX = /#{ATTR_NAME}=/
78
87
 
79
88
  def reset(lines = nil, stacks = nil)
80
89
  # Since you can indent however you like in Slim, we need to keep a list
@@ -208,8 +217,9 @@ module Slim
208
217
  when /\Adoctype\s+/i
209
218
  # Found doctype declaration
210
219
  @stacks.last << [:html, :doctype, $'.strip]
211
- when TAG_REGEX
220
+ when @tag_regex
212
221
  # Found a HTML tag.
222
+ @line = $' if $1
213
223
  parse_tag($&)
214
224
  else
215
225
  syntax_error! 'Unknown line indicator'
@@ -279,25 +289,20 @@ module Slim
279
289
  end
280
290
 
281
291
  def parse_tag(tag)
282
- if tag == '#' || tag == '.'
283
- tag = options[:default_tag]
284
- else
285
- @line.slice!(0, tag.size)
286
- end
287
-
288
- tag = [:html, :tag, tag, parse_attributes]
292
+ tag = [:slim, :tag, @shortcut[tag] ? @shortcut[tag][0] : tag, parse_attributes]
289
293
  @stacks.last << tag
290
294
 
291
295
  case @line
292
296
  when /\A\s*:\s*/
293
297
  # Block expansion
294
298
  @line = $'
295
- (@line =~ TAG_REGEX) || syntax_error!('Expected tag')
299
+ (@line =~ @tag_regex) || syntax_error!('Expected tag')
300
+ @line = $' if $1
296
301
  content = [:multi]
297
302
  tag << content
298
303
  i = @stacks.size
299
304
  @stacks << content
300
- parse_tag($1)
305
+ parse_tag($&)
301
306
  @stacks.delete_at(i)
302
307
  when /\A\s*=(=?)('?)/
303
308
  # Handle output code
@@ -321,13 +326,14 @@ module Slim
321
326
  end
322
327
 
323
328
  def parse_attributes
324
- attributes = [:html, :attrs]
329
+ attributes = [:slim, :attrs]
330
+ attribute = nil
325
331
 
326
- # Find any literal class/id attributes
327
- while @line =~ CLASS_ID_REGEX
332
+ # Find any shortcut attributes
333
+ while @line =~ @shortcut_regex
328
334
  # The class/id attribute is :static instead of :slim :text,
329
335
  # because we don't want text interpolation in .class or #id shortcut
330
- attributes << [:html, :attr, ATTR_SHORTCUT[$1], [:static, $2]]
336
+ attributes << [:html, :attr, @shortcut[$1][1], [:static, $2]]
331
337
  @line = $'
332
338
  end
333
339
 
@@ -338,54 +344,67 @@ module Slim
338
344
  @line.slice!(0)
339
345
  end
340
346
 
341
- orig_line = @orig_line
342
- lineno = @lineno
347
+ if delimiter
348
+ boolean_attr_regex = /#{ATTR_NAME}(?=(\s|#{Regexp.escape delimiter}))/
349
+ end_regex = /\A\s*#{Regexp.escape delimiter}/
350
+ end
351
+
343
352
  while true
344
- # Parse attributes
345
- attr_regex = delimiter ? /#{ATTR_NAME_REGEX}(=|\s|(?=#{Regexp.escape delimiter}))/ : /#{ATTR_NAME_REGEX}=/
346
- while @line =~ attr_regex
353
+ case @line
354
+ when /\A\s*\*(?=[^\s]+)/
355
+ # Splat attribute
356
+ @line = $'
357
+ attributes << [:slim, :splat, parse_ruby_code(delimiter)]
358
+ when QUOTED_ATTR_REGEX
359
+ # Value is quoted (static)
347
360
  @line = $'
361
+ attributes << [:html, :attr, $1, [:slim, :interpolate, parse_quoted_attribute($2)]]
362
+ when CODE_ATTR_REGEX
363
+ # Value is ruby code
364
+ @line = $'
365
+ escape = @line[0] != ?=
366
+ @line.slice!(0) unless escape
348
367
  name = $1
349
- if delimiter && $2 != '='
350
- attributes << [:slim, :attr, name, false, 'true']
351
- elsif @line =~ /\A["']/
352
- # Value is quoted (static)
368
+ value = parse_ruby_code(delimiter)
369
+ # Remove attribute wrapper which doesn't belong to the ruby code
370
+ # e.g id=[hash[:a] + hash[:b]]
371
+ value = value[1..-2] if value =~ DELIMITER_REGEX &&
372
+ DELIMITERS[$&] == value[-1, 1]
373
+ syntax_error!('Invalid empty attribute') if value.empty?
374
+ attributes << [:slim, :attr, name, escape, value]
375
+ else
376
+ break unless delimiter
377
+
378
+ case @line
379
+ when boolean_attr_regex
380
+ # Boolean attribute
353
381
  @line = $'
354
- attributes << [:html, :attr, name, [:slim, :interpolate, parse_quoted_attribute($&)]]
382
+ attributes << [:slim, :attr, $1, false, 'true']
383
+ when end_regex
384
+ # Find ending delimiter
385
+ @line = $'
386
+ break
355
387
  else
356
- # Value is ruby code
357
- escape = @line[0] != ?=
358
- @line.slice!(0) unless escape
359
- attributes << [:slim, :attr, name, escape, parse_ruby_attribute(delimiter)]
388
+ # Found something where an attribute should be
389
+ @line.lstrip!
390
+ syntax_error!('Expected attribute') unless @line.empty?
391
+
392
+ # Attributes span multiple lines
393
+ @stacks.last << [:newline]
394
+ orig_line, lineno = @orig_line, @lineno
395
+ next_line || syntax_error!("Expected closing delimiter #{delimiter}",
396
+ :orig_line => orig_line,
397
+ :lineno => lineno,
398
+ :column => orig_line.size)
360
399
  end
361
400
  end
362
-
363
- # No ending delimiter, attribute end
364
- break unless delimiter
365
-
366
- # Find ending delimiter
367
- if @line =~ /\A\s*#{Regexp.escape delimiter}/
368
- @line = $'
369
- break
370
- end
371
-
372
- # Found something where an attribute should be
373
- @line.lstrip!
374
- syntax_error!('Expected attribute') unless @line.empty?
375
-
376
- # Attributes span multiple lines
377
- @stacks.last << [:newline]
378
- next_line || syntax_error!("Expected closing delimiter #{delimiter}",
379
- :orig_line => orig_line,
380
- :lineno => lineno,
381
- :column => orig_line.size)
382
401
  end
383
402
 
384
403
  attributes
385
404
  end
386
405
 
387
- def parse_ruby_attribute(outer_delimiter)
388
- value, count, delimiter, close_delimiter = '', 0, nil, nil
406
+ def parse_ruby_code(outer_delimiter)
407
+ code, count, delimiter, close_delimiter = '', 0, nil, nil
389
408
 
390
409
  # Attribute ends with space or attribute delimiter
391
410
  end_regex = /\A[\s#{Regexp.escape outer_delimiter.to_s}]/
@@ -401,18 +420,10 @@ module Slim
401
420
  count = 1
402
421
  delimiter, close_delimiter = $&, DELIMITERS[$&]
403
422
  end
404
- value << @line.slice!(0)
423
+ code << @line.slice!(0)
405
424
  end
406
-
407
- syntax_error!("Expected closing attribute delimiter #{close_delimiter}") if count != 0
408
- syntax_error!('Invalid empty attribute') if value.empty?
409
-
410
- # Remove attribute wrapper which doesn't belong to the ruby code
411
- # e.g id=[hash[:a] + hash[:b]]
412
- value = value[1..-2] if value =~ DELIMITER_REGEX &&
413
- DELIMITERS[$&] == value[-1, 1]
414
-
415
- value
425
+ syntax_error!("Expected closing delimiter #{close_delimiter}") if count != 0
426
+ code
416
427
  end
417
428
 
418
429
  def parse_quoted_attribute(quote)