sass 3.1.8 → 3.1.9
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/VERSION +1 -1
- data/lib/sass/engine.rb +26 -10
- data/lib/sass/less.rb +1 -1
- data/lib/sass/scss/parser.rb +28 -8
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/tree/comment_node.rb +24 -11
- data/lib/sass/tree/visitors/convert.rb +10 -5
- data/lib/sass/tree/visitors/perform.rb +36 -8
- data/lib/sass/tree/visitors/to_css.rb +2 -12
- data/lib/sass/util.rb +51 -0
- data/test/sass/conversion_test.rb +2 -6
- data/test/sass/engine_test.rb +38 -5
- data/test/sass/scss/css_test.rb +6 -0
- data/test/sass/util_test.rb +12 -0
- metadata +4 -4
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            3.1. | 
| 1 | 
            +
            3.1.9
         | 
    
        data/lib/sass/engine.rb
    CHANGED
    
    | @@ -90,7 +90,10 @@ module Sass | |
| 90 90 | 
             
                #
         | 
| 91 91 | 
             
                # `children`: `Array<Line>`
         | 
| 92 92 | 
             
                # : The lines nested below this one.
         | 
| 93 | 
            -
                 | 
| 93 | 
            +
                #
         | 
| 94 | 
            +
                # `comment_tab_str`: `String?`
         | 
| 95 | 
            +
                # : The prefix indentation for this comment, if it is a comment.
         | 
| 96 | 
            +
                class Line < Struct.new(:text, :tabs, :index, :offset, :filename, :children, :comment_tab_str)
         | 
| 94 97 | 
             
                  def comment?
         | 
| 95 98 | 
             
                    text[0] == COMMENT_CHAR && (text[1] == SASS_COMMENT_CHAR || text[1] == CSS_COMMENT_CHAR)
         | 
| 96 99 | 
             
                  end
         | 
| @@ -107,6 +110,10 @@ module Sass | |
| 107 110 | 
             
                # which is not output as a CSS comment.
         | 
| 108 111 | 
             
                SASS_COMMENT_CHAR = ?/
         | 
| 109 112 |  | 
| 113 | 
            +
                # The character that indicates that a comment allows interpolation
         | 
| 114 | 
            +
                # and should be preserved even in `:compressed` mode.
         | 
| 115 | 
            +
                SASS_LOUD_COMMENT_CHAR = ?!
         | 
| 116 | 
            +
             | 
| 110 117 | 
             
                # The character that follows the general COMMENT_CHAR and designates a CSS comment,
         | 
| 111 118 | 
             
                # which is embedded in the CSS document.
         | 
| 112 119 | 
             
                CSS_COMMENT_CHAR = ?*
         | 
| @@ -420,7 +427,8 @@ but this line was indented by #{Sass::Shared.human_indentation line[/^\s*/]}. | |
| 420 427 | 
             
            MSG
         | 
| 421 428 | 
             
                  end
         | 
| 422 429 |  | 
| 423 | 
            -
                  last. | 
| 430 | 
            +
                  last.comment_tab_str ||= comment_tab_str
         | 
| 431 | 
            +
                  last.text << "\n" << line
         | 
| 424 432 | 
             
                  true
         | 
| 425 433 | 
             
                end
         | 
| 426 434 |  | 
| @@ -486,8 +494,8 @@ MSG | |
| 486 494 | 
             
                    if child.is_a?(Tree::CommentNode) && child.silent
         | 
| 487 495 | 
             
                      if continued_comment &&
         | 
| 488 496 | 
             
                          child.line == continued_comment.line +
         | 
| 489 | 
            -
                          continued_comment. | 
| 490 | 
            -
                        continued_comment.value  | 
| 497 | 
            +
                          continued_comment.lines + 1
         | 
| 498 | 
            +
                        continued_comment.value += ["\n"] + child.value
         | 
| 491 499 | 
             
                        next
         | 
| 492 500 | 
             
                      end
         | 
| 493 501 |  | 
| @@ -538,7 +546,7 @@ WARNING | |
| 538 546 | 
             
                  when ?$
         | 
| 539 547 | 
             
                    parse_variable(line)
         | 
| 540 548 | 
             
                  when COMMENT_CHAR
         | 
| 541 | 
            -
                    parse_comment(line | 
| 549 | 
            +
                    parse_comment(line)
         | 
| 542 550 | 
             
                  when DIRECTIVE_CHAR
         | 
| 543 551 | 
             
                    parse_directive(parent, line, root)
         | 
| 544 552 | 
             
                  when ESCAPE_CHAR
         | 
| @@ -600,11 +608,19 @@ WARNING | |
| 600 608 | 
             
                end
         | 
| 601 609 |  | 
| 602 610 | 
             
                def parse_comment(line)
         | 
| 603 | 
            -
                  if line[1] == CSS_COMMENT_CHAR || line[1] == SASS_COMMENT_CHAR
         | 
| 604 | 
            -
                    silent = line[1] == SASS_COMMENT_CHAR
         | 
| 605 | 
            -
                     | 
| 606 | 
            -
                       | 
| 607 | 
            -
                       | 
| 611 | 
            +
                  if line.text[1] == CSS_COMMENT_CHAR || line.text[1] == SASS_COMMENT_CHAR
         | 
| 612 | 
            +
                    silent = line.text[1] == SASS_COMMENT_CHAR
         | 
| 613 | 
            +
                    if loud = line.text[2] == SASS_LOUD_COMMENT_CHAR
         | 
| 614 | 
            +
                      value = self.class.parse_interp(line.text, line.index, line.offset, :filename => @filename)
         | 
| 615 | 
            +
                      value[0].slice!(2) # get rid of the "!"
         | 
| 616 | 
            +
                    else
         | 
| 617 | 
            +
                      value = [line.text]
         | 
| 618 | 
            +
                    end
         | 
| 619 | 
            +
                    value = with_extracted_values(value) do |str|
         | 
| 620 | 
            +
                      str = str.gsub(/^#{line.comment_tab_str}/m, '')[2..-1] # get rid of // or /*
         | 
| 621 | 
            +
                      format_comment_text(str, silent)
         | 
| 622 | 
            +
                    end
         | 
| 623 | 
            +
                    Tree::CommentNode.new(value, silent, loud)
         | 
| 608 624 | 
             
                  else
         | 
| 609 625 | 
             
                    Tree::RuleNode.new(parse_interp(line))
         | 
| 610 626 | 
             
                  end
         | 
    
        data/lib/sass/less.rb
    CHANGED
    
    | @@ -31,7 +31,7 @@ module Less | |
| 31 31 | 
             
            WARNING: Sass doesn't support mixing in selector sequences.
         | 
| 32 32 | 
             
            Replacing "#{sel}" with "@extend #{base}"
         | 
| 33 33 | 
             
            WARNING
         | 
| 34 | 
            -
                          env << Node::SassNode.new(Sass::Tree::CommentNode.new("// #{sel};", true))
         | 
| 34 | 
            +
                          env << Node::SassNode.new(Sass::Tree::CommentNode.new(["// #{sel};"], true, false))
         | 
| 35 35 | 
             
                          env << Node::SassNode.new(Sass::Tree::ExtendNode.new([base]))
         | 
| 36 36 | 
             
                        end
         | 
| 37 37 | 
             
                      end
         | 
    
        data/lib/sass/scss/parser.rb
    CHANGED
    
    | @@ -89,14 +89,28 @@ module Sass | |
| 89 89 | 
             
                  end
         | 
| 90 90 |  | 
| 91 91 | 
             
                  def process_comment(text, node)
         | 
| 92 | 
            -
                     | 
| 93 | 
            -
                     | 
| 94 | 
            -
             | 
| 95 | 
            -
                       | 
| 96 | 
            -
                       | 
| 97 | 
            -
                     | 
| 98 | 
            -
             | 
| 99 | 
            -
                     | 
| 92 | 
            +
                    silent = text =~ /^\/\//
         | 
| 93 | 
            +
                    line = @line - text.count("\n")
         | 
| 94 | 
            +
                    if loud = text =~ %r{^/[/*]!}
         | 
| 95 | 
            +
                      value = Sass::Engine.parse_interp(text, line, @scanner.pos - text.size, :filename => @filename)
         | 
| 96 | 
            +
                      value[0].slice!(2) # get rid of the "!"
         | 
| 97 | 
            +
                    else
         | 
| 98 | 
            +
                      value = [text]
         | 
| 99 | 
            +
                    end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                    if silent
         | 
| 102 | 
            +
                      value = Sass::Util.with_extracted_values(value) do |str|
         | 
| 103 | 
            +
                        str.sub(/^\s*\/\//, '/*').gsub(/^\s*\/\//, ' *') + ' */'
         | 
| 104 | 
            +
                      end
         | 
| 105 | 
            +
                    else
         | 
| 106 | 
            +
                      value.unshift(@scanner.
         | 
| 107 | 
            +
                        string[0...@scanner.pos].
         | 
| 108 | 
            +
                        reverse[/.*?\*\/(.*?)($|\Z)/, 1].
         | 
| 109 | 
            +
                        reverse.gsub(/[^\s]/, ' '))
         | 
| 110 | 
            +
                    end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                    comment = Sass::Tree::CommentNode.new(value, silent, loud)
         | 
| 113 | 
            +
                    comment.line = line
         | 
| 100 114 | 
             
                    node << comment
         | 
| 101 115 | 
             
                  end
         | 
| 102 116 |  | 
| @@ -777,8 +791,14 @@ MESSAGE | |
| 777 791 | 
             
                  end
         | 
| 778 792 |  | 
| 779 793 | 
             
                  def str?
         | 
| 794 | 
            +
                    pos = @scanner.pos
         | 
| 795 | 
            +
                    line = @line
         | 
| 780 796 | 
             
                    @strs.push ""
         | 
| 781 797 | 
             
                    yield && @strs.last
         | 
| 798 | 
            +
                  rescue Sass::SyntaxError => e
         | 
| 799 | 
            +
                    @scanner.pos = pos
         | 
| 800 | 
            +
                    @line = line
         | 
| 801 | 
            +
                    nil
         | 
| 782 802 | 
             
                  ensure
         | 
| 783 803 | 
             
                    @strs.pop
         | 
| 784 804 | 
             
                  end
         | 
    
        data/lib/sass/shared.rb
    CHANGED
    
    | @@ -17,7 +17,7 @@ module Sass | |
| 17 17 | 
             
                # @return [String] The text remaining in the scanner after all `#{`s have been processed
         | 
| 18 18 | 
             
                def handle_interpolation(str)
         | 
| 19 19 | 
             
                  scan = StringScanner.new(str)
         | 
| 20 | 
            -
                  yield scan while scan.scan(/(.*?)(\\*)\#\{/)
         | 
| 20 | 
            +
                  yield scan while scan.scan(/(.*?)(\\*)\#\{/m)
         | 
| 21 21 | 
             
                  scan.rest
         | 
| 22 22 | 
             
                end
         | 
| 23 23 |  | 
| @@ -6,10 +6,19 @@ module Sass::Tree | |
| 6 6 | 
             
              # @see Sass::Tree
         | 
| 7 7 | 
             
              class CommentNode < Node
         | 
| 8 8 | 
             
                # The text of the comment, not including `/*` and `*/`.
         | 
| 9 | 
            +
                # Interspersed with {Sass::Script::Node}s representing `#{}`-interpolation
         | 
| 10 | 
            +
                # if this is a loud comment.
         | 
| 9 11 | 
             
                #
         | 
| 10 | 
            -
                # @return [String]
         | 
| 12 | 
            +
                # @return [Array<String, Sass::Script::Node>]
         | 
| 11 13 | 
             
                attr_accessor :value
         | 
| 12 14 |  | 
| 15 | 
            +
                # The text of the comment
         | 
| 16 | 
            +
                # after any interpolated SassScript has been resolved.
         | 
| 17 | 
            +
                # Only set once \{Tree::Visitors::Perform} has been run.
         | 
| 18 | 
            +
                #
         | 
| 19 | 
            +
                # @return [String]
         | 
| 20 | 
            +
                attr_accessor :resolved_value
         | 
| 21 | 
            +
             | 
| 13 22 | 
             
                # Whether the comment is loud.
         | 
| 14 23 | 
             
                #
         | 
| 15 24 | 
             
                # Loud comments start with ! and force the comment to be generated
         | 
| @@ -23,14 +32,13 @@ module Sass::Tree | |
| 23 32 | 
             
                # @return [Boolean]
         | 
| 24 33 | 
             
                attr_accessor :silent
         | 
| 25 34 |  | 
| 26 | 
            -
                # @param value [String] See \{#value}
         | 
| 35 | 
            +
                # @param value [Array<String, Sass::Script::Node>] See \{#value}
         | 
| 27 36 | 
             
                # @param silent [Boolean] See \{#silent}
         | 
| 28 | 
            -
                 | 
| 29 | 
            -
             | 
| 37 | 
            +
                # @param loud [Boolean] See \{#loud}
         | 
| 38 | 
            +
                def initialize(value, silent, loud)
         | 
| 39 | 
            +
                  @value = Sass::Util.with_extracted_values(value) {|str| normalize_indentation str}
         | 
| 30 40 | 
             
                  @silent = silent
         | 
| 31 | 
            -
                  @ | 
| 32 | 
            -
                  @loud = @value =~ %r{^(/[\/\*])?!}
         | 
| 33 | 
            -
                  @value.sub!("#{$1}!", $1.to_s) if @loud
         | 
| 41 | 
            +
                  @loud = loud
         | 
| 34 42 | 
             
                  super()
         | 
| 35 43 | 
             
                end
         | 
| 36 44 |  | 
| @@ -40,7 +48,7 @@ module Sass::Tree | |
| 40 48 | 
             
                # @return [Boolean] Whether or not this node and the other object
         | 
| 41 49 | 
             
                #   are the same
         | 
| 42 50 | 
             
                def ==(other)
         | 
| 43 | 
            -
                  self.class == other.class && value == other.value && silent == other.silent
         | 
| 51 | 
            +
                  self.class == other.class && value == other.value && silent == other.silent && loud == other.loud
         | 
| 44 52 | 
             
                end
         | 
| 45 53 |  | 
| 46 54 | 
             
                # Returns `true` if this is a silent comment
         | 
| @@ -57,9 +65,14 @@ module Sass::Tree | |
| 57 65 | 
             
                  end
         | 
| 58 66 | 
             
                end
         | 
| 59 67 |  | 
| 60 | 
            -
                # Returns  | 
| 61 | 
            -
                 | 
| 62 | 
            -
             | 
| 68 | 
            +
                # Returns the number of lines in the comment.
         | 
| 69 | 
            +
                #
         | 
| 70 | 
            +
                # @return [Fixnum]
         | 
| 71 | 
            +
                def lines
         | 
| 72 | 
            +
                  @value.inject(0) do |s, e|
         | 
| 73 | 
            +
                    next s + e.count("\n") if e.is_a?(String)
         | 
| 74 | 
            +
                    next s
         | 
| 75 | 
            +
                  end
         | 
| 63 76 | 
             
                end
         | 
| 64 77 |  | 
| 65 78 | 
             
                private
         | 
| @@ -32,7 +32,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base | |
| 32 32 | 
             
                  visit(child) +
         | 
| 33 33 | 
             
                    if nxt &&
         | 
| 34 34 | 
             
                        (child.is_a?(Sass::Tree::CommentNode) &&
         | 
| 35 | 
            -
                          child.line + child. | 
| 35 | 
            +
                          child.line + child.lines + 1 == nxt.line) ||
         | 
| 36 36 | 
             
                        (child.is_a?(Sass::Tree::ImportNode) && nxt.is_a?(Sass::Tree::ImportNode) &&
         | 
| 37 37 | 
             
                          child.line + 1 == nxt.line) ||
         | 
| 38 38 | 
             
                        (child.is_a?(Sass::Tree::VariableNode) && nxt.is_a?(Sass::Tree::VariableNode) &&
         | 
| @@ -49,8 +49,13 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base | |
| 49 49 | 
             
              end
         | 
| 50 50 |  | 
| 51 51 | 
             
              def visit_comment(node)
         | 
| 52 | 
            +
                value = node.value.map do |r|
         | 
| 53 | 
            +
                  next r if r.is_a?(String)
         | 
| 54 | 
            +
                  "\#{#{r.to_sass(@options)}}"
         | 
| 55 | 
            +
                end.join
         | 
| 56 | 
            +
             | 
| 52 57 | 
             
                content = if @format == :sass
         | 
| 53 | 
            -
                  content =  | 
| 58 | 
            +
                  content = value.gsub(/\*\/$/, '').rstrip
         | 
| 54 59 | 
             
                  if content =~ /\A[ \t]/
         | 
| 55 60 | 
             
                    # Re-indent SCSS comments like this:
         | 
| 56 61 | 
             
                    #     /* foo
         | 
| @@ -78,11 +83,11 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base | |
| 78 83 | 
             
                  content.gsub!(/^/, tab_str)
         | 
| 79 84 | 
             
                  content.rstrip + "\n"
         | 
| 80 85 | 
             
                else
         | 
| 81 | 
            -
                  spaces = ('  ' * [@tabs -  | 
| 86 | 
            +
                  spaces = ('  ' * [@tabs - value[/^ */].size, 0].max)
         | 
| 82 87 | 
             
                  content = if node.silent
         | 
| 83 | 
            -
                     | 
| 88 | 
            +
                    value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
         | 
| 84 89 | 
             
                  else
         | 
| 85 | 
            -
                     | 
| 90 | 
            +
                    value
         | 
| 86 91 | 
             
                  end.gsub(/^/, spaces) + "\n"
         | 
| 87 92 | 
             
                  content
         | 
| 88 93 | 
             
                end
         | 
| @@ -53,12 +53,10 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base | |
| 53 53 | 
             
              # Removes this node from the tree if it's a silent comment.
         | 
| 54 54 | 
             
              def visit_comment(node)
         | 
| 55 55 | 
             
                return [] if node.invisible?
         | 
| 56 | 
            -
                 | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
                  node.value = run_interp([Sass::Script::String.new(node.value)])
         | 
| 61 | 
            -
                end
         | 
| 56 | 
            +
                check_for_loud_silent_comment node
         | 
| 57 | 
            +
                check_for_comment_interp node
         | 
| 58 | 
            +
                node.resolved_value = run_interp_no_strip(node.value)
         | 
| 59 | 
            +
                node.resolved_value.gsub!(/\\([\\#])/, '\1')
         | 
| 62 60 | 
             
                node
         | 
| 63 61 | 
             
              end
         | 
| 64 62 |  | 
| @@ -278,14 +276,18 @@ END | |
| 278 276 |  | 
| 279 277 | 
             
              private
         | 
| 280 278 |  | 
| 281 | 
            -
              def  | 
| 279 | 
            +
              def run_interp_no_strip(text)
         | 
| 282 280 | 
             
                text.map do |r|
         | 
| 283 281 | 
             
                  next r if r.is_a?(String)
         | 
| 284 282 | 
             
                  val = r.perform(@environment)
         | 
| 285 283 | 
             
                  # Interpolated strings should never render with quotes
         | 
| 286 284 | 
             
                  next val.value if val.is_a?(Sass::Script::String)
         | 
| 287 285 | 
             
                  val.to_s
         | 
| 288 | 
            -
                end.join | 
| 286 | 
            +
                end.join
         | 
| 287 | 
            +
              end
         | 
| 288 | 
            +
             | 
| 289 | 
            +
              def run_interp(text)
         | 
| 290 | 
            +
                run_interp_no_strip(text).strip
         | 
| 289 291 | 
             
              end
         | 
| 290 292 |  | 
| 291 293 | 
             
              def handle_include_loop!(node)
         | 
| @@ -301,4 +303,30 @@ END | |
| 301 303 | 
             
                end.join("\n")
         | 
| 302 304 | 
             
                raise Sass::SyntaxError.new(msg)
         | 
| 303 305 | 
             
              end
         | 
| 306 | 
            +
             | 
| 307 | 
            +
              def check_for_loud_silent_comment(node)
         | 
| 308 | 
            +
                return unless node.loud && node.silent
         | 
| 309 | 
            +
                Sass::Util.sass_warn <<MESSAGE
         | 
| 310 | 
            +
            WARNING:
         | 
| 311 | 
            +
            On line #{node.line}#{" of '#{node.filename}'" if node.filename}
         | 
| 312 | 
            +
            `//` comments will no longer be allowed to use the `!` flag in Sass 3.2.
         | 
| 313 | 
            +
            Please change to `/*` comments.
         | 
| 314 | 
            +
            MESSAGE
         | 
| 315 | 
            +
              end
         | 
| 316 | 
            +
             | 
| 317 | 
            +
              def check_for_comment_interp(node)
         | 
| 318 | 
            +
                return if node.loud
         | 
| 319 | 
            +
                node.value.each do |e|
         | 
| 320 | 
            +
                  next unless e.is_a?(String)
         | 
| 321 | 
            +
                  e.scan(/(\\*)#\{/) do |esc|
         | 
| 322 | 
            +
                    Sass::Util.sass_warn <<MESSAGE if esc.first.size.even?
         | 
| 323 | 
            +
            WARNING:
         | 
| 324 | 
            +
            On line #{node.line}#{" of '#{node.filename}'" if node.filename}
         | 
| 325 | 
            +
            Comments will evaluate the contents of interpolations (\#{ ... }) in Sass 3.2.
         | 
| 326 | 
            +
            Please escape the interpolation by adding a backslash before the `#`.
         | 
| 327 | 
            +
            MESSAGE
         | 
| 328 | 
            +
                    return
         | 
| 329 | 
            +
                  end
         | 
| 330 | 
            +
                end
         | 
| 331 | 
            +
              end
         | 
| 304 332 | 
             
            end
         | 
| @@ -57,21 +57,11 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base | |
| 57 57 |  | 
| 58 58 | 
             
              def visit_comment(node)
         | 
| 59 59 | 
             
                return if node.invisible?
         | 
| 60 | 
            -
                spaces = ('  ' * [@tabs - node. | 
| 60 | 
            +
                spaces = ('  ' * [@tabs - node.resolved_value[/^ */].size, 0].max)
         | 
| 61 61 |  | 
| 62 | 
            -
                content = node. | 
| 62 | 
            +
                content = node.resolved_value.gsub(/^/, spaces).gsub(%r{^(\s*)//(.*)$}) do |md|
         | 
| 63 63 | 
             
                  "#{$1}/*#{$2} */"
         | 
| 64 64 | 
             
                end
         | 
| 65 | 
            -
                if content =~ /[^\\]\#\{.*\}/
         | 
| 66 | 
            -
                  Sass::Util.sass_warn <<MESSAGE
         | 
| 67 | 
            -
            WARNING:
         | 
| 68 | 
            -
            On line #{node.line}#{" of '#{node.filename}'" if node.filename}
         | 
| 69 | 
            -
            Comments will evaluate the contents of interpolations (\#{ ... }) in Sass 3.2.
         | 
| 70 | 
            -
            Please escape the interpolation by adding a backslash before the hash sign.
         | 
| 71 | 
            -
            MESSAGE
         | 
| 72 | 
            -
                elsif content =~ /\\\#\{.*\}/
         | 
| 73 | 
            -
                  content.gsub!(/\\(\#\{.*\})/, '\1')
         | 
| 74 | 
            -
                end
         | 
| 75 65 | 
             
                content.gsub!(/\n +(\* *(?!\/))?/, ' ') if (node.style == :compact || node.style == :compressed) && !node.loud
         | 
| 76 66 | 
             
                content
         | 
| 77 67 | 
             
              end
         | 
    
        data/lib/sass/util.rb
    CHANGED
    
    | @@ -612,6 +612,57 @@ MSG | |
| 612 612 | 
             
                  '"' + obj.gsub(/[\x00-\x7F]+/) {|s| s.inspect[1...-1]} + '"'
         | 
| 613 613 | 
             
                end
         | 
| 614 614 |  | 
| 615 | 
            +
                # Extracts the non-string vlaues from an array containing both strings and non-strings.
         | 
| 616 | 
            +
                # These values are replaced with escape sequences.
         | 
| 617 | 
            +
                # This can be undone using \{#inject\_values}.
         | 
| 618 | 
            +
                #
         | 
| 619 | 
            +
                # This is useful e.g. when we want to do string manipulation
         | 
| 620 | 
            +
                # on an interpolated string.
         | 
| 621 | 
            +
                #
         | 
| 622 | 
            +
                # The precise format of the resulting string is not guaranteed.
         | 
| 623 | 
            +
                # However, it is guaranteed that newlines and whitespace won't be affected.
         | 
| 624 | 
            +
                #
         | 
| 625 | 
            +
                # @param arr [Array] The array from which values are extracted.
         | 
| 626 | 
            +
                # @return [(String, Array)] The resulting string, and an array of extracted values.
         | 
| 627 | 
            +
                def extract_values(arr)
         | 
| 628 | 
            +
                  values = []
         | 
| 629 | 
            +
                  return arr.map do |e|
         | 
| 630 | 
            +
                    next e.gsub('{', '{{') if e.is_a?(String)
         | 
| 631 | 
            +
                    values << e
         | 
| 632 | 
            +
                    next "{#{values.count - 1}}"
         | 
| 633 | 
            +
                  end.join, values
         | 
| 634 | 
            +
                end
         | 
| 635 | 
            +
             | 
| 636 | 
            +
                # Undoes \{#extract\_values} by transforming a string with escape sequences
         | 
| 637 | 
            +
                # into an array of strings and non-string values.
         | 
| 638 | 
            +
                #
         | 
| 639 | 
            +
                # @param str [String] The string with escape sequences.
         | 
| 640 | 
            +
                # @param values [Array] The array of values to inject.
         | 
| 641 | 
            +
                # @return [Array] The array of strings and values.
         | 
| 642 | 
            +
                def inject_values(str, values)
         | 
| 643 | 
            +
                  return [str.gsub('{{', '{')] if values.empty?
         | 
| 644 | 
            +
                  # Add an extra { so that we process the tail end of the string
         | 
| 645 | 
            +
                  result = (str + '{{').scan(/(.*?)(?:(\{\{)|\{(\d+)\})/m).map do |(pre, esc, n)|
         | 
| 646 | 
            +
                    [pre, esc ? '{' : '', n ? values[n.to_i] : '']
         | 
| 647 | 
            +
                  end.flatten(1)
         | 
| 648 | 
            +
                  result[-2] = '' # Get rid of the extra {
         | 
| 649 | 
            +
                  merge_adjacent_strings(result).reject {|s| s == ''}
         | 
| 650 | 
            +
                end
         | 
| 651 | 
            +
             | 
| 652 | 
            +
                # Allows modifications to be performed on the string form
         | 
| 653 | 
            +
                # of an array containing both strings and non-strings.
         | 
| 654 | 
            +
                #
         | 
| 655 | 
            +
                # @param arr [Array] The array from which values are extracted.
         | 
| 656 | 
            +
                # @yield [str] A block in which string manipulation can be done to the array.
         | 
| 657 | 
            +
                # @yieldparam str [String] The string form of `arr`.
         | 
| 658 | 
            +
                # @yieldreturn [String] The modified string.
         | 
| 659 | 
            +
                # @return [Array] The modified, interpolated array.
         | 
| 660 | 
            +
                def with_extracted_values(arr)
         | 
| 661 | 
            +
                  str, vals = extract_values(arr)
         | 
| 662 | 
            +
                  str = yield str
         | 
| 663 | 
            +
                  inject_values(str, vals)
         | 
| 664 | 
            +
                end
         | 
| 665 | 
            +
             | 
| 615 666 | 
             
                ## Static Method Stuff
         | 
| 616 667 |  | 
| 617 668 | 
             
                # The context in which the ERB for \{#def\_static\_method} will be run.
         | 
| @@ -1131,17 +1131,13 @@ div | |
| 1131 1131 | 
             
            SASS
         | 
| 1132 1132 | 
             
              end
         | 
| 1133 1133 |  | 
| 1134 | 
            -
             | 
| 1134 | 
            +
               def test_loud_comment_conversion
         | 
| 1135 1135 | 
             
                assert_renders(<<SASS, <<SCSS)
         | 
| 1136 1136 | 
             
            /*! \#{"interpolated"}
         | 
| 1137 | 
            -
            /*!
         | 
| 1138 | 
            -
             *  \#{"also interpolated"}
         | 
| 1139 1137 | 
             
            SASS
         | 
| 1140 1138 | 
             
            /*! \#{"interpolated"} */
         | 
| 1141 | 
            -
            /*!
         | 
| 1142 | 
            -
             *  \#{"also interpolated"} */
         | 
| 1143 1139 | 
             
            SCSS
         | 
| 1144 | 
            -
                assert_renders(<<SASS, <<SCSS)
         | 
| 1140 | 
            +
                silence_warnings {assert_renders(<<SASS, <<SCSS)}
         | 
| 1145 1141 | 
             
            //! \#{"interpolated"}
         | 
| 1146 1142 | 
             
            //!
         | 
| 1147 1143 | 
             
            //! \#{"also interpolated"}
         | 
    
        data/test/sass/engine_test.rb
    CHANGED
    
    | @@ -1570,11 +1570,11 @@ foo | |
| 1570 1570 | 
             
               */
         | 
| 1571 1571 | 
             
            SASS
         | 
| 1572 1572 | 
             
              end
         | 
| 1573 | 
            +
             | 
| 1573 1574 | 
             
              def test_loud_comment_in_silent_comment
         | 
| 1574 | 
            -
                assert_equal <<CSS, render(<<SASS, :style => :compressed)
         | 
| 1575 | 
            +
                silence_warnings {assert_equal <<CSS, render(<<SASS, :style => :compressed)}
         | 
| 1575 1576 | 
             
            foo{color:blue;/* foo */
         | 
| 1576 1577 | 
             
            /* bar */
         | 
| 1577 | 
            -
            /* */
         | 
| 1578 1578 | 
             
            /* bip */
         | 
| 1579 1579 | 
             
            /* baz */}
         | 
| 1580 1580 | 
             
            CSS
         | 
| @@ -1590,8 +1590,7 @@ SASS | |
| 1590 1590 |  | 
| 1591 1591 | 
             
              def test_loud_comment_is_evaluated
         | 
| 1592 1592 | 
             
                assert_equal <<CSS, render(<<SASS)
         | 
| 1593 | 
            -
            /*
         | 
| 1594 | 
            -
             * Hue: 327.216deg */
         | 
| 1593 | 
            +
            /* Hue: 327.216deg */
         | 
| 1595 1594 | 
             
            CSS
         | 
| 1596 1595 | 
             
            /*!
         | 
| 1597 1596 | 
             
              Hue: \#{hue(#f836a0)}
         | 
| @@ -2030,6 +2029,31 @@ CSS | |
| 2030 2029 |  | 
| 2031 2030 | 
             
              # Regression tests
         | 
| 2032 2031 |  | 
| 2032 | 
            +
              def test_interpolated_comment_in_mixin
         | 
| 2033 | 
            +
                assert_equal <<CSS, render(<<SASS)
         | 
| 2034 | 
            +
            /* color: red */
         | 
| 2035 | 
            +
            .foo {
         | 
| 2036 | 
            +
              color: red; }
         | 
| 2037 | 
            +
             | 
| 2038 | 
            +
            /* color: blue */
         | 
| 2039 | 
            +
            .foo {
         | 
| 2040 | 
            +
              color: blue; }
         | 
| 2041 | 
            +
             | 
| 2042 | 
            +
            /* color: green */
         | 
| 2043 | 
            +
            .foo {
         | 
| 2044 | 
            +
              color: green; }
         | 
| 2045 | 
            +
            CSS
         | 
| 2046 | 
            +
            =foo($var)
         | 
| 2047 | 
            +
              /*! color: \#{$var}
         | 
| 2048 | 
            +
              .foo
         | 
| 2049 | 
            +
                color: $var
         | 
| 2050 | 
            +
             | 
| 2051 | 
            +
            +foo(red)
         | 
| 2052 | 
            +
            +foo(blue)
         | 
| 2053 | 
            +
            +foo(green)
         | 
| 2054 | 
            +
            SASS
         | 
| 2055 | 
            +
              end
         | 
| 2056 | 
            +
             | 
| 2033 2057 | 
             
              def test_parens_in_mixins
         | 
| 2034 2058 | 
             
                assert_equal(<<CSS, render(<<SASS))
         | 
| 2035 2059 | 
             
            .foo {
         | 
| @@ -2308,7 +2332,16 @@ SASS | |
| 2308 2332 | 
             
            WARNING:
         | 
| 2309 2333 | 
             
            On line 1 of 'test_comment_interpolation_warning_inline.sass'
         | 
| 2310 2334 | 
             
            Comments will evaluate the contents of interpolations (\#{ ... }) in Sass 3.2.
         | 
| 2311 | 
            -
            Please escape the interpolation by adding a backslash before the  | 
| 2335 | 
            +
            Please escape the interpolation by adding a backslash before the `#`.
         | 
| 2336 | 
            +
            END
         | 
| 2337 | 
            +
              end
         | 
| 2338 | 
            +
             | 
| 2339 | 
            +
              def test_loud_silent_comment_warning
         | 
| 2340 | 
            +
                assert_warning(<<END) {render("//! \#{foo}")}
         | 
| 2341 | 
            +
            WARNING:
         | 
| 2342 | 
            +
            On line 1 of 'test_loud_silent_comment_warning_inline.sass'
         | 
| 2343 | 
            +
            `//` comments will no longer be allowed to use the `!` flag in Sass 3.2.
         | 
| 2344 | 
            +
            Please change to `/*` comments.
         | 
| 2312 2345 | 
             
            END
         | 
| 2313 2346 | 
             
              end
         | 
| 2314 2347 |  | 
    
        data/test/sass/scss/css_test.rb
    CHANGED
    
    | @@ -800,6 +800,12 @@ SCSS | |
| 800 800 | 
             
                assert_selector_parses('E*:hover')
         | 
| 801 801 | 
             
              end
         | 
| 802 802 |  | 
| 803 | 
            +
              def test_spaceless_combo_selectors
         | 
| 804 | 
            +
                assert_equal "E > F {\n  a: b; }\n", render("E>F { a: b;} ")
         | 
| 805 | 
            +
                assert_equal "E ~ F {\n  a: b; }\n", render("E~F { a: b;} ")
         | 
| 806 | 
            +
                assert_equal "E + F {\n  a: b; }\n", render("E+F { a: b;} ")
         | 
| 807 | 
            +
              end
         | 
| 808 | 
            +
             | 
| 803 809 | 
             
              ## Errors
         | 
| 804 810 |  | 
| 805 811 | 
             
              def test_invalid_directives
         | 
    
        data/test/sass/util_test.rb
    CHANGED
    
    | @@ -208,6 +208,18 @@ class UtilTest < Test::Unit::TestCase | |
| 208 208 | 
             
                assert(set_eql?(s1, s2))
         | 
| 209 209 | 
             
              end
         | 
| 210 210 |  | 
| 211 | 
            +
              def test_extract_and_inject_values
         | 
| 212 | 
            +
                test = lambda {|arr| assert_equal(arr, with_extracted_values(arr) {|str| str})}
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                test[['foo bar']]
         | 
| 215 | 
            +
                test[['foo {12} bar']]
         | 
| 216 | 
            +
                test[['foo {{12} bar']]
         | 
| 217 | 
            +
                test[['foo {{1', 12, '2} bar']]
         | 
| 218 | 
            +
                test[['foo 1', 2, '{3', 4, 5, 6, '{7}', 8]]
         | 
| 219 | 
            +
                test[['foo 1', [2, 3, 4], ' bar']]
         | 
| 220 | 
            +
                test[['foo ', 1, "\n bar\n", [2, 3, 4], "\n baz"]]
         | 
| 221 | 
            +
              end
         | 
| 222 | 
            +
             | 
| 211 223 | 
             
              def test_caller_info
         | 
| 212 224 | 
             
                assert_equal(["/tmp/foo.rb", 12, "fizzle"], caller_info("/tmp/foo.rb:12: in `fizzle'"))
         | 
| 213 225 | 
             
                assert_equal(["/tmp/foo.rb", 12, nil], caller_info("/tmp/foo.rb:12"))
         | 
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: sass
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 4 | 
            +
              hash: 17
         | 
| 5 5 | 
             
              prerelease: false
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 3
         | 
| 8 8 | 
             
              - 1
         | 
| 9 | 
            -
              -  | 
| 10 | 
            -
              version: 3.1. | 
| 9 | 
            +
              - 9
         | 
| 10 | 
            +
              version: 3.1.9
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - Nathan Weizenbaum
         | 
| @@ -17,7 +17,7 @@ autorequire: | |
| 17 17 | 
             
            bindir: bin
         | 
| 18 18 | 
             
            cert_chain: []
         | 
| 19 19 |  | 
| 20 | 
            -
            date: 2011- | 
| 20 | 
            +
            date: 2011-10-06 00:00:00 -07:00
         | 
| 21 21 | 
             
            default_executable: 
         | 
| 22 22 | 
             
            dependencies: 
         | 
| 23 23 | 
             
            - !ruby/object:Gem::Dependency 
         |