slim 1.3.6 → 1.3.8

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.
data/lib/slim/engine.rb CHANGED
@@ -5,27 +5,42 @@ 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 :pretty => false,
8
+ define_options :attr_quote,
9
+ :merge_attrs,
10
+ :pretty => false,
9
11
  :sort_attrs => true,
10
- :attr_wrapper => '"',
11
- :attr_delimiter => {'class' => ' '},
12
12
  :generator => Temple::Generators::ArrayBuffer,
13
- :default_tag => 'div'
13
+ :default_tag => 'div',
14
+ :attr_quote => '"',
15
+ :merge_attrs => {'class' => ' '},
16
+ :escape_quoted_attrs => false
14
17
 
15
- # TODO: Remove these options in 1.4.0
16
- define_deprecated_options :remove_empty_attrs, :chain
18
+ # Removed in 2.0
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
17
32
 
18
33
  use Slim::Parser, :file, :tabsize, :encoding, :shortcut, :default_tag, :escape_quoted_attrs
19
- use Slim::EmbeddedEngine, :enable_engines, :disable_engines, :pretty
34
+ use Slim::Embedded, :enable_engines, :disable_engines, :pretty
20
35
  use Slim::Interpolation
21
36
  use Slim::EndInserter
22
- use Slim::ControlStructures, :disable_capture
23
- use Slim::SplatAttributes, :attr_delimiter, :attr_wrapper, :sort_attrs, :default_tag
37
+ use Slim::Controls, :disable_capture
38
+ use Slim::SplatAttributes, :merge_attrs, :attr_quote, :sort_attrs, :default_tag
24
39
  html :AttributeSorter, :sort_attrs
25
- html :AttributeMerger, :attr_delimiter
26
- use Slim::CodeAttributes, :attr_delimiter
27
- use(:AttributeRemover) { Temple::HTML::AttributeRemover.new(:remove_empty_attrs => options[:attr_delimiter].keys) }
28
- html :Pretty, :format, :attr_wrapper, :pretty, :indent
40
+ html :AttributeMerger, :merge_attrs
41
+ use Slim::CodeAttributes, :merge_attrs
42
+ use(:AttributeRemover) { Temple::HTML::AttributeRemover.new(:remove_empty_attrs => options[:merge_attrs].keys) }
43
+ html :Pretty, :format, :attr_quote, :pretty, :indent, :js_wrapper
29
44
  filter :Escapable, :use_html_safe, :disable_escape
30
45
  filter :ControlFlow
31
46
  filter :MultiFlattener
data/lib/slim/filter.rb CHANGED
@@ -14,7 +14,7 @@ module Slim
14
14
 
15
15
  # Pass-through handler
16
16
  def on_slim_embedded(type, content)
17
- [:slim, :embedded, code, compile(content)]
17
+ [:slim, :embedded, type, compile(content)]
18
18
  end
19
19
 
20
20
  # Pass-through handler
@@ -14,7 +14,7 @@ module Slim
14
14
  super
15
15
  access = options[:dictionary_access]
16
16
  if access == :wrapped
17
- warn 'Slim::LogicLess - Wrapped dictionary access is deprecated'
17
+ warn 'Slim::LogicLess - Wrapped dictionary access is deprecated and unsupported in Slim 2.0'
18
18
  access = DEFAULT_ACCESS_ORDER
19
19
  else
20
20
  access = [access].flatten.compact
data/lib/slim/parser.rb CHANGED
@@ -4,7 +4,7 @@ module Slim
4
4
  class Parser < Temple::Parser
5
5
  define_options :file,
6
6
  :default_tag,
7
- :escape_quoted_attrs => false,
7
+ :escape_quoted_attrs,
8
8
  :tabsize => 4,
9
9
  :encoding => 'utf-8',
10
10
  :shortcut => {
@@ -24,7 +24,7 @@ module Slim
24
24
  end
25
25
 
26
26
  def to_s
27
- line = @line.strip
27
+ line = @line.lstrip
28
28
  column = @column + line.size - @line.size
29
29
  %{#{error}
30
30
  #{file}, Line #{lineno}, Column #{@column}
@@ -36,7 +36,14 @@ module Slim
36
36
 
37
37
  def initialize(opts = {})
38
38
  super
39
- @tab = ' ' * options[:tabsize]
39
+ tabsize = options[:tabsize]
40
+ if tabsize > 1
41
+ @tab_re = /\G((?: {#{tabsize}})*) {0,#{tabsize-1}}\t/
42
+ @tab = '\1' + ' ' * tabsize
43
+ else
44
+ @tab_re = "\t"
45
+ @tab = ' '
46
+ end
40
47
  @tag_shortcut, @attr_shortcut = {}, {}
41
48
  options[:shortcut].each do |k,v|
42
49
  v = deprecated_shortcut(v) if String === v
@@ -47,8 +54,8 @@ module Slim
47
54
  raise ArgumentError, 'You can only use special characters for attribute shortcuts' if k =~ /[\w-]/
48
55
  end
49
56
  end
50
- @attr_shortcut_regex = /\A(#{shortcut_regex @attr_shortcut})(\w[\w-]*\w|\w+)/
51
- @tag_regex = /\A(?:#{shortcut_regex @tag_shortcut}|\*(?=[^\s]+)|(\w[\w:-]*\w|\w+))/
57
+ @attr_shortcut_regex = /\A(#{Regexp.union @attr_shortcut.keys})(\w[\w-]*\w|\w+)/
58
+ @tag_regex = /\A(?:#{Regexp.union @tag_shortcut.keys}|\*(?=[^\s]+)|(\w[\w:-]*\w|\w+))/
52
59
  end
53
60
 
54
61
  # Compile string to Temple expression
@@ -75,14 +82,17 @@ module Slim
75
82
  '{' => '}',
76
83
  }.freeze
77
84
 
85
+ ATTR_DELIM_REGEX = /\A\s*[#{Regexp.escape DELIMITERS.keys.join}]/
78
86
  DELIMITER_REGEX = /\A[#{Regexp.escape DELIMITERS.keys.join}]/
79
87
  ATTR_NAME = '\A\s*(\w[:\w-]*)'
80
88
  QUOTED_ATTR_REGEX = /#{ATTR_NAME}=(=?)("|')/
81
89
  CODE_ATTR_REGEX = /#{ATTR_NAME}=(=?)/
90
+ QUOTED_ATTR_REGEX_20 = /#{ATTR_NAME}\s*=(=?)\s*("|')/
91
+ CODE_ATTR_REGEX_20 = /#{ATTR_NAME}\s*=(=?)\s*/
82
92
 
83
93
  # Convert deprecated string shortcut to hash
84
94
  def deprecated_shortcut(v)
85
- warn "Slim :shortcut string values are deprecated, use hash like { '#' => { :tag => 'div', :attr => 'id' } }"
95
+ warn "Slim :shortcut string values are deprecated and unsupported in Slim 2.0, use hash like { '#' => { :tag => 'div', :attr => 'id' } }"
86
96
  if v =~ /\A([^\s]+)\s+([^\s]+)\Z/
87
97
  { :tag => $1, :attr => $2 }
88
98
  else
@@ -90,11 +100,6 @@ module Slim
90
100
  end
91
101
  end
92
102
 
93
- # Compile shortcut regular expression
94
- def shortcut_regex(shortcut)
95
- shortcut.map { |k,v| Regexp.escape(k) }.join('|')
96
- end
97
-
98
103
  # Set string encoding if option is set
99
104
  def set_encoding(s)
100
105
  if options[:encoding] && s.respond_to?(:encoding)
@@ -102,7 +107,10 @@ module Slim
102
107
  s = s.dup if s.frozen?
103
108
  s.force_encoding(options[:encoding])
104
109
  # Fall back to old encoding if new encoding is invalid
105
- s.force_encoding(old_enc) unless s.valid_encoding?
110
+ unless s.valid_encoding?
111
+ s.force_encoding(old_enc)
112
+ s.force_encoding(Encoding::BINARY) unless s.valid_encoding?
113
+ end
106
114
  end
107
115
  s
108
116
  end
@@ -160,7 +168,7 @@ module Slim
160
168
  def get_indent(line)
161
169
  # Figure out the indentation. Kinda ugly/slow way to support tabs,
162
170
  # but remember that this is only done at parsing time.
163
- line[/\A[ \t]*/].gsub("\t", @tab).size
171
+ line[/\A[ \t]*/].gsub(@tab_re, @tab).size
164
172
  end
165
173
 
166
174
  def parse_line
@@ -354,8 +362,10 @@ module Slim
354
362
  tag << [:slim, :output, $1 != '=', parse_broken_line, block]
355
363
  @stacks.last << [:static, ' '] unless $2.empty?
356
364
  @stacks << block
357
- when /\A\s*\//
365
+ when /\A\s*\/\s*/
358
366
  # Closed tag. Do nothing
367
+ @line = $'
368
+ syntax_error!('Unexpected text after closed tag') unless @line.empty?
359
369
  when /\A\s*\Z/
360
370
  # Empty content
361
371
  content = [:multi]
@@ -380,9 +390,13 @@ module Slim
380
390
 
381
391
  # Check to see if there is a delimiter right after the tag name
382
392
  delimiter = nil
383
- if @line =~ DELIMITER_REGEX
384
- delimiter = DELIMITERS[$&]
385
- @line.slice!(0)
393
+ if @line =~ ATTR_DELIM_REGEX
394
+ if $&.size > 1
395
+ warn "#{options[:file]}:#{@lineno} - spaces around attribute delimiters will be allowed in Slim 2.0. Your code is incompatible."
396
+ else
397
+ delimiter = DELIMITERS[$&]
398
+ @line.slice!(0)
399
+ end
386
400
  end
387
401
 
388
402
  if delimiter
@@ -399,9 +413,16 @@ module Slim
399
413
  when QUOTED_ATTR_REGEX
400
414
  # Value is quoted (static)
401
415
  @line = $'
402
- attributes << [:html, :attr, $1,
403
- [:escape, options[:escape_quoted_attrs] && $2.empty?,
404
- [:slim, :interpolate, parse_quoted_attribute($3)]]]
416
+ name = $1
417
+ escape = $2.empty?
418
+ quote = $3
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]]]
405
426
  when CODE_ATTR_REGEX
406
427
  # Value is ruby code
407
428
  @line = $'
@@ -410,11 +431,17 @@ module Slim
410
431
  value = parse_ruby_code(delimiter)
411
432
  # Remove attribute wrapper which doesn't belong to the ruby code
412
433
  # e.g id=[hash[:a] + hash[:b]]
413
- value = value[1..-2] if value =~ DELIMITER_REGEX &&
414
- DELIMITERS[$&] == value[-1, 1]
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
415
438
  syntax_error!('Invalid empty attribute') if value.empty?
416
439
  attributes << [:html, :attr, name, [:slim, :attrvalue, escape, value]]
417
440
  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
+
418
445
  break unless delimiter
419
446
 
420
447
  case @line
@@ -1,13 +1,13 @@
1
1
  module Slim
2
2
  # @api private
3
3
  class SplatAttributes < Filter
4
- define_options :attr_delimiter, :attr_wrapper, :sort_attrs, :default_tag
4
+ define_options :sort_attrs, :default_tag, :merge_attrs, :attr_quote
5
5
 
6
6
  def call(exp)
7
- @attr_delimiter, @splat_used = unique_name, false
7
+ @merge_attrs, @splat_used = unique_name, false
8
8
  exp = compile(exp)
9
9
  if @splat_used
10
- [:multi, [:code, "#{@attr_delimiter} = #{@options[:attr_delimiter].inspect}"], exp]
10
+ [:multi, [:code, "#{@merge_attrs} = #{@options[:merge_attrs].inspect}"], exp]
11
11
  else
12
12
  exp
13
13
  end
@@ -82,14 +82,14 @@ module Slim
82
82
  merger << [:block, "#{hash}.keys.each do |#{name}|",
83
83
  [:multi,
84
84
  [:code, "#{value} = #{hash}[#{name}]"],
85
- [:if, "#{@attr_delimiter}[#{name}]",
85
+ [:if, "#{@merge_attrs}[#{name}]",
86
86
  [:multi,
87
87
  [:code, "#{value}.flatten!"],
88
88
  [:code, "#{value}.map!(&:to_s)"],
89
89
  [:code, "#{value}.reject!(&:empty?)"],
90
90
  [:if, "#{value}.empty?",
91
91
  [:code, "#{hash}.delete(#{name})"],
92
- [:code, "#{hash}[#{name}] = #{value}.join(#{@attr_delimiter}[#{name}].to_s)"]]],
92
+ [:code, "#{hash}[#{name}] = #{value}.join(#{@merge_attrs}[#{name}].to_s)"]]],
93
93
  [:multi,
94
94
  [:if, "#{value}.size > 1",
95
95
  [:code, %{raise("Multiple #\{#{name}\} attributes specified")}]],
@@ -101,9 +101,9 @@ module Slim
101
101
  attr = [:multi,
102
102
  [:static, ' '],
103
103
  [:dynamic, name],
104
- [:static, "=#{options[:attr_wrapper]}"],
104
+ [:static, "=#{options[:attr_quote]}"],
105
105
  [:escape, true, [:dynamic, value]],
106
- [:static, options[:attr_wrapper]]]
106
+ [:static, options[:attr_quote]]]
107
107
  enumerator = options[:sort_attrs] ? "#{hash}.sort_by {|#{name},#{value}| #{name} }" : hash
108
108
  formatter = [:block, "#{enumerator}.each do |#{name},#{value}|", attr]
109
109
 
data/lib/slim/template.rb CHANGED
@@ -3,7 +3,7 @@ module Slim
3
3
  # @api public
4
4
  Template = Temple::Templates::Tilt(Slim::Engine, :register_as => :slim)
5
5
 
6
- if Object.const_defined?(:Rails)
6
+ if defined?(::ActionView)
7
7
  # Rails template implementation for Slim
8
8
  # @api public
9
9
  RailsTemplate = Temple::Templates::Rails(Slim::Engine,
@@ -14,6 +14,6 @@ module Slim
14
14
  # Disable the internal slim capturing.
15
15
  # Rails takes care of the capturing by itself.
16
16
  :disable_capture => true,
17
- :streaming => Object.const_defined?(:Fiber))
17
+ :streaming => defined?(::Fiber))
18
18
  end
19
19
  end
@@ -6,13 +6,13 @@ module Slim
6
6
  :tr_fn => '_',
7
7
  :tr => false
8
8
 
9
- if Object.const_defined?(:I18n)
9
+ if defined?(::I18n)
10
10
  set_default_options :tr_fn => '::Slim::Translator.i18n_text',
11
11
  :tr => true
12
- elsif Object.const_defined?(:GetText)
12
+ elsif defined?(::GetText)
13
13
  set_default_options :tr_fn => '::GetText._',
14
14
  :tr => true
15
- elsif Object.const_defined?(:FastGettext)
15
+ elsif defined?(::FastGettext)
16
16
  set_default_options :tr_fn => '::FastGettext::Translation._',
17
17
  :tr => true
18
18
  end
data/lib/slim/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Slim
2
2
  # Slim version string
3
3
  # @api public
4
- VERSION = '1.3.6'
4
+ VERSION = '1.3.8'
5
5
  end
data/slim.gemspec CHANGED
@@ -17,13 +17,6 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = %w(lib)
19
19
 
20
- s.add_runtime_dependency('temple', ['~> 0.5.5'])
20
+ s.add_runtime_dependency('temple', ['~> 0.6.3'])
21
21
  s.add_runtime_dependency('tilt', ['~> 1.3.3'])
22
-
23
- s.add_development_dependency('rake', ['>= 0.8.7'])
24
- s.add_development_dependency('sass', ['>= 3.1.0'])
25
- s.add_development_dependency('minitest', ['>= 0'])
26
- s.add_development_dependency('kramdown', ['>= 0'])
27
- s.add_development_dependency('creole', ['>= 0'])
28
- s.add_development_dependency('builder', ['>= 0'])
29
22
  end
data/test/core/helper.rb CHANGED
@@ -16,7 +16,27 @@ class TestSlim < MiniTest::Unit::TestCase
16
16
 
17
17
  def render(source, options = {}, &block)
18
18
  scope = options.delete(:scope)
19
- Slim::Template.new(options[:file], options) { source }.render(scope || @env, &block)
19
+ locals = options.delete(:locals)
20
+ Slim::Template.new(options[:file], options) { source }.render(scope || @env, locals, &block)
21
+ end
22
+
23
+ class HtmlSafeString < String
24
+ def html_safe?
25
+ true
26
+ end
27
+
28
+ def to_s
29
+ self
30
+ end
31
+ end
32
+
33
+ def with_html_safe
34
+ String.send(:define_method, :html_safe?) { false }
35
+ String.send(:define_method, :html_safe) { HtmlSafeString.new(self) }
36
+ yield
37
+ ensure
38
+ String.send(:undef_method, :html_safe?) if String.method_defined?(:html_safe?)
39
+ String.send(:undef_method, :html_safe) if String.method_defined?(:html_safe)
20
40
  end
21
41
 
22
42
  def assert_html(expected, source, options = {}, &block)
@@ -69,18 +89,6 @@ end
69
89
  class Env
70
90
  attr_reader :var, :x
71
91
 
72
- class ::HtmlSafeString < String
73
- def html_safe?
74
- true
75
- end
76
- end
77
-
78
- class ::HtmlUnsafeString < String
79
- def html_safe?
80
- false
81
- end
82
- end
83
-
84
92
  def initialize
85
93
  @var = 'instance'
86
94
  @x = 0
@@ -19,18 +19,22 @@ p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
19
19
 
20
20
  def test_render_with_html_safe_false
21
21
  source = %q{
22
- p = HtmlUnsafeString.new("<strong>Hello World\\n, meet \\"Slim\\"</strong>.")
22
+ p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
23
23
  }
24
24
 
25
- assert_html "<p>&lt;strong&gt;Hello World\n, meet \&quot;Slim\&quot;&lt;/strong&gt;.</p>", source, :use_html_safe => true
25
+ with_html_safe do
26
+ assert_html "<p>&lt;strong&gt;Hello World\n, meet \&quot;Slim\&quot;&lt;/strong&gt;.</p>", source, :use_html_safe => true
27
+ end
26
28
  end
27
29
 
28
30
  def test_render_with_html_safe_true
29
31
  source = %q{
30
- p = HtmlSafeString.new("<strong>Hello World\\n, meet \\"Slim\\"</strong>.")
32
+ p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>.".html_safe
31
33
  }
32
34
 
33
- assert_html "<p><strong>Hello World\n, meet \"Slim\"</strong>.</p>", source, :use_html_safe => true
35
+ with_html_safe do
36
+ assert_html "<p><strong>Hello World\n, meet \"Slim\"</strong>.</p>", source, :use_html_safe => true
37
+ end
34
38
  end
35
39
 
36
40
  def test_render_with_disable_escape_false
@@ -50,4 +54,58 @@ p = HtmlSafeString.new("<strong>Hello World\\n, meet \\"Slim\\"</strong>.")
50
54
 
51
55
  assert_html "<p>Hello</p><p>World</p>", source, :disable_escape => true
52
56
  end
57
+
58
+ def test_escaping_evil_method_with_pretty
59
+ source = %q{
60
+ p = evil_method
61
+ }
62
+
63
+ assert_html "<p>\n &lt;script&gt;do_something_evil();&lt;/script&gt;\n</p>", source, :pretty => true
64
+ end
65
+
66
+ def test_render_without_html_safe_with_pretty
67
+ source = %q{
68
+ p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
69
+ }
70
+
71
+ assert_html "<p>\n &lt;strong&gt;Hello World\n , meet \&quot;Slim\&quot;&lt;/strong&gt;.\n</p>", source, :pretty => true
72
+ end
73
+
74
+ def test_render_with_html_safe_false_with_pretty
75
+ source = %q{
76
+ p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>."
77
+ }
78
+
79
+ with_html_safe do
80
+ assert_html "<p>\n &lt;strong&gt;Hello World\n , meet \&quot;Slim\&quot;&lt;/strong&gt;.\n</p>", source, :use_html_safe => true, :pretty => true
81
+ end
82
+ end
83
+
84
+ def test_render_with_html_safe_true_with_pretty
85
+ source = %q{
86
+ p = "<strong>Hello World\\n, meet \\"Slim\\"</strong>.".html_safe
87
+ }
88
+
89
+ with_html_safe do
90
+ assert_html "<p>\n <strong>Hello World\n , meet \"Slim\"</strong>.\n</p>", source, :use_html_safe => true, :pretty => true
91
+ end
92
+ end
93
+
94
+ def test_render_with_disable_escape_false_with_pretty
95
+ source = %q{
96
+ = "<p>Hello</p>"
97
+ == "<p>World</p>"
98
+ }
99
+
100
+ assert_html "&lt;p&gt;Hello&lt;/p&gt;<p>World</p>", source, :pretty => true
101
+ end
102
+
103
+ def test_render_with_disable_escape_true_with_pretty
104
+ source = %q{
105
+ = "<p>Hello</p>"
106
+ == "<p>World</p>"
107
+ }
108
+
109
+ assert_html "<p>Hello</p><p>World</p>", source, :disable_escape => true, :pretty => true
110
+ end
53
111
  end