Class Sass::CSS
In: lib/sass/css.rb
Parent: Object
Haml::Util Engine Color SyntaxError UnitConversionError StandardError AbstractSequence CommaSequence Sequence SimpleSequence Simple Parent Universal Class SelectorPseudoClass Id Pseudo Attribute Interpolation Element Node Operation Literal UnaryOperation StringInterpolation Funcall Interpolation Variable Lexer CssLexer Number Bool String Parser Parser CssParser EvaluationContext StaticParser SassParser CssParser Node DebugNode IfNode CommentNode ForNode PropNode MixinNode DirectiveNode ExtendNode VariableNode WarnNode RootNode WhileNode RuleNode MixinDefNode Enumerable ImportNode Merb::BootLoader MerbBootLoader Repl CSS Environment Rack StalenessChecker lib/sass/repl.rb lib/sass/css.rb lib/sass/environment.rb lib/sass/error.rb lib/sass/engine.rb lib/sass/selector/simple_sequence.rb lib/sass/selector/abstract_sequence.rb lib/sass/selector/sequence.rb lib/sass/selector/comma_sequence.rb lib/sass/selector/simple.rb lib/sass/selector.rb Selector lib/sass/script/css_parser.rb lib/sass/script/lexer.rb lib/sass/script/color.rb lib/sass/script/string.rb lib/sass/script/unary_operation.rb lib/sass/script/variable.rb lib/sass/script/funcall.rb lib/sass/script/string_interpolation.rb lib/sass/script/operation.rb lib/sass/script/bool.rb lib/sass/script/parser.rb lib/sass/script/literal.rb lib/sass/script/node.rb lib/sass/script/interpolation.rb lib/sass/script/css_lexer.rb lib/sass/script/number.rb lib/sass/script/functions.rb Functions Script lib/sass/scss/sass_parser.rb lib/sass/scss/static_parser.rb lib/sass/scss/parser.rb lib/sass/scss/css_parser.rb ScriptLexer ScriptParser RX SCSS Files Callbacks lib/sass/tree/while_node.rb lib/sass/tree/if_node.rb lib/sass/tree/mixin_def_node.rb lib/sass/tree/debug_node.rb lib/sass/tree/root_node.rb lib/sass/tree/for_node.rb lib/sass/tree/import_node.rb lib/sass/tree/prop_node.rb lib/sass/tree/node.rb lib/sass/tree/comment_node.rb lib/sass/tree/extend_node.rb lib/sass/tree/mixin_node.rb lib/sass/tree/warn_node.rb lib/sass/tree/directive_node.rb lib/sass/tree/rule_node.rb lib/sass/tree/variable_node.rb Tree lib/sass/plugin/rack.rb lib/sass/plugin/staleness_checker.rb lib/sass/plugin/merb.rb Plugin Sass dot/m_85_0.png

This class converts CSS documents into Sass or SCSS templates. It works by parsing the CSS document into a {Sass::Tree} structure, and then applying various transformations to the structure to produce more concise and idiomatic Sass/SCSS.

Example usage:

    Sass::CSS.new("p { color: blue }").render(:sass) #=> "p\n  color: blue"
    Sass::CSS.new("p { color: blue }").render(:scss) #=> "p {\n  color: blue; }"

Methods

Public Class methods

@param template [String] The CSS stylesheet.

  This stylesheet can be encoded using any encoding
  that can be converted to Unicode.
  If the stylesheet contains an `@charset` declaration,
  that overrides the Ruby encoding
  (see {file:SASS_REFERENCE.md#encodings the encoding documentation})

@option options :old [Boolean] (false)

    Whether or not to output old property syntax
    (`:color blue` as opposed to `color: blue`).
    This is only meaningful when generating Sass code,
    rather than SCSS.

[Source]

    # File lib/sass/css.rb, line 28
28:     def initialize(template, options = {})
29:       if template.is_a? IO
30:         template = template.read
31:       end
32: 
33:       @options = options.dup
34:       # Backwards compatibility
35:       @options[:old] = true if @options[:alternate] == false
36:       @template = template
37:     end

Public Instance methods

Converts the CSS template into Sass or SCSS code.

@param fmt [Symbol] `:sass` or `:scss`, designating the format to return. @return [String] The resulting Sass or SCSS code @raise [Sass::SyntaxError] if there‘s an error parsing the CSS template

[Source]

    # File lib/sass/css.rb, line 44
44:     def render(fmt = :sass)
45:       check_encoding!
46:       build_tree.send("to_#{fmt}", @options).strip + "\n"
47:     rescue Sass::SyntaxError => err
48:       err.modify_backtrace(:filename => @options[:filename] || '(css)')
49:       raise err
50:     end

Returns the original encoding of the document, or `nil` under Ruby 1.8.

@return [Encoding, nil] @raise [Encoding::UndefinedConversionError] if the source encoding

  cannot be converted to UTF-8

@raise [ArgumentError] if the document uses an unknown encoding with `@charset`

[Source]

    # File lib/sass/css.rb, line 59
59:     def source_encoding
60:       check_encoding!
61:       @original_encoding
62:     end

Private Instance methods

Parses the CSS template and applies various transformations

@return [Tree::Node] The root node of the parsed tree

[Source]

    # File lib/sass/css.rb, line 77
77:     def build_tree
78:       root = Sass::SCSS::CssParser.new(@template).parse
79:       expand_commas      root
80:       parent_ref_rules   root
81:       remove_parent_refs root
82:       flatten_rules      root
83:       fold_commas        root
84:       root
85:     end

[Source]

    # File lib/sass/css.rb, line 66
66:     def check_encoding!
67:       return if @checked_encoding
68:       @checked_encoding = true
69:       @template, @original_encoding = Haml::Util.check_sass_encoding(@template) do |msg, line|
70:         raise Sass::SyntaxError.new(msg, :line => line)
71:       end
72:     end

Transform

    foo, bar, baz
      color: blue

into

    foo
      color: blue
    bar
      color: blue
    baz
      color: blue

@param root [Tree::Node] The parent node

[Source]

     # File lib/sass/css.rb, line 102
102:     def expand_commas(root)
103:       root.children.map! do |child|
104:         unless child.is_a?(Tree::RuleNode) && child.rule.first.include?(',')
105:           expand_commas(child) if child.is_a?(Tree::DirectiveNode)
106:           next child
107:         end
108:         child.rule.first.split(',').map do |rule|
109:           node = Tree::RuleNode.new([rule.strip])
110:           node.children = child.children
111:           node
112:         end
113:       end
114:       root.children.flatten!
115:     end

Flattens a single rule

@param rule [Tree::RuleNode] The candidate for flattening @see flatten_rules

[Source]

     # File lib/sass/css.rb, line 243
243:     def flatten_rule(rule)
244:       while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
245:         child = rule.children.first
246: 
247:         if child.rule.first[0] == ?&
248:           rule.rule = [child.rule.first.gsub(/^&/, rule.rule.first)]
249:         else
250:           rule.rule = ["#{rule.rule.first} #{child.rule.first}"]
251:         end
252: 
253:         rule.children = child.children
254:       end
255: 
256:       flatten_rules(rule)
257:     end

Flatten rules so that

    foo
      bar
        color: red

becomes

    foo bar
      color: red

and

    foo
      &.bar
        color: blue

becomes

    foo.bar
      color: blue

@param root [Tree::Node] The parent node

[Source]

     # File lib/sass/css.rb, line 228
228:     def flatten_rules(root)
229:       root.children.each do |child|
230:         case child
231:         when Tree::RuleNode
232:           flatten_rule(child)
233:         when Tree::DirectiveNode
234:           flatten_rules(child)
235:         end
236:       end
237:     end

Transform

    foo
      bar
        color: blue
      baz
        color: blue

into

    foo
      bar, baz
        color: blue

@param rule [Tree::RuleNode] The candidate for flattening

[Source]

     # File lib/sass/css.rb, line 274
274:     def fold_commas(root)
275:       prev_rule = nil
276:       root.children.map! do |child|
277:         unless child.is_a?(Tree::RuleNode)
278:           fold_commas(child) if child.is_a?(Tree::DirectiveNode)
279:           next child
280:         end
281: 
282:         if prev_rule && prev_rule.children == child.children
283:           prev_rule.rule.first << ", #{child.rule.first}"
284:           next nil
285:         end
286: 
287:         fold_commas(child)
288:         prev_rule = child
289:         child
290:       end
291:       root.children.compact!
292:     end

Make rules use parent refs so that

    foo
      color: green
    foo.bar
      color: blue

becomes

    foo
      color: green
      &.bar
        color: blue

This has the side effect of nesting rules, so that

    foo
      color: green
    foo bar
      color: red
    foo baz
      color: blue

becomes

    foo
      color: green
      & bar
        color: red
      & baz
        color: blue

@param root [Tree::Node] The parent node

[Source]

     # File lib/sass/css.rb, line 151
151:     def parent_ref_rules(root)
152:       current_rule = nil
153:       root.children.map! do |child|
154:         unless child.is_a?(Tree::RuleNode)
155:           parent_ref_rules(child) if child.is_a?(Tree::DirectiveNode)
156:           next child
157:         end
158: 
159:         first, rest = child.rule.first.scan(/\A(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?\Z/m).first
160: 
161:         if current_rule.nil? || current_rule.rule.first != first
162:           current_rule = Tree::RuleNode.new([first])
163:         end
164: 
165:         if rest
166:           child.rule = ["&" + rest]
167:           current_rule << child
168:         else
169:           current_rule.children += child.children
170:         end
171: 
172:         current_rule
173:       end
174:       root.children.compact!
175:       root.children.uniq!
176: 
177:       root.children.each { |v| parent_ref_rules(v) }
178:     end

Remove useless parent refs so that

    foo
      & bar
        color: blue

becomes

    foo
      bar
        color: blue

@param root [Tree::Node] The parent node

[Source]

     # File lib/sass/css.rb, line 193
193:     def remove_parent_refs(root)
194:       root.children.each do |child|
195:         case child
196:         when Tree::RuleNode
197:           child.rule.first.gsub! /^& +/, ''
198:           remove_parent_refs child
199:         when Tree::DirectiveNode
200:           remove_parent_refs child
201:         end
202:       end
203:     end

[Validate]