slim 4.1.0 → 5.2.1
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/.github/workflows/test.yml +107 -0
- data/.yardopts +1 -1
- data/CHANGES +44 -8
- data/Gemfile +18 -45
- data/LICENSE +1 -1
- data/README.jp.md +28 -41
- data/README.md +66 -43
- data/Rakefile +2 -9
- data/doc/jp/translator.md +1 -1
- data/doc/logic_less.md +1 -1
- data/doc/translator.md +1 -1
- data/lib/slim/code_attributes.rb +2 -1
- data/lib/slim/command.rb +2 -8
- data/lib/slim/controls.rb +1 -0
- data/lib/slim/do_inserter.rb +4 -3
- data/lib/slim/embedded.rb +17 -17
- data/lib/slim/end_inserter.rb +3 -2
- data/lib/slim/engine.rb +3 -0
- data/lib/slim/erb_converter.rb +1 -0
- data/lib/slim/filter.rb +1 -0
- data/lib/slim/grammar.rb +1 -0
- data/lib/slim/include.rb +1 -0
- data/lib/slim/interpolation.rb +1 -0
- data/lib/slim/logic_less/context.rb +6 -7
- data/lib/slim/logic_less/filter.rb +1 -0
- data/lib/slim/logic_less.rb +1 -0
- data/lib/slim/parser.rb +26 -39
- data/lib/slim/railtie.rb +19 -0
- data/lib/slim/smart/escaper.rb +1 -1
- data/lib/slim/smart/filter.rb +3 -2
- data/lib/slim/smart/parser.rb +4 -3
- data/lib/slim/smart.rb +1 -0
- data/lib/slim/splat/builder.rb +16 -8
- data/lib/slim/splat/filter.rb +6 -4
- data/lib/slim/template.rb +1 -14
- data/lib/slim/translator.rb +4 -3
- data/lib/slim/version.rb +2 -1
- data/lib/slim.rb +2 -0
- data/slim.gemspec +14 -5
- data/test/core/helper.rb +3 -11
- data/test/core/test_code_evaluation.rb +1 -0
- data/test/core/test_code_structure.rb +17 -0
- data/test/core/test_commands.rb +19 -22
- data/test/core/test_embedded_engines.rb +18 -14
- data/test/core/test_encoding.rb +2 -2
- data/test/core/test_erb_converter.rb +4 -6
- data/test/core/test_html_attributes.rb +8 -0
- data/test/core/test_html_structure.rb +54 -0
- data/test/core/test_pretty.rb +4 -7
- data/test/core/test_ruby_errors.rb +19 -0
- data/test/literate/TESTS.md +72 -22
- data/test/literate/helper.rb +1 -1
- data/test/literate/run.rb +3 -3
- data/test/logic_less/test_logic_less.rb +15 -0
- data/test/rails/app/controllers/slim_controller.rb +7 -1
- data/test/rails/app/views/layouts/application.html+testvariant.slim +10 -0
- data/test/rails/app/views/slim/attributes.html.slim +3 -0
- data/test/rails/app/views/slim/splat_with_delimiter.slim +1 -0
- data/test/rails/config/application.rb +1 -18
- data/test/rails/test/test_slim.rb +24 -12
- data/test/sinatra/helper.rb +0 -2
- metadata +27 -37
- data/.travis.yml +0 -38
- data/benchmarks/context.rb +0 -11
- data/benchmarks/profile-parser.rb +0 -10
- data/benchmarks/profile-render.rb +0 -12
- data/benchmarks/run-benchmarks.rb +0 -120
- data/benchmarks/run-diffbench.rb +0 -21
- data/benchmarks/view.erb +0 -25
- data/benchmarks/view.haml +0 -20
- data/benchmarks/view.slim +0 -19
- data/test/rails/config/initializers/secret_token.rb +0 -7
data/lib/slim/parser.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Slim
|
2
3
|
# Parses Slim code and transforms it to a Temple expression
|
3
4
|
# @api private
|
@@ -49,7 +50,7 @@ module Slim
|
|
49
50
|
@code_attr_delims = options[:code_attr_delims]
|
50
51
|
tabsize = options[:tabsize]
|
51
52
|
if tabsize > 1
|
52
|
-
@tab_re = /\G((?: {#{tabsize}})*) {0,#{tabsize-1}}\t/
|
53
|
+
@tab_re = /\G((?: {#{tabsize}})*) {0,#{tabsize - 1}}\t/
|
53
54
|
@tab = '\1' + ' ' * tabsize
|
54
55
|
else
|
55
56
|
@tab_re = "\t"
|
@@ -63,15 +64,15 @@ module Slim
|
|
63
64
|
raise ArgumentError, 'You can only use special characters for attribute shortcuts' if k =~ /(\p{Word}|-)/
|
64
65
|
end
|
65
66
|
if v.include?(:attr)
|
66
|
-
@attr_shortcut[k] = [v[:attr]].flatten
|
67
|
+
@attr_shortcut[k] = v[:attr].is_a?(Proc) ? v[:attr] : [v[:attr]].flatten
|
67
68
|
end
|
68
69
|
if v.include?(:additional_attrs)
|
69
70
|
@additional_attrs[k] = v[:additional_attrs]
|
70
71
|
end
|
71
72
|
end
|
72
|
-
keys = Regexp.union @attr_shortcut.keys.sort_by {|k| -k.size }
|
73
|
+
keys = Regexp.union @attr_shortcut.keys.sort_by { |k| -k.size }
|
73
74
|
@attr_shortcut_re = /\A(#{keys}+)((?:\p{Word}|-|\/\d+|:(\w|-)+)*)/
|
74
|
-
keys = Regexp.union @tag_shortcut.keys.sort_by {|k| -k.size }
|
75
|
+
keys = Regexp.union @tag_shortcut.keys.sort_by { |k| -k.size }
|
75
76
|
@tag_re = /\A(?:#{keys}|\*(?=[^\s]+)|(\p{Word}(?:\p{Word}|:|-)*\p{Word}|\p{Word}+))/
|
76
77
|
keys = Regexp.escape @code_attr_delims.keys.join
|
77
78
|
@code_attr_delims_re = /\A[#{keys}]/
|
@@ -79,12 +80,12 @@ module Slim
|
|
79
80
|
@attr_list_delims_re = /\A\s*([#{keys}])/
|
80
81
|
@embedded_re = /\A(#{Regexp.union(Embedded.engines.keys.map(&:to_s))})(?:\s*(?:(.*)))?:(\s*)/
|
81
82
|
keys = Regexp.escape ('"\'></='.split(//) + @attr_list_delims.flatten + @code_attr_delims.flatten).uniq.join
|
82
|
-
@attr_name = "\\A\\s*([
|
83
|
+
@attr_name = "\\A\\s*([^\\0\\s#{keys}]+)"
|
83
84
|
@quoted_attr_re = /#{@attr_name}\s*=(=?)\s*("|')/
|
84
85
|
@code_attr_re = /#{@attr_name}\s*=(=?)\s*/
|
85
86
|
|
86
87
|
splat_prefix = Regexp.escape(options[:splat_prefix])
|
87
|
-
splat_regexp_source = '\A\s*'
|
88
|
+
splat_regexp_source = '\A\s*' + splat_prefix + '(?=[^\s]+)'
|
88
89
|
@splat_attrs_regexp = Regexp.new(splat_regexp_source)
|
89
90
|
end
|
90
91
|
|
@@ -209,10 +210,12 @@ module Slim
|
|
209
210
|
when /\A\//
|
210
211
|
# Slim comment
|
211
212
|
parse_comment_block
|
212
|
-
when /\A([\|'])( ?)/
|
213
|
+
when /\A([\|'])([<>]{1,2}(?: |\z)| ?)/
|
213
214
|
# Found verbatim text block.
|
214
|
-
|
215
|
-
|
215
|
+
leading_ws = $2.include?('<'.freeze)
|
216
|
+
trailing_ws = ($1 == "'") || $2.include?('>'.freeze)
|
217
|
+
@stacks.last << [:static, ' '] if leading_ws
|
218
|
+
@stacks.last << [:slim, :text, :verbatim, parse_text_block($', @indents.last + $2.count(' ') + 1)]
|
216
219
|
@stacks.last << [:static, ' '] if trailing_ws
|
217
220
|
when /\A</
|
218
221
|
# Inline html
|
@@ -226,17 +229,14 @@ module Slim
|
|
226
229
|
block = [:multi]
|
227
230
|
@stacks.last << [:slim, :control, parse_broken_line, block]
|
228
231
|
@stacks << block
|
229
|
-
when /\A=(=?)([
|
232
|
+
when /\A=(=?)([<>]*)/
|
230
233
|
# Found an output block.
|
231
234
|
# We expect the line to be broken or the next line to be indented.
|
232
235
|
@line = $'
|
236
|
+
leading_ws = $2.include?('<'.freeze)
|
233
237
|
trailing_ws = $2.include?('>'.freeze)
|
234
|
-
if $2.include?('\''.freeze)
|
235
|
-
deprecated_syntax '=\' for trailing whitespace is deprecated in favor of =>'
|
236
|
-
trailing_ws = true
|
237
|
-
end
|
238
238
|
block = [:multi]
|
239
|
-
@stacks.last << [:static, ' '] if
|
239
|
+
@stacks.last << [:static, ' '] if leading_ws
|
240
240
|
@stacks.last << [:slim, :output, $1.empty?, parse_broken_line, block]
|
241
241
|
@stacks.last << [:static, ' '] if trailing_ws
|
242
242
|
@stacks << block
|
@@ -336,7 +336,13 @@ module Slim
|
|
336
336
|
# The class/id attribute is :static instead of :slim :interpolate,
|
337
337
|
# because we don't want text interpolation in .class or #id shortcut
|
338
338
|
syntax_error!('Illegal shortcut') unless shortcut = @attr_shortcut[$1]
|
339
|
-
|
339
|
+
|
340
|
+
if shortcut.is_a?(Proc)
|
341
|
+
shortcut.call($2).each { |a, v| attributes << [:html, :attr, a, [:static, v]] }
|
342
|
+
else
|
343
|
+
shortcut.each {|a| attributes << [:html, :attr, a, [:static, $2]] }
|
344
|
+
end
|
345
|
+
|
340
346
|
if additional_attr_pairs = @additional_attrs[$1]
|
341
347
|
additional_attr_pairs.each do |k,v|
|
342
348
|
attributes << [:html, :attr, k.to_s, [:static, v]]
|
@@ -348,11 +354,6 @@ module Slim
|
|
348
354
|
@line =~ /\A[<>']*/
|
349
355
|
@line = $'
|
350
356
|
trailing_ws = $&.include?('>'.freeze)
|
351
|
-
if $&.include?('\''.freeze)
|
352
|
-
deprecated_syntax 'tag\' for trailing whitespace is deprecated in favor of tag>'
|
353
|
-
trailing_ws = true
|
354
|
-
end
|
355
|
-
|
356
357
|
leading_ws = $&.include?('<'.freeze)
|
357
358
|
|
358
359
|
parse_attributes(attributes)
|
@@ -387,10 +388,6 @@ module Slim
|
|
387
388
|
# Handle output code
|
388
389
|
@line = $'
|
389
390
|
trailing_ws2 = $2.include?('>'.freeze)
|
390
|
-
if $2.include?('\''.freeze)
|
391
|
-
deprecated_syntax '=\' for trailing whitespace is deprecated in favor of =>'
|
392
|
-
trailing_ws2 = true
|
393
|
-
end
|
394
391
|
block = [:multi]
|
395
392
|
@stacks.last.insert(-2, [:static, ' ']) if !leading_ws && $2.include?('<'.freeze)
|
396
393
|
tag << [:slim, :output, $1 != '=', parse_broken_line, block]
|
@@ -471,7 +468,7 @@ module Slim
|
|
471
468
|
end
|
472
469
|
|
473
470
|
def parse_ruby_code(outer_delimiter)
|
474
|
-
code, count, delimiter, close_delimiter = '', 0, nil, nil
|
471
|
+
code, count, delimiter, close_delimiter = ''.dup, 0, nil, nil
|
475
472
|
|
476
473
|
# Attribute ends with space or attribute delimiter
|
477
474
|
end_re = /\A[\s#{Regexp.escape outer_delimiter.to_s}]/
|
@@ -499,16 +496,16 @@ module Slim
|
|
499
496
|
end
|
500
497
|
|
501
498
|
def parse_quoted_attribute(quote)
|
502
|
-
value, count = '', 0
|
499
|
+
value, count = ''.dup, 0
|
503
500
|
|
504
501
|
until count == 0 && @line[0] == quote[0]
|
505
502
|
if @line =~ /\A(\\)?\Z/
|
506
503
|
value << ($1 ? ' ' : "\n")
|
507
504
|
expect_next_line
|
508
505
|
else
|
509
|
-
if @line[0] ==
|
506
|
+
if @line[0] == '{'
|
510
507
|
count += 1
|
511
|
-
elsif @line[0] ==
|
508
|
+
elsif @line[0] == '}'
|
512
509
|
count -= 1
|
513
510
|
end
|
514
511
|
value << @line.slice!(0)
|
@@ -530,16 +527,6 @@ module Slim
|
|
530
527
|
raise
|
531
528
|
end
|
532
529
|
|
533
|
-
def deprecated_syntax(message)
|
534
|
-
line = @orig_line.lstrip
|
535
|
-
column = (@orig_line && @line ? @orig_line.size - @line.size : 0) + line.size - @orig_line.size
|
536
|
-
warn %{Deprecated syntax: #{message}
|
537
|
-
#{options[:file]}, Line #{@lineno}, Column #{column + 1}
|
538
|
-
#{line}
|
539
|
-
#{' ' * column}^
|
540
|
-
}
|
541
|
-
end
|
542
|
-
|
543
530
|
def expect_next_line
|
544
531
|
next_line || syntax_error!('Unexpected end of file')
|
545
532
|
@line.strip!
|
data/lib/slim/railtie.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slim
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
initializer 'initialize slim template handler' do
|
6
|
+
ActiveSupport.on_load(:action_view) do
|
7
|
+
Slim::RailsTemplate = Temple::Templates::Rails(Slim::Engine,
|
8
|
+
register_as: :slim,
|
9
|
+
# Use rails-specific generator. This is necessary
|
10
|
+
# to support block capturing and streaming.
|
11
|
+
generator: Temple::Generators::RailsOutputBuffer,
|
12
|
+
# Disable the internal slim capturing.
|
13
|
+
# Rails takes care of the capturing by itself.
|
14
|
+
disable_capture: true,
|
15
|
+
streaming: true)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/slim/smart/escaper.rb
CHANGED
data/lib/slim/smart/filter.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Slim
|
2
3
|
module Smart
|
3
4
|
# Perform newline processing in the
|
@@ -50,13 +51,13 @@ module Slim
|
|
50
51
|
# so we don't have to worry about that at all.
|
51
52
|
block = [:multi]
|
52
53
|
prev = nil
|
53
|
-
last_exp = exps.reject{ |exp| exp.first == :newline }.last unless @active && @append
|
54
|
+
last_exp = exps.reject { |exp| exp.first == :newline }.last unless @active && @append
|
54
55
|
exps.each do |exp|
|
55
56
|
@append = exp.equal?(last_exp)
|
56
57
|
if @active
|
57
58
|
@prepend = false if prev
|
58
59
|
else
|
59
|
-
@prepend = prev && (
|
60
|
+
@prepend = prev && (prev.first != :slim || prev[1] != :text)
|
60
61
|
end
|
61
62
|
block << compile(exp)
|
62
63
|
prev = exp unless exp.first == :newline
|
data/lib/slim/smart/parser.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Slim
|
2
3
|
module Smart
|
3
4
|
# @api private
|
@@ -7,9 +8,9 @@ module Slim
|
|
7
8
|
def initialize(opts = {})
|
8
9
|
super
|
9
10
|
word_re = options[:implicit_text] ? '[_a-z0-9]' : '\p{Word}'
|
10
|
-
attr_keys = Regexp.union(@attr_shortcut.keys.sort_by {|k| -k.size }
|
11
|
+
attr_keys = Regexp.union(@attr_shortcut.keys.sort_by { |k| -k.size })
|
11
12
|
@attr_shortcut_re = /\A(#{attr_keys}+)((?:\p{Word}|-)*)/
|
12
|
-
tag_keys = Regexp.union((@tag_shortcut.keys - @attr_shortcut.keys).sort_by {|k| -k.size }
|
13
|
+
tag_keys = Regexp.union((@tag_shortcut.keys - @attr_shortcut.keys).sort_by { |k| -k.size })
|
13
14
|
@tag_re = /\A(?:#{attr_keys}(?=-*\p{Word})|#{tag_keys}|\*(?=[^\s]+)|(#{word_re}(?:#{word_re}|:|-)*#{word_re}|#{word_re}+))/
|
14
15
|
end
|
15
16
|
|
@@ -24,7 +25,7 @@ module Slim
|
|
24
25
|
end
|
25
26
|
# Found implicit smart text block.
|
26
27
|
if line = @lines.first
|
27
|
-
indent = (
|
28
|
+
indent = (line =~ /\A\s*\Z/ ? @indents.last + 1 : get_indent(line))
|
28
29
|
end
|
29
30
|
@stacks.last << [:slim, :text, :implicit, parse_text_block(@line, indent)]
|
30
31
|
end
|
data/lib/slim/smart.rb
CHANGED
data/lib/slim/splat/builder.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Slim
|
2
3
|
class InvalidAttributeNameError < StandardError; end
|
3
4
|
module Splat
|
4
5
|
# @api private
|
5
6
|
class Builder
|
6
|
-
|
7
|
-
|
7
|
+
# https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
8
|
+
INVALID_ATTRIBUTE_NAME_REGEX = /[ \0"'>\/=]/
|
9
|
+
|
8
10
|
def initialize(options)
|
9
11
|
@options = options
|
10
12
|
@attrs = {}
|
@@ -17,7 +19,7 @@ module Slim
|
|
17
19
|
elsif @options[:hyphen_attrs].include?(name) && Hash === value
|
18
20
|
hyphen_attr(name, escape, value)
|
19
21
|
elsif value != false && value != nil
|
20
|
-
attr(name, escape_html(
|
22
|
+
attr(name, escape_html(escape, value))
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -33,7 +35,7 @@ module Slim
|
|
33
35
|
end
|
34
36
|
if @attrs[name]
|
35
37
|
if delim = @options[:merge_attrs][name]
|
36
|
-
@attrs[name]
|
38
|
+
@attrs[name] = @attrs[name].to_s + delim + value.to_s
|
37
39
|
else
|
38
40
|
raise("Multiple #{name} attributes specified")
|
39
41
|
end
|
@@ -90,16 +92,22 @@ module Slim
|
|
90
92
|
|
91
93
|
def hyphen_attr(name, escape, value)
|
92
94
|
if Hash === value
|
93
|
-
|
94
|
-
|
95
|
+
if @options[:hyphen_underscore_attrs]
|
96
|
+
value.each do |n, v|
|
97
|
+
hyphen_attr("#{name}-#{n.to_s.tr('_', '-')}", escape, v)
|
98
|
+
end
|
99
|
+
else
|
100
|
+
value.each do |n, v|
|
101
|
+
hyphen_attr("#{name}-#{n}", escape, v)
|
102
|
+
end
|
95
103
|
end
|
96
104
|
else
|
97
|
-
attr(name, escape_html(
|
105
|
+
attr(name, escape_html(escape, value))
|
98
106
|
end
|
99
107
|
end
|
100
108
|
|
101
109
|
def escape_html(escape, value)
|
102
|
-
return value
|
110
|
+
return value if !escape || value == true
|
103
111
|
@options[:use_html_safe] ? Temple::Utils.escape_html_safe(value) : Temple::Utils.escape_html(value)
|
104
112
|
end
|
105
113
|
end
|
data/lib/slim/splat/filter.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Slim
|
2
3
|
module Splat
|
3
4
|
# @api private
|
4
5
|
class Filter < ::Slim::Filter
|
5
6
|
define_options :merge_attrs, :attr_quote, :sort_attrs, :default_tag, :format, :disable_capture,
|
6
|
-
hyphen_attrs: %w(data aria), use_html_safe: ''.respond_to?(:html_safe?)
|
7
|
+
hyphen_attrs: %w(data aria), use_html_safe: ''.respond_to?(:html_safe?),
|
8
|
+
hyphen_underscore_attrs: false
|
7
9
|
|
8
10
|
def call(exp)
|
9
11
|
@splat_options = nil
|
10
12
|
exp = compile(exp)
|
11
13
|
if @splat_options
|
12
|
-
opts = options.to_hash.reject {|k,v| !Filter.options.valid_key?(k) }.inspect
|
14
|
+
opts = options.to_hash.reject { |k, v| !Filter.options.valid_key?(k) }.inspect
|
13
15
|
[:multi, [:code, "#{@splat_options} = #{opts}"], exp]
|
14
16
|
else
|
15
17
|
exp
|
@@ -43,7 +45,7 @@ module Slim
|
|
43
45
|
# @param [Array] attrs Array of temple expressions
|
44
46
|
# @return [Array] Compiled temple expression
|
45
47
|
def on_html_attrs(*attrs)
|
46
|
-
if attrs.any? {|attr| splat?(attr) }
|
48
|
+
if attrs.any? { |attr| splat?(attr) }
|
47
49
|
builder, block = make_builder(attrs)
|
48
50
|
[:multi,
|
49
51
|
block,
|
@@ -84,7 +86,7 @@ module Slim
|
|
84
86
|
attr
|
85
87
|
end
|
86
88
|
end
|
87
|
-
|
89
|
+
[builder, result]
|
88
90
|
end
|
89
91
|
end
|
90
92
|
end
|
data/lib/slim/template.rb
CHANGED
@@ -1,19 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Slim
|
2
3
|
# Tilt template implementation for Slim
|
3
4
|
# @api public
|
4
5
|
Template = Temple::Templates::Tilt(Slim::Engine, register_as: :slim)
|
5
|
-
|
6
|
-
if defined?(::ActionView)
|
7
|
-
# Rails template implementation for Slim
|
8
|
-
# @api public
|
9
|
-
RailsTemplate = Temple::Templates::Rails(Slim::Engine,
|
10
|
-
register_as: :slim,
|
11
|
-
# Use rails-specific generator. This is necessary
|
12
|
-
# to support block capturing and streaming.
|
13
|
-
generator: Temple::Generators::RailsOutputBuffer,
|
14
|
-
# Disable the internal slim capturing.
|
15
|
-
# Rails takes care of the capturing by itself.
|
16
|
-
disable_capture: true,
|
17
|
-
streaming: true)
|
18
|
-
end
|
19
6
|
end
|
data/lib/slim/translator.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'slim'
|
2
3
|
|
3
4
|
module Slim
|
@@ -62,7 +63,7 @@ module Slim
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def call(exp)
|
65
|
-
@text, @captures = '', []
|
66
|
+
@text, @captures = ''.dup, []
|
66
67
|
result = compile(exp)
|
67
68
|
|
68
69
|
text = @translate.call(@text)
|
@@ -89,7 +90,7 @@ module Slim
|
|
89
90
|
define_options :tr_fn
|
90
91
|
|
91
92
|
def call(exp)
|
92
|
-
@captures_count, @captures_var, @text = 0, unique_name, ''
|
93
|
+
@captures_count, @captures_var, @text = 0, unique_name, ''.dup
|
93
94
|
|
94
95
|
result = compile(exp)
|
95
96
|
|
@@ -109,7 +110,7 @@ module Slim
|
|
109
110
|
def on_slim_output(escape, code, content)
|
110
111
|
@captures_count += 1
|
111
112
|
@text << "%#{@captures_count}"
|
112
|
-
[:capture, "#{@captures_var}[#{@captures_count-1}]", [:slim, :output, escape, code, content]]
|
113
|
+
[:capture, "#{@captures_var}[#{@captures_count - 1}]", [:slim, :output, escape, code, content]]
|
113
114
|
end
|
114
115
|
end
|
115
116
|
end
|
data/lib/slim/version.rb
CHANGED
data/lib/slim.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'temple'
|
2
3
|
require 'slim/parser'
|
3
4
|
require 'slim/filter'
|
@@ -12,3 +13,4 @@ require 'slim/code_attributes'
|
|
12
13
|
require 'slim/engine'
|
13
14
|
require 'slim/template'
|
14
15
|
require 'slim/version'
|
16
|
+
require 'slim/railtie' if defined?(Rails::Railtie)
|
data/slim.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
require File.dirname(__FILE__) + '/lib/slim/version'
|
3
2
|
require 'date'
|
4
3
|
|
@@ -10,15 +9,25 @@ Gem::Specification.new do |s|
|
|
10
9
|
s.email = ['mail@daniel-mendler.de', 'andy@stonean.com', 'ifredwu@gmail.com']
|
11
10
|
s.summary = 'Slim is a template language.'
|
12
11
|
s.description = 'Slim is a template language whose goal is reduce the syntax to the essential parts without becoming cryptic.'
|
13
|
-
s.homepage = '
|
12
|
+
s.homepage = 'https://slim-template.github.io/'
|
14
13
|
s.license = 'MIT'
|
15
14
|
|
15
|
+
s.metadata = {
|
16
|
+
"bug_tracker_uri" => "https://github.com/slim-template/slim/issues",
|
17
|
+
"changelog_uri" => "https://github.com/slim-template/slim/blob/main/CHANGES",
|
18
|
+
"documentation_uri" => "https://rubydoc.info/gems/slim/frames",
|
19
|
+
"homepage_uri" => "https://slim-template.github.io/",
|
20
|
+
"source_code_uri" => "https://github.com/slim-template/slim",
|
21
|
+
"wiki_uri" => "https://github.com/slim-template/slim/wiki",
|
22
|
+
"funding_uri" => "https://github.com/sponsors/slim-template"
|
23
|
+
}
|
24
|
+
|
16
25
|
s.files = `git ls-files`.split("\n")
|
17
26
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
27
|
s.require_paths = %w(lib)
|
19
28
|
|
20
|
-
s.required_ruby_version = '>=2.
|
29
|
+
s.required_ruby_version = '>= 2.5.0'
|
21
30
|
|
22
|
-
s.add_runtime_dependency('temple', ['
|
23
|
-
s.add_runtime_dependency('tilt', ['>= 2.0
|
31
|
+
s.add_runtime_dependency('temple', ['~> 0.10.0'])
|
32
|
+
s.add_runtime_dependency('tilt', ['>= 2.1.0'])
|
24
33
|
end
|
data/test/core/helper.rb
CHANGED
@@ -62,16 +62,8 @@ class TestSlim < Minitest::Test
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def assert_backtrace(ex, from)
|
65
|
-
|
66
|
-
|
67
|
-
if ex.backtrace[0] !~ /^#{Regexp.escape from}/
|
68
|
-
ex.backtrace[1] =~ /([^\s]+:\d+)/
|
69
|
-
assert_equal from, $1
|
70
|
-
end
|
71
|
-
else
|
72
|
-
ex.backtrace[0] =~ /([^\s]+:\d+)/
|
73
|
-
assert_equal from, $1
|
74
|
-
end
|
65
|
+
ex.backtrace[0] =~ /([^\s]+:\d+)/
|
66
|
+
assert_equal from, $1
|
75
67
|
end
|
76
68
|
|
77
69
|
def assert_ruby_syntax_error(from, source, options = {})
|
@@ -121,7 +113,7 @@ class Env
|
|
121
113
|
end
|
122
114
|
|
123
115
|
def hello_world(text = "Hello World from @env", opts = {})
|
124
|
-
text
|
116
|
+
text = text + (opts.to_a * " ") if opts.any?
|
125
117
|
if block_given?
|
126
118
|
"#{text} #{yield} #{text}"
|
127
119
|
else
|
@@ -163,6 +163,7 @@ p id=(1 + 1)*5 Test it
|
|
163
163
|
end
|
164
164
|
|
165
165
|
def test_code_attribute_does_not_modify_argument
|
166
|
+
require 'ostruct'
|
166
167
|
template = 'span class=attribute'
|
167
168
|
model = OpenStruct.new(attribute: [:a, :b, [:c, :d]])
|
168
169
|
output = Slim::Template.new { template }.render(model)
|
@@ -120,6 +120,23 @@ p
|
|
120
120
|
assert_html '<p>42 is the answer</p><p>41 is the answer</p><p>42 is the answer</p><p>41 is the answer</p>', source
|
121
121
|
end
|
122
122
|
|
123
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7")
|
124
|
+
def test_render_with_case_in
|
125
|
+
source = %q{
|
126
|
+
p
|
127
|
+
- case [:greet, "world"]
|
128
|
+
- in :greet, value if false
|
129
|
+
= "Goodbye #{value}"
|
130
|
+
- in :greet, value unless true
|
131
|
+
= "Top of the morning to you, #{value}"
|
132
|
+
- in :greet, value
|
133
|
+
= "Hello #{value}"
|
134
|
+
}
|
135
|
+
|
136
|
+
assert_html '<p>Hello world</p>', source
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
123
140
|
def test_render_with_slim_comments
|
124
141
|
source = %q{
|
125
142
|
p Hello
|
data/test/core/test_commands.rb
CHANGED
@@ -15,9 +15,6 @@ class TestSlimCommands < Minitest::Test
|
|
15
15
|
# exception raising example
|
16
16
|
EXCEPTION_TEMPLATE = '- raise NotImplementedError'
|
17
17
|
|
18
|
-
# Temple has this feature...
|
19
|
-
STRING_FREEZER = RUBY_VERSION >= '2.1' ? '.freeze' : ''
|
20
|
-
|
21
18
|
def test_option_help
|
22
19
|
out, err = exec_slimrb '--help'
|
23
20
|
|
@@ -43,7 +40,7 @@ class TestSlimCommands < Minitest::Test
|
|
43
40
|
def test_compile
|
44
41
|
prepare_common_test STATIC_TEMPLATE, '--compile' do |out, err|
|
45
42
|
assert err.empty?
|
46
|
-
assert_match %r{\"<p>Hello World!<\/p>\"
|
43
|
+
assert_match %r{\"<p>Hello World!<\/p>\".freeze}, out
|
47
44
|
end
|
48
45
|
end
|
49
46
|
|
@@ -58,10 +55,14 @@ class TestSlimCommands < Minitest::Test
|
|
58
55
|
prepare_common_test DYNAMIC_TEMPLATE, '--rails' do |out, err|
|
59
56
|
assert err.empty?
|
60
57
|
|
61
|
-
|
62
|
-
|
58
|
+
if Gem::Version.new(Temple::VERSION) >= Gem::Version.new('0.9')
|
59
|
+
assert out.include? %Q{@output_buffer = output_buffer || ActionView::OutputBuffer.new;}
|
60
|
+
else
|
61
|
+
assert out.include? %Q{@output_buffer = ActiveSupport::SafeBuffer.new;}
|
62
|
+
end
|
63
|
+
assert out.include? %Q{@output_buffer.safe_concat(("<p>Hello ".freeze));}
|
63
64
|
assert out.include? %Q{@output_buffer.safe_concat(((::Temple::Utils.escape_html((name))).to_s));}
|
64
|
-
assert out.include? %Q{@output_buffer.safe_concat(("!</p>"
|
65
|
+
assert out.include? %Q{@output_buffer.safe_concat(("!</p>".freeze));}
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
@@ -72,23 +73,19 @@ class TestSlimCommands < Minitest::Test
|
|
72
73
|
end
|
73
74
|
end
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
prepare_common_test DYNAMIC_TEMPLATE, '--locals', data do |out, err|
|
81
|
-
assert err.empty?
|
82
|
-
assert_equal "<p>Hello from slim!</p>\n", out
|
83
|
-
end
|
76
|
+
def test_locals_json
|
77
|
+
data = '{"name":"from slim"}'
|
78
|
+
prepare_common_test DYNAMIC_TEMPLATE, '--locals', data do |out, err|
|
79
|
+
assert err.empty?
|
80
|
+
assert_equal "<p>Hello from slim!</p>\n", out
|
84
81
|
end
|
82
|
+
end
|
85
83
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
84
|
+
def test_locals_yaml
|
85
|
+
data = "name: from slim"
|
86
|
+
prepare_common_test DYNAMIC_TEMPLATE, '--locals', data do |out, err|
|
87
|
+
assert err.empty?
|
88
|
+
assert_equal "<p>Hello from slim!</p>\n", out
|
92
89
|
end
|
93
90
|
end
|
94
91
|
|