class XPath::Renderer

def self.render(node, type)

def self.render(node, type)
  new(type).render(node)
end

def anywhere(element_names)

def anywhere(element_names)
  with_element_conditions('//', element_names)
end

def attribute(current, name)

def attribute(current, name)
  if valid_xml_name?(name)
    "#{current}/@#{name}"
  else
    "#{current}/attribute::*[local-name(.) = #{string_literal(name)}]"
  end
end

def axis(current, name, element_names)

def axis(current, name, element_names)
  with_element_conditions("#{current}/#{name}::", element_names)
end

def binary_operator(name, left, right)

def binary_operator(name, left, right)
  "(#{left} #{name} #{right})"
end

def child(current, element_names)

def child(current, element_names)
  with_element_conditions("#{current}/", element_names)
end

def convert_argument(argument)

def convert_argument(argument)
  case argument
  when Expression, Union then render(argument)
  when Array then argument.map { |element| convert_argument(element) }
  when String then string_literal(argument)
  when Literal then argument.value
  else argument.to_s
  end
end

def css(current, selector)

def css(current, selector)
  paths = Nokogiri::CSS.xpath_for(selector).map do |xpath_selector|
    "#{current}#{xpath_selector}"
  end
  union(paths)
end

def descendant(current, element_names)

def descendant(current, element_names)
  with_element_conditions("#{current}//", element_names)
end

def function(name, *arguments)

def function(name, *arguments)
  "#{name}(#{arguments.join(', ')})"
end

def initialize(type)

def initialize(type)
  @type = type
end

def is(one, two)

def is(one, two)
  if @type == :exact
    binary_operator('=', one, two)
  else
    function(:contains, one, two)
  end
end

def literal(node)

def literal(node)
  node
end

def render(node)

def render(node)
  arguments = node.arguments.map { |argument| convert_argument(argument) }
  send(node.expression, *arguments)
end

def string_literal(string)

def string_literal(string)
  if string.include?("'")
    string = string.split("'", -1).map do |substr|
      "'#{substr}'"
    end.join(%q(,"'",))
    "concat(#{string})"
  else
    "'#{string}'"
  end
end

def text(current)

def text(current)
  "#{current}/text()"
end

def this_node

def this_node
  '.'
end

def union(*expressions)

def union(*expressions)
  expressions.join(' | ')
end

def valid_xml_name?(name)

def valid_xml_name?(name)
  name =~ /^[a-zA-Z_:][a-zA-Z0-9_:\.\-]*$/
end

def variable(name)

def variable(name)
  "%{#{name}}"
end

def where(on, condition)

def where(on, condition)
  "#{on}[#{condition}]"
end

def with_element_conditions(expression, element_names)

def with_element_conditions(expression, element_names)
  if element_names.length == 1
    "#{expression}#{element_names.first}"
  elsif element_names.length > 1
    "#{expression}*[#{element_names.map { |e| "self::#{e}" }.join(' | ')}]"
  else
    "#{expression}*"
  end
end