class MirrorMirror::MirrorVisitor

Public Class Methods

new() click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 5
def initialize
  @in_meta_directive = false
  @nested = false
  @enabled = false
  @inline = false
  @options = {}
  @property_transformers = Transformation::PropertyTransformation.instances
  @debug = false
end

Public Instance Methods

visit(node) click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 24
def visit(node)
  method = "visit_#{node_name node}"
  if self.respond_to?(method, true)
    self.send(method, node) {node.children = visit_children(node)}
  else
    node.children = visit_children(node)
    node
  end
end
visit_children(parent) click to toggle source
Calls superclass method
# File lib/mirror-mirror/mirror_visitor.rb, line 34
def visit_children(parent)
  r = super
  r.flatten!
  r.compact!
  r
end
visit_directive(directive_node) { || ... } click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 112
def visit_directive(directive_node)
  if directive_node.resolved_value.strip == "@-mirror-mirror"
    @in_meta_directive = true
    begin
      yield
    ensure
      @in_meta_directive = false
    end
    nil # remove this node from the output
  elsif directive_node.resolved_value.strip == "@-mirror-mirror no-flip"
    old_enabled = @enabled
    @enabled = false
    begin
      yield
      directive_node.children
    ensure
      @enabled = old_enabled
    end
  elsif directive_node.resolved_value.strip == "@-mirror-mirror inline-flip"
    old_inline = @inline
    old_enabled = @enabled
    @inline = true
    @enabled = true
    begin
      yield
      directive_node.children
    ensure
      @enabled = old_enabled
      @inline = old_inline
    end
  else
    yield
    directive_node
  end
end
visit_prop(prop_node) click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 49
def visit_prop(prop_node)
  if @in_meta_directive && prop_node.resolved_name == "enabled"
    @enabled = prop_node.resolved_value == "true"
    #if @nested
      #raise Sass::SyntaxError, "Cannot #{@enabled ? 'enable' : 'disable'} mirror flipping in a nested context"
    #end
    puts @enabled ? "ENABLED" : "DISABLED" if @debug
    return prop_node
  end

  puts "PROPERTY: #{prop_node.resolved_name}" if @debug
  unless @enabled
    return prop_node
  end

  prop_name = prop_node.resolved_name.downcase
  value = prop_node.resolved_value
  prefix, prop_name = $1, $2 if prop_name =~ /^(\*|_|#|-moz-|-ms-|-webkit-|-o-)(.*)$/
  original_name = prop_name
  original_value = value
  important = nil

  if value =~ /^(.*[^ ])( *!important *)$/
    value, important = $1, $2
  end

  property_transformers(prop_name, :name).each do |t|
    prop_name = t.transform_name(prop_name)
  end

  property_transformers(original_name, :value).each do |t|
    value = t.transform_value(original_name, value)
  end

  expression = nil
  begin
    property_transformers(original_name, :expression).each do |t|
      expression ||= parsed_value(value, prop_node.line, original_name.size)
      expression = t.transform_expression(original_name, expression)
    end
  rescue Sass::SyntaxError => e
    Sass.logger.warn("Syntax error during mirror flip of `#{original_name}: #{original_value}`: #{e.message}")
    return prop_node
  end
  begin
    value = literalize(expression).to_s(@options) if expression
  rescue => e
    Sass.logger.warn "Failed to stringify the transformation of `#{original_name}: #{original_value}`: #{e.message} (#{expression.class.name})"
    Sass.logger.warn(e.backtrace.join("\n"))
    value = original_value
  end

  if @debug && prop_node.resolved_name != "#{prefix}#{prop_name}"
    puts "CHANGED name FROM #{prop_node.resolved_name} TO #{prefix}#{prop_name}"
  end
  if @debug && prop_node.resolved_value != value
    puts "CHANGED value FROM #{prop_node.resolved_value} TO #{value}"
  end
  prop_node.resolved_name = "#{prefix}#{prop_name}"
  prop_node.resolved_value = "#{value}#{important}"
  prop_node
end
visit_root(root_node) { || ... } click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 15
def visit_root(root_node)
  # XXX set up defaults from options
  @options = root_node.options
  custom_opts = @options[:custom] || {}
  @enabled = !!custom_opts.fetch(:mirror_mirror, MirrorMirror.flipped_by_default)
  root_node.children = yield
  root_node
end
visit_rule(rule_node) { || ... } click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 41
def visit_rule(rule_node)
  puts "RULE: #{rule_node.resolved_rules}" if @debug
  @nested = true;
  yield
  @nested = false;
  rule_node
end

Protected Instance Methods

_slashify(expression) click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 183
def _slashify(expression)
  if expression.is_a?(Sass::Script::List)
    expression.value.map! {|v| _slashify(v) }
    expression.value.flatten!
  elsif expression.is_a?(Sass::Script::Operation)
    operator = Sass::Script::String.new(Sass::Script::Lexer::OPERATORS_REVERSE[expression.operator])
    operator.options = expression.options
    return [_slashify(expression.operand1), operator, _slashify(expression.operand2)]
  end
  expression
end
literalize(expression) click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 162
def literalize(expression)
  case expression
  when Sass::Script::List
    expression.value.map!{|v| literalize(v) }
    expression
  when Sass::Script::Funcall
    expression.send(:to_literal, expression.args.map {|a| literalize(a) })
  else
    expression
  end
end
parsed_value(value, line, offset) click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 158
def parsed_value(value, line, offset)
  slashify(Sass::Script::Parser.new(value, line, offset).parse)
end
property_transformers(name, type) click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 150
def property_transformers(name, type)
  @propert_transformers_by_property ||= {}
  @propert_transformers_by_property[name] ||= {}
  @propert_transformers_by_property[name][type] ||= begin
    @property_transformers.select {|t| t.send(:"transform_#{type}?", name)}
  end
end
slashify(expression) click to toggle source
# File lib/mirror-mirror/mirror_visitor.rb, line 174
def slashify(expression)
  result = _slashify(expression)
  if result.is_a?(Array)
    result = Sass::Script::List.new(result, :space)
    result.options = expression.options
  end
  result
end