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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +107 -0
  3. data/.yardopts +1 -1
  4. data/CHANGES +44 -8
  5. data/Gemfile +18 -45
  6. data/LICENSE +1 -1
  7. data/README.jp.md +28 -41
  8. data/README.md +66 -43
  9. data/Rakefile +2 -9
  10. data/doc/jp/translator.md +1 -1
  11. data/doc/logic_less.md +1 -1
  12. data/doc/translator.md +1 -1
  13. data/lib/slim/code_attributes.rb +2 -1
  14. data/lib/slim/command.rb +2 -8
  15. data/lib/slim/controls.rb +1 -0
  16. data/lib/slim/do_inserter.rb +4 -3
  17. data/lib/slim/embedded.rb +17 -17
  18. data/lib/slim/end_inserter.rb +3 -2
  19. data/lib/slim/engine.rb +3 -0
  20. data/lib/slim/erb_converter.rb +1 -0
  21. data/lib/slim/filter.rb +1 -0
  22. data/lib/slim/grammar.rb +1 -0
  23. data/lib/slim/include.rb +1 -0
  24. data/lib/slim/interpolation.rb +1 -0
  25. data/lib/slim/logic_less/context.rb +6 -7
  26. data/lib/slim/logic_less/filter.rb +1 -0
  27. data/lib/slim/logic_less.rb +1 -0
  28. data/lib/slim/parser.rb +26 -39
  29. data/lib/slim/railtie.rb +19 -0
  30. data/lib/slim/smart/escaper.rb +1 -1
  31. data/lib/slim/smart/filter.rb +3 -2
  32. data/lib/slim/smart/parser.rb +4 -3
  33. data/lib/slim/smart.rb +1 -0
  34. data/lib/slim/splat/builder.rb +16 -8
  35. data/lib/slim/splat/filter.rb +6 -4
  36. data/lib/slim/template.rb +1 -14
  37. data/lib/slim/translator.rb +4 -3
  38. data/lib/slim/version.rb +2 -1
  39. data/lib/slim.rb +2 -0
  40. data/slim.gemspec +14 -5
  41. data/test/core/helper.rb +3 -11
  42. data/test/core/test_code_evaluation.rb +1 -0
  43. data/test/core/test_code_structure.rb +17 -0
  44. data/test/core/test_commands.rb +19 -22
  45. data/test/core/test_embedded_engines.rb +18 -14
  46. data/test/core/test_encoding.rb +2 -2
  47. data/test/core/test_erb_converter.rb +4 -6
  48. data/test/core/test_html_attributes.rb +8 -0
  49. data/test/core/test_html_structure.rb +54 -0
  50. data/test/core/test_pretty.rb +4 -7
  51. data/test/core/test_ruby_errors.rb +19 -0
  52. data/test/literate/TESTS.md +72 -22
  53. data/test/literate/helper.rb +1 -1
  54. data/test/literate/run.rb +3 -3
  55. data/test/logic_less/test_logic_less.rb +15 -0
  56. data/test/rails/app/controllers/slim_controller.rb +7 -1
  57. data/test/rails/app/views/layouts/application.html+testvariant.slim +10 -0
  58. data/test/rails/app/views/slim/attributes.html.slim +3 -0
  59. data/test/rails/app/views/slim/splat_with_delimiter.slim +1 -0
  60. data/test/rails/config/application.rb +1 -18
  61. data/test/rails/test/test_slim.rb +24 -12
  62. data/test/sinatra/helper.rb +0 -2
  63. metadata +27 -37
  64. data/.travis.yml +0 -38
  65. data/benchmarks/context.rb +0 -11
  66. data/benchmarks/profile-parser.rb +0 -10
  67. data/benchmarks/profile-render.rb +0 -12
  68. data/benchmarks/run-benchmarks.rb +0 -120
  69. data/benchmarks/run-diffbench.rb +0 -21
  70. data/benchmarks/view.erb +0 -25
  71. data/benchmarks/view.haml +0 -20
  72. data/benchmarks/view.slim +0 -19
  73. 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*([^\0\s#{keys}]+)"
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*' << splat_prefix << '(?=[^\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
- trailing_ws = $1 == "'"
215
- @stacks.last << [:slim, :text, :verbatim, parse_text_block($', @indents.last + $2.size + 1)]
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 $2.include?('<'.freeze)
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
- shortcut.each {|a| attributes << [:html, :attr, a, [:static, $2]] }
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!
@@ -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
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slim
2
3
  module Smart
3
4
  # Perform smart entity escaping in the
@@ -36,7 +37,6 @@ module Slim
36
37
  end
37
38
  block
38
39
  end
39
-
40
40
  end
41
41
  end
42
42
  end
@@ -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 && ( prev.first != :slim || prev[1] != :text )
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
@@ -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 = ( line =~ /\A\s*\Z/ ? @indents.last + 1 : get_indent(line) )
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
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'slim'
2
3
  require 'slim/smart/filter'
3
4
  require 'slim/smart/escaper'
@@ -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
- # https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
7
- INVALID_ATTRIBUTE_NAME_REGEX = /[ \0"'>\/=]/
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(value != true && escape, value))
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] += delim + value.to_s
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
- value.each do |n, v|
94
- hyphen_attr("#{name}-#{n}", escape, v)
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(value != true && escape, value))
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 unless escape
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
@@ -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
- return builder, result
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
@@ -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
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Slim
2
3
  # Slim version string
3
4
  # @api public
4
- VERSION = '4.1.0'
5
+ VERSION = '5.2.1'
5
6
  end
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 = 'http://slim-lang.com/'
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.0.0'
29
+ s.required_ruby_version = '>= 2.5.0'
21
30
 
22
- s.add_runtime_dependency('temple', ['>= 0.7.6', '< 0.9'])
23
- s.add_runtime_dependency('tilt', ['>= 2.0.6', '< 2.1'])
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
- if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
66
- # HACK: Rubinius stack trace sometimes has one entry more
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 << opts.to_a * " " if opts.any?
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
@@ -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>\"#{STRING_FREEZER}}, out
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
- assert out.include? %Q{@output_buffer = ActiveSupport::SafeBuffer.new;}
62
- assert out.include? %Q{@output_buffer.safe_concat(("<p>Hello "#{STRING_FREEZER}));}
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>"#{STRING_FREEZER}));}
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
- # We cannot run these two on Travis, because we can't install libyaml.
76
- # See https://github.com/slim-template/slim/issues/576
77
- if ENV['TRAVIS'] && RUBY_ENGINE != 'rbx'
78
- def test_locals_json
79
- data = '{"name":"from slim"}'
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
- def test_locals_yaml
87
- data = "name: from slim"
88
- prepare_common_test DYNAMIC_TEMPLATE, '--locals', data do |out, err|
89
- assert err.empty?
90
- assert_equal "<p>Hello from slim!</p>\n", out
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