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; }"
@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.
# 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
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
# 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`
# File lib/sass/css.rb, line 59 59: def source_encoding 60: check_encoding! 61: @original_encoding 62: end
Parses the CSS template and applies various transformations
@return [Tree::Node] The root node of the parsed tree
# 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
# 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
# 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 #
# 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
# 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
# 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
# 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/).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
# 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
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.