slim 1.3.9 → 2.0.0
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -8
- data/.travis.yml +8 -7
- data/CHANGES +35 -0
- data/Gemfile +9 -9
- data/README.md +94 -176
- data/Rakefile +7 -14
- data/benchmarks/run-benchmarks.rb +9 -37
- data/doc/logic_less.md +140 -0
- data/doc/translator.md +31 -0
- data/lib/slim.rb +3 -1
- data/lib/slim/code_attributes.rb +20 -20
- data/lib/slim/command.rb +16 -6
- data/lib/slim/do_inserter.rb +33 -0
- data/lib/slim/embedded.rb +0 -6
- data/lib/slim/end_inserter.rb +2 -2
- data/lib/slim/engine.rb +9 -23
- data/lib/slim/erb_converter.rb +14 -0
- data/lib/slim/filter.rb +2 -2
- data/lib/slim/logic_less/context.rb +8 -0
- data/lib/slim/logic_less/filter.rb +12 -11
- data/lib/slim/parser.rb +57 -113
- data/lib/slim/splat/builder.rb +79 -0
- data/lib/slim/splat/filter.rb +93 -0
- data/lib/slim/version.rb +1 -1
- data/slim.gemspec +1 -1
- data/test/core/helper.rb +1 -3
- data/test/core/test_code_blocks.rb +51 -0
- data/test/core/test_code_evaluation.rb +4 -12
- data/test/core/test_embedded_engines.rb +18 -44
- data/test/core/test_encoding.rb +8 -1
- data/test/core/test_erb_converter.rb +67 -0
- data/test/core/test_html_attributes.rb +19 -25
- data/test/core/test_html_escaping.rb +10 -2
- data/test/core/test_html_structure.rb +6 -6
- data/test/core/test_parser_errors.rb +1 -1
- data/test/core/test_ruby_errors.rb +2 -6
- data/test/core/test_thread_options.rb +4 -4
- data/test/core/test_unicode.rb +18 -0
- data/test/literate/TESTS.md +193 -34
- data/test/logic_less/test_logic_less.rb +17 -0
- data/test/rails/app/controllers/application_controller.rb +0 -1
- data/test/rails/app/controllers/entries_controller.rb +5 -0
- data/test/rails/app/controllers/slim_controller.rb +3 -0
- data/test/rails/app/models/entry.rb +16 -0
- data/test/rails/app/views/entries/edit.html.slim +3 -0
- data/test/rails/app/views/slim/form_for.html.slim +2 -0
- data/test/rails/app/views/slim/xml.slim +1 -0
- data/test/rails/config/application.rb +2 -2
- data/test/rails/config/environments/test.rb +1 -1
- data/test/rails/config/routes.rb +1 -1
- data/test/rails/test/helper.rb +0 -3
- data/test/rails/test/test_slim.rb +13 -8
- data/test/translator/test_translator.rb +13 -2
- metadata +17 -14
- data/lib/slim/splat_attributes.rb +0 -113
- data/test/rails/app/controllers/parents_controller.rb +0 -85
- data/test/rails/app/models/child.rb +0 -3
- data/test/rails/app/models/parent.rb +0 -4
- data/test/rails/app/views/parents/_form.html.slim +0 -8
- data/test/rails/app/views/parents/edit.html.slim +0 -2
- data/test/rails/app/views/parents/new.html.slim +0 -2
- data/test/rails/app/views/parents/show.html.slim +0 -5
- data/test/rails/config/database.yml +0 -4
- data/test/rails/db/migrate/20101220223037_parents_and_children.rb +0 -17
data/lib/slim/engine.rb
CHANGED
@@ -5,37 +5,23 @@ module Slim
|
|
5
5
|
# This overwrites some Temple default options or sets default options for Slim specific filters.
|
6
6
|
# It is recommended to set the default settings only once in the code and avoid duplication. Only use
|
7
7
|
# `define_options` when you have to override some default settings.
|
8
|
-
define_options :
|
9
|
-
:merge_attrs,
|
10
|
-
:pretty => false,
|
8
|
+
define_options :pretty => false,
|
11
9
|
:sort_attrs => true,
|
12
|
-
:generator => Temple::Generators::ArrayBuffer,
|
13
|
-
:default_tag => 'div',
|
14
10
|
:attr_quote => '"',
|
15
11
|
:merge_attrs => {'class' => ' '},
|
16
|
-
:
|
17
|
-
|
18
|
-
|
19
|
-
define_deprecated_options :remove_empty_attrs,
|
20
|
-
:chain,
|
21
|
-
:escape_quoted_attrs,
|
22
|
-
:attr_wrapper,
|
23
|
-
:attr_delimiter
|
24
|
-
|
25
|
-
def initialize(opts = {})
|
26
|
-
super
|
27
|
-
deprecated = {}
|
28
|
-
deprecated[:merge_attrs] = options[:attr_delimiter] if options.include? :attr_delimiter
|
29
|
-
deprecated[:attr_quote] = options[:attr_wrapper] if options.include? :attr_wrapper
|
30
|
-
@options = Temple::ImmutableHash.new(deprecated, @options) unless deprecated.empty?
|
31
|
-
end
|
12
|
+
:encoding => 'utf-8',
|
13
|
+
:generator => Temple::Generators::ArrayBuffer,
|
14
|
+
:default_tag => 'div'
|
32
15
|
|
33
|
-
|
16
|
+
filter :Encoding, :encoding
|
17
|
+
filter :RemoveBOM
|
18
|
+
use Slim::Parser, :file, :tabsize, :shortcut, :default_tag
|
34
19
|
use Slim::Embedded, :enable_engines, :disable_engines, :pretty
|
35
20
|
use Slim::Interpolation
|
21
|
+
use Slim::Splat::Filter, :merge_attrs, :attr_quote, :sort_attrs, :default_tag, :hyphen_attrs
|
22
|
+
use Slim::DoInserter
|
36
23
|
use Slim::EndInserter
|
37
24
|
use Slim::Controls, :disable_capture
|
38
|
-
use Slim::SplatAttributes, :merge_attrs, :attr_quote, :sort_attrs, :default_tag
|
39
25
|
html :AttributeSorter, :sort_attrs
|
40
26
|
html :AttributeMerger, :merge_attrs
|
41
27
|
use Slim::CodeAttributes, :merge_attrs
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'slim'
|
2
|
+
|
3
|
+
module Slim
|
4
|
+
# Slim to ERB converter
|
5
|
+
#
|
6
|
+
# @example Conversion
|
7
|
+
# Slim::ERBConverter.new(options).call(slim_code) # outputs erb_code
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
class ERBConverter < Engine
|
11
|
+
replace :Optimizer, Temple::Filters::CodeMerger
|
12
|
+
replace :Generator, Temple::Generators::ERB
|
13
|
+
end
|
14
|
+
end
|
data/lib/slim/filter.rb
CHANGED
@@ -23,8 +23,8 @@ module Slim
|
|
23
23
|
end
|
24
24
|
|
25
25
|
# Pass-through handler
|
26
|
-
def on_slim_output(
|
27
|
-
[:slim, :output,
|
26
|
+
def on_slim_output(escape, code, content)
|
27
|
+
[:slim, :output, escape, code, compile(content)]
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -45,6 +45,10 @@ module Slim
|
|
45
45
|
yield if !value || (value.respond_to?(:empty?) && value.empty?)
|
46
46
|
end
|
47
47
|
|
48
|
+
def to_s
|
49
|
+
scope.to_s
|
50
|
+
end
|
51
|
+
|
48
52
|
private
|
49
53
|
|
50
54
|
class Scope
|
@@ -89,6 +93,10 @@ module Slim
|
|
89
93
|
@parent[name] if @parent
|
90
94
|
end
|
91
95
|
|
96
|
+
def to_s
|
97
|
+
@dict.to_s
|
98
|
+
end
|
99
|
+
|
92
100
|
private
|
93
101
|
|
94
102
|
def has_key?(name)
|
@@ -12,17 +12,11 @@ module Slim
|
|
12
12
|
|
13
13
|
def initialize(opts = {})
|
14
14
|
super
|
15
|
-
access = options[:dictionary_access]
|
16
|
-
|
17
|
-
|
18
|
-
access = DEFAULT_ACCESS_ORDER
|
19
|
-
else
|
20
|
-
access = [access].flatten.compact
|
21
|
-
access.each do |type|
|
22
|
-
raise ArgumentError, "Invalid dictionary access #{type.inspect}" unless DEFAULT_ACCESS_ORDER.include?(type)
|
23
|
-
end
|
24
|
-
raise ArgumentError, 'Option dictionary access is missing' if access.empty?
|
15
|
+
access = [options[:dictionary_access]].flatten.compact
|
16
|
+
access.each do |type|
|
17
|
+
raise ArgumentError, "Invalid dictionary access #{type.inspect}" unless DEFAULT_ACCESS_ORDER.include?(type)
|
25
18
|
end
|
19
|
+
raise ArgumentError, 'Option dictionary access is missing' if access.empty?
|
26
20
|
@access = access.inspect
|
27
21
|
end
|
28
22
|
|
@@ -73,7 +67,14 @@ module Slim
|
|
73
67
|
private
|
74
68
|
|
75
69
|
def access(name)
|
76
|
-
|
70
|
+
case name
|
71
|
+
when 'yield'
|
72
|
+
'yield'
|
73
|
+
when 'self'
|
74
|
+
"#{@context}.to_s"
|
75
|
+
else
|
76
|
+
"#{@context}[#{name.to_sym.inspect}]"
|
77
|
+
end
|
77
78
|
end
|
78
79
|
end
|
79
80
|
end
|
data/lib/slim/parser.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
module Slim
|
2
3
|
# Parses Slim code and transforms it to a Temple expression
|
3
4
|
# @api private
|
4
5
|
class Parser < Temple::Parser
|
5
6
|
define_options :file,
|
6
7
|
:default_tag,
|
7
|
-
:escape_quoted_attrs,
|
8
8
|
:tabsize => 4,
|
9
|
-
:encoding => 'utf-8',
|
10
9
|
:shortcut => {
|
11
10
|
'#' => { :attr => 'id' },
|
12
11
|
'.' => { :attr => 'class' }
|
@@ -46,16 +45,15 @@ module Slim
|
|
46
45
|
end
|
47
46
|
@tag_shortcut, @attr_shortcut = {}, {}
|
48
47
|
options[:shortcut].each do |k,v|
|
49
|
-
v = deprecated_shortcut(v) if String === v
|
50
48
|
raise ArgumentError, 'Shortcut requires :tag and/or :attr' unless (v[:attr] || v[:tag]) && (v.keys - [:attr, :tag]).empty?
|
51
49
|
@tag_shortcut[k] = v[:tag] || options[:default_tag]
|
52
50
|
if v.include?(:attr)
|
53
51
|
@attr_shortcut[k] = v[:attr]
|
54
|
-
raise ArgumentError, 'You can only use special characters for attribute shortcuts' if k =~ /
|
52
|
+
raise ArgumentError, 'You can only use special characters for attribute shortcuts' if k =~ /(#{WORD_RE}|-)/
|
55
53
|
end
|
56
54
|
end
|
57
|
-
@
|
58
|
-
@
|
55
|
+
@attr_shortcut_re = /\A(#{Regexp.union @attr_shortcut.keys})(#{WORD_RE}(?:#{WORD_RE}|-)*#{WORD_RE}|#{WORD_RE}+)/
|
56
|
+
@tag_re = /\A(?:#{Regexp.union @tag_shortcut.keys}|\*(?=[^\s]+)|(#{WORD_RE}(?:#{WORD_RE}|:|-)*#{WORD_RE}|#{WORD_RE}+))/
|
59
57
|
end
|
60
58
|
|
61
59
|
# Compile string to Temple expression
|
@@ -63,8 +61,6 @@ module Slim
|
|
63
61
|
# @param [String] str Slim code
|
64
62
|
# @return [Array] Temple expression representing the code]]
|
65
63
|
def call(str)
|
66
|
-
str = remove_bom(set_encoding(str))
|
67
|
-
|
68
64
|
result = [:multi]
|
69
65
|
reset(str.split(/\r?\n/), [result])
|
70
66
|
|
@@ -76,57 +72,18 @@ module Slim
|
|
76
72
|
|
77
73
|
protected
|
78
74
|
|
79
|
-
|
75
|
+
DELIMS = {
|
80
76
|
'(' => ')',
|
81
77
|
'[' => ']',
|
82
78
|
'{' => '}',
|
83
79
|
}.freeze
|
84
80
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
CODE_ATTR_REGEX_20 = /#{ATTR_NAME}\s*=(=?)\s*/
|
92
|
-
|
93
|
-
# Convert deprecated string shortcut to hash
|
94
|
-
def deprecated_shortcut(v)
|
95
|
-
warn "Slim :shortcut string values are deprecated and unsupported in Slim 2.0, use hash like { '#' => { :tag => 'div', :attr => 'id' } }"
|
96
|
-
if v =~ /\A([^\s]+)\s+([^\s]+)\Z/
|
97
|
-
{ :tag => $1, :attr => $2 }
|
98
|
-
else
|
99
|
-
{ :attr => v }
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# Set string encoding if option is set
|
104
|
-
def set_encoding(s)
|
105
|
-
if options[:encoding] && s.respond_to?(:encoding)
|
106
|
-
old_enc = s.encoding
|
107
|
-
s = s.dup if s.frozen?
|
108
|
-
s.force_encoding(options[:encoding])
|
109
|
-
# Fall back to old encoding if new encoding is invalid
|
110
|
-
unless s.valid_encoding?
|
111
|
-
s.force_encoding(old_enc)
|
112
|
-
s.force_encoding(Encoding::BINARY) unless s.valid_encoding?
|
113
|
-
end
|
114
|
-
end
|
115
|
-
s
|
116
|
-
end
|
117
|
-
|
118
|
-
# Remove unicode byte order mark from string
|
119
|
-
def remove_bom(s)
|
120
|
-
if s.respond_to?(:encoding)
|
121
|
-
if s.encoding.name =~ /^UTF-(8|16|32)(BE|LE)?/
|
122
|
-
s.gsub(Regexp.new("\\A\uFEFF".encode(s.encoding.name)), '')
|
123
|
-
else
|
124
|
-
s
|
125
|
-
end
|
126
|
-
else
|
127
|
-
s.gsub(/\A\xEF\xBB\xBF/, '')
|
128
|
-
end
|
129
|
-
end
|
81
|
+
WORD_RE = ''.respond_to?(:encoding) ? '\p{Word}' : '\w'
|
82
|
+
DELIM_RE = /\A[#{Regexp.escape DELIMS.keys.join}]/
|
83
|
+
ATTR_DELIM_RE = /\A\s*([#{Regexp.escape DELIMS.keys.join}])/
|
84
|
+
ATTR_NAME = "\\A\\s*(#{WORD_RE}(?:#{WORD_RE}|:|-)*)"
|
85
|
+
QUOTED_ATTR_RE = /#{ATTR_NAME}\s*=(=?)\s*("|')/
|
86
|
+
CODE_ATTR_RE = /#{ATTR_NAME}\s*=(=?)\s*/
|
130
87
|
|
131
88
|
def reset(lines = nil, stacks = nil)
|
132
89
|
# Since you can indent however you like in Slim, we need to keep a list
|
@@ -237,7 +194,6 @@ module Slim
|
|
237
194
|
@stacks.last << [:static, ' '] if trailing_ws
|
238
195
|
when /\A</
|
239
196
|
# Inline html
|
240
|
-
# @stacks.last << parse_text_block(@line, @indents.last + 1)
|
241
197
|
block = [:multi]
|
242
198
|
@stacks.last << [:multi, [:slim, :interpolate, @line], block]
|
243
199
|
@stacks << block
|
@@ -248,14 +204,15 @@ module Slim
|
|
248
204
|
block = [:multi]
|
249
205
|
@stacks.last << [:slim, :control, parse_broken_line, block]
|
250
206
|
@stacks << block
|
251
|
-
when /\A
|
207
|
+
when /\A=(=?)(['<>]*)/
|
252
208
|
# Found an output block.
|
253
209
|
# We expect the line to be broken or the next line to be indented.
|
254
|
-
@line =~ /\A=(=?)('?)/
|
255
210
|
@line = $'
|
211
|
+
trailing_ws = $2.include?('\'') || $2.include?('>')
|
256
212
|
block = [:multi]
|
213
|
+
@stacks.last << [:static, ' '] if $2.include?('<')
|
257
214
|
@stacks.last << [:slim, :output, $1.empty?, parse_broken_line, block]
|
258
|
-
@stacks.last << [:static, ' ']
|
215
|
+
@stacks.last << [:static, ' '] if trailing_ws
|
259
216
|
@stacks << block
|
260
217
|
when /\A(\w+):\s*\Z/
|
261
218
|
# Embedded template detected. It is treated as block.
|
@@ -263,7 +220,7 @@ module Slim
|
|
263
220
|
when /\Adoctype\s+/i
|
264
221
|
# Found doctype declaration
|
265
222
|
@stacks.last << [:html, :doctype, $'.strip]
|
266
|
-
when @
|
223
|
+
when @tag_re
|
267
224
|
# Found a HTML tag.
|
268
225
|
@line = $' if $1
|
269
226
|
parse_tag($&)
|
@@ -340,14 +297,33 @@ module Slim
|
|
340
297
|
tag = @tag_shortcut[tag]
|
341
298
|
end
|
342
299
|
|
343
|
-
|
300
|
+
# Find any shortcut attributes
|
301
|
+
attributes = [:html, :attrs]
|
302
|
+
while @line =~ @attr_shortcut_re
|
303
|
+
# The class/id attribute is :static instead of :slim :interpolate,
|
304
|
+
# because we don't want text interpolation in .class or #id shortcut
|
305
|
+
attributes << [:html, :attr, @attr_shortcut[$1], [:static, $2]]
|
306
|
+
@line = $'
|
307
|
+
end
|
308
|
+
|
309
|
+
@line =~ /\A[<>']*/
|
310
|
+
@line = $'
|
311
|
+
trailing_ws = $&.include?('\'') || $&.include?('>')
|
312
|
+
leading_ws = $&.include?('<')
|
313
|
+
|
314
|
+
parse_attributes(attributes)
|
315
|
+
|
316
|
+
tag = [:html, :tag, tag, attributes]
|
317
|
+
|
318
|
+
@stacks.last << [:static, ' '] if leading_ws
|
344
319
|
@stacks.last << tag
|
320
|
+
@stacks.last << [:static, ' '] if trailing_ws
|
345
321
|
|
346
322
|
case @line
|
347
323
|
when /\A\s*:\s*/
|
348
324
|
# Block expansion
|
349
325
|
@line = $'
|
350
|
-
(@line =~ @
|
326
|
+
(@line =~ @tag_re) || syntax_error!('Expected tag')
|
351
327
|
@line = $' if $1
|
352
328
|
content = [:multi]
|
353
329
|
tag << content
|
@@ -355,12 +331,14 @@ module Slim
|
|
355
331
|
@stacks << content
|
356
332
|
parse_tag($&)
|
357
333
|
@stacks.delete_at(i)
|
358
|
-
when /\A\s*=(=?)('
|
334
|
+
when /\A\s*=(=?)(['<>]*)/
|
359
335
|
# Handle output code
|
360
336
|
@line = $'
|
337
|
+
trailing_ws2 = $2.include?('\'') || $2.include?('>')
|
361
338
|
block = [:multi]
|
339
|
+
@stacks.last << [:static, ' '] if !leading_ws && $2.include?('<')
|
362
340
|
tag << [:slim, :output, $1 != '=', parse_broken_line, block]
|
363
|
-
@stacks.last << [:static, ' ']
|
341
|
+
@stacks.last << [:static, ' '] if !trailing_ws && trailing_ws2
|
364
342
|
@stacks << block
|
365
343
|
when /\A\s*\/\s*/
|
366
344
|
# Closed tag. Do nothing
|
@@ -377,31 +355,17 @@ module Slim
|
|
377
355
|
end
|
378
356
|
end
|
379
357
|
|
380
|
-
def parse_attributes
|
381
|
-
attributes = [:html, :attrs]
|
382
|
-
|
383
|
-
# Find any shortcut attributes
|
384
|
-
while @line =~ @attr_shortcut_regex
|
385
|
-
# The class/id attribute is :static instead of :slim :interpolate,
|
386
|
-
# because we don't want text interpolation in .class or #id shortcut
|
387
|
-
attributes << [:html, :attr, @attr_shortcut[$1], [:static, $2]]
|
388
|
-
@line = $'
|
389
|
-
end
|
390
|
-
|
358
|
+
def parse_attributes(attributes)
|
391
359
|
# Check to see if there is a delimiter right after the tag name
|
392
360
|
delimiter = nil
|
393
|
-
if @line =~
|
394
|
-
|
395
|
-
|
396
|
-
else
|
397
|
-
delimiter = DELIMITERS[$&]
|
398
|
-
@line.slice!(0)
|
399
|
-
end
|
361
|
+
if @line =~ ATTR_DELIM_RE
|
362
|
+
delimiter = DELIMS[$1]
|
363
|
+
@line = $'
|
400
364
|
end
|
401
365
|
|
402
366
|
if delimiter
|
403
|
-
|
404
|
-
|
367
|
+
boolean_attr_re = /#{ATTR_NAME}(?=(\s|#{Regexp.escape delimiter}|\Z))/
|
368
|
+
end_re = /\A\s*#{Regexp.escape delimiter}/
|
405
369
|
end
|
406
370
|
|
407
371
|
while true
|
@@ -410,46 +374,28 @@ module Slim
|
|
410
374
|
# Splat attribute
|
411
375
|
@line = $'
|
412
376
|
attributes << [:slim, :splat, parse_ruby_code(delimiter)]
|
413
|
-
when
|
377
|
+
when QUOTED_ATTR_RE
|
414
378
|
# Value is quoted (static)
|
415
379
|
@line = $'
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
value = parse_quoted_attribute(quote)
|
420
|
-
if escape && !options[:escape_quoted_attrs] && value =~ /&(amp|quot|gt|lt);/
|
421
|
-
warn "#{options[:file]}:#{@lineno} - quoted attribute value '#{value}' might be double escaped in Slim 2.0. Remove manually escaped entities and set :escape_quoted_attrs => true! :escaped_quoted_attrs is activated on Slim 2.0 by default."
|
422
|
-
end
|
423
|
-
attributes << [:html, :attr, name,
|
424
|
-
[:escape, options[:escape_quoted_attrs] && escape,
|
425
|
-
[:slim, :interpolate, value]]]
|
426
|
-
when CODE_ATTR_REGEX
|
380
|
+
attributes << [:html, :attr, $1,
|
381
|
+
[:escape, $2.empty?, [:slim, :interpolate, parse_quoted_attribute($3)]]]
|
382
|
+
when CODE_ATTR_RE
|
427
383
|
# Value is ruby code
|
428
384
|
@line = $'
|
429
385
|
name = $1
|
430
386
|
escape = $2.empty?
|
431
387
|
value = parse_ruby_code(delimiter)
|
432
|
-
# Remove attribute wrapper which doesn't belong to the ruby code
|
433
|
-
# e.g id=[hash[:a] + hash[:b]]
|
434
|
-
if value =~ /\A[\[\{]/ && DELIMITERS[$&] == value[-1, 1]
|
435
|
-
warn "#{options[:file]}:#{@lineno} - ruby attribute value #{value} with curly braces/brackets is deprecated and unsupported in Slim 2.0. Use parentheses!"
|
436
|
-
value = value[1..-2]
|
437
|
-
end
|
438
388
|
syntax_error!('Invalid empty attribute') if value.empty?
|
439
389
|
attributes << [:html, :attr, name, [:slim, :attrvalue, escape, value]]
|
440
390
|
else
|
441
|
-
if @line =~ QUOTED_ATTR_REGEX_20 || @line =~ CODE_ATTR_REGEX_20
|
442
|
-
warn "#{options[:file]}:#{@lineno} - you have spaces around =, this will be interpreted as attribute in Slim 2.0."
|
443
|
-
end
|
444
|
-
|
445
391
|
break unless delimiter
|
446
392
|
|
447
393
|
case @line
|
448
|
-
when
|
394
|
+
when boolean_attr_re
|
449
395
|
# Boolean attribute
|
450
396
|
@line = $'
|
451
397
|
attributes << [:html, :attr, $1, [:slim, :attrvalue, false, 'true']]
|
452
|
-
when
|
398
|
+
when end_re
|
453
399
|
# Find ending delimiter
|
454
400
|
@line = $'
|
455
401
|
break
|
@@ -465,17 +411,15 @@ module Slim
|
|
465
411
|
end
|
466
412
|
end
|
467
413
|
end
|
468
|
-
|
469
|
-
attributes
|
470
414
|
end
|
471
415
|
|
472
416
|
def parse_ruby_code(outer_delimiter)
|
473
417
|
code, count, delimiter, close_delimiter = '', 0, nil, nil
|
474
418
|
|
475
419
|
# Attribute ends with space or attribute delimiter
|
476
|
-
|
420
|
+
end_re = /\A[\s#{Regexp.escape outer_delimiter.to_s}]/
|
477
421
|
|
478
|
-
until @line.empty? || (count == 0 && @line =~
|
422
|
+
until @line.empty? || (count == 0 && @line =~ end_re)
|
479
423
|
if @line =~ /\A[,\\]\Z/
|
480
424
|
code << @line << "\n"
|
481
425
|
expect_next_line
|
@@ -486,9 +430,9 @@ module Slim
|
|
486
430
|
elsif @line[0] == close_delimiter[0]
|
487
431
|
count -= 1
|
488
432
|
end
|
489
|
-
elsif @line =~
|
433
|
+
elsif @line =~ DELIM_RE
|
490
434
|
count = 1
|
491
|
-
delimiter, close_delimiter = $&,
|
435
|
+
delimiter, close_delimiter = $&, DELIMS[$&]
|
492
436
|
end
|
493
437
|
code << @line.slice!(0)
|
494
438
|
end
|