slim 1.3.9 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|