/scalate-jruby/src/main/resources/haml-3.0.25/lib/sass/tree/rule_node.rb
http://github.com/scalate/scalate · Ruby · 261 lines · 146 code · 33 blank · 82 comment · 27 complexity · 25896d0d288f5e5a10d745513c60e248 MD5 · raw file
- require 'pathname'
- require 'uri'
- module Sass::Tree
- # A static node reprenting a CSS rule.
- #
- # @see Sass::Tree
- class RuleNode < Node
- # The character used to include the parent selector
- PARENT = '&'
- # The CSS selector for this rule,
- # interspersed with {Sass::Script::Node}s
- # representing `#{}`-interpolation.
- # Any adjacent strings will be merged together.
- #
- # @return [Array<String, Sass::Script::Node>]
- attr_accessor :rule
- # The CSS selector for this rule,
- # without any unresolved interpolation
- # but with parent references still intact.
- # It's only set once {Tree::Node#perform} has been called.
- #
- # @return [Selector::CommaSequence]
- attr_accessor :parsed_rules
- # The CSS selector for this rule,
- # without any unresolved interpolation or parent references.
- # It's only set once {Tree::Node#cssize} has been called.
- #
- # @return [Selector::CommaSequence]
- attr_accessor :resolved_rules
- # How deep this rule is indented
- # relative to a base-level rule.
- # This is only greater than 0 in the case that:
- #
- # * This node is in a CSS tree
- # * The style is :nested
- # * This is a child rule of another rule
- # * The parent rule has properties, and thus will be rendered
- #
- # @return [Fixnum]
- attr_accessor :tabs
- # Whether or not this rule is the last rule in a nested group.
- # This is only set in a CSS tree.
- #
- # @return [Boolean]
- attr_accessor :group_end
- # @param rule [Array<String, Sass::Script::Node>]
- # The CSS rule. See \{#rule}
- def initialize(rule)
- #p rule
- merged = Haml::Util.merge_adjacent_strings(rule)
- #p merged
- @rule = Haml::Util.strip_string_array(merged)
- #p @rule
- @tabs = 0
- super()
- end
- # Compares the contents of two rules.
- #
- # @param other [Object] The object to compare with
- # @return [Boolean] Whether or not this node and the other object
- # are the same
- def ==(other)
- self.class == other.class && rule == other.rule && super
- end
- # Adds another {RuleNode}'s rules to this one's.
- #
- # @param node [RuleNode] The other node
- def add_rules(node)
- @rule = Haml::Util.strip_string_array(
- Haml::Util.merge_adjacent_strings(@rule + ["\n"] + node.rule))
- end
- # @return [Boolean] Whether or not this rule is continued on the next line
- def continued?
- last = @rule.last
- last.is_a?(String) && last[-1] == ?,
- end
- # @see Node#to_sass
- def to_sass(tabs, opts = {})
- name = selector_to_sass(rule, opts)
- name = "\\" + name if name[0] == ?:
- name.gsub(/^/, ' ' * tabs) + children_to_src(tabs, opts, :sass)
- end
- # @see Node#to_scss
- def to_scss(tabs, opts = {})
- name = selector_to_scss(rule, tabs, opts)
- res = name + children_to_src(tabs, opts, :scss)
- if children.last.is_a?(CommentNode) && children.last.silent
- res.slice!(-3..-1)
- res << "\n" << (' ' * tabs) << "}\n"
- end
- res
- end
- # Extends this Rule's selector with the given `extends`.
- #
- # @see Node#do_extend
- def do_extend(extends)
- node = dup
- node.resolved_rules = resolved_rules.do_extend(extends)
- node
- end
- protected
- # Computes the CSS for the rule.
- #
- # @param tabs [Fixnum] The level of indentation for the CSS
- # @return [String] The resulting CSS
- def _to_s(tabs)
- tabs = tabs + self.tabs
- rule_separator = style == :compressed ? ',' : ', '
- line_separator =
- case style
- when :nested, :expanded; "\n"
- when :compressed; ""
- else; " "
- end
- rule_indent = ' ' * (tabs - 1)
- per_rule_indent, total_indent = [:nested, :expanded].include?(style) ? [rule_indent, ''] : ['', rule_indent]
- total_rule = total_indent + resolved_rules.members.
- map {|seq| seq.to_a.join.gsub(/([^,])\n/m, style == :compressed ? '\1 ' : "\\1\n")}.
- join(rule_separator).split("\n").map do |line|
- per_rule_indent + line.strip
- end.join(line_separator)
- to_return = ''
- old_spaces = ' ' * (tabs - 1)
- spaces = ' ' * tabs
- if style != :compressed
- if @options[:debug_info]
- to_return << debug_info_rule.to_s(tabs) << "\n"
- elsif @options[:line_comments]
- to_return << "#{old_spaces}/* line #{line}"
- if filename
- relative_filename = if @options[:css_filename]
- begin
- Pathname.new(filename).relative_path_from(
- Pathname.new(File.dirname(@options[:css_filename]))).to_s
- rescue ArgumentError
- nil
- end
- end
- relative_filename ||= filename
- to_return << ", #{relative_filename}"
- end
- to_return << " */\n"
- end
- end
- if style == :compact
- properties = children.map { |a| a.to_s(1) }.join(' ')
- to_return << "#{total_rule} { #{properties} }#{"\n" if group_end}"
- elsif style == :compressed
- properties = children.map { |a| a.to_s(1) }.join(';')
- to_return << "#{total_rule}{#{properties}}"
- else
- properties = children.map { |a| a.to_s(tabs + 1) }.join("\n")
- end_props = (style == :expanded ? "\n" + old_spaces : ' ')
- to_return << "#{total_rule} {\n#{properties}#{end_props}}#{"\n" if group_end}"
- end
- to_return
- end
- # Runs SassScript interpolation in the selector,
- # and then parses the result into a {Sass::Selector::CommaSequence}.
- #
- # @param environment [Sass::Environment] The lexical environment containing
- # variable and mixin values
- def perform!(environment)
- @parsed_rules = Sass::SCSS::StaticParser.new(run_interp(@rule, environment), self.line).
- parse_selector(self.filename)
- super
- end
- # Converts nested rules into a flat list of rules.
- #
- # @param extends [Haml::Util::SubsetMap{Selector::Simple => Selector::Sequence}]
- # The extensions defined for this tree
- # @param parent [RuleNode, nil] The parent node of this node,
- # or nil if the parent isn't a {RuleNode}
- def _cssize(extends, parent)
- node = super
- rules = node.children.select {|c| c.is_a?(RuleNode)}
- props = node.children.reject {|c| c.is_a?(RuleNode) || c.invisible?}
- unless props.empty?
- node.children = props
- rules.each {|r| r.tabs += 1} if style == :nested
- rules.unshift(node)
- end
- rules.last.group_end = true unless parent || rules.empty?
- rules
- end
- # Resolves parent references and nested selectors,
- # and updates the indentation based on the parent's indentation.
- #
- # @param extends [Haml::Util::SubsetMap{Selector::Simple => Selector::Sequence}]
- # The extensions defined for this tree
- # @param parent [RuleNode, nil] The parent node of this node,
- # or nil if the parent isn't a {RuleNode}
- # @raise [Sass::SyntaxError] if the rule has no parents but uses `&`
- def cssize!(extends, parent)
- self.resolved_rules = @parsed_rules.resolve_parent_refs(parent && parent.resolved_rules)
- super
- end
- # A hash that will be associated with this rule in the CSS document
- # if the {file:SASS_REFERENCE.md#debug_info-option `:debug_info` option} is enabled.
- # This data is used by e.g. [the FireSass Firebug extension](https://addons.mozilla.org/en-US/firefox/addon/103988).
- #
- # @return [{#to_s => #to_s}]
- def debug_info
- {:filename => filename && ("file://" + URI.escape(File.expand_path(filename))),
- :line => self.line}
- end
- private
- def debug_info_rule
- node = DirectiveNode.new("@media -sass-debug-info")
- debug_info.map {|k, v| [k.to_s, v.to_s]}.sort.each do |k, v|
- rule = RuleNode.new([""])
- rule.resolved_rules = Sass::Selector::CommaSequence.new(
- [Sass::Selector::Sequence.new(
- [Sass::Selector::SimpleSequence.new(
- [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)])
- ])
- ])
- prop = PropNode.new([""], "", :new)
- prop.resolved_name = "font-family"
- prop.resolved_value = Sass::SCSS::RX.escape_ident(v.to_s)
- rule << prop
- node << rule
- end
- node.options = @options.merge(:debug_info => false, :line_comments => false, :style => :compressed)
- node
- end
- end
- end