~ubuntu-branches/ubuntu/wily/ruby-xpath/wily-proposed

« back to all changes in this revision

Viewing changes to lib/xpath/renderer.rb

  • Committer: Package Import Robot
  • Author(s): Markus Tornow
  • Date: 2012-12-08 22:57:18 UTC
  • Revision ID: package-import@ubuntu.com-20121208225718-6n9jpw8w8la9x2hr
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
module XPath
 
2
  class Renderer
 
3
    def self.render(node)
 
4
      new.render(node)
 
5
    end
 
6
 
 
7
    def render(node)
 
8
      arguments = node.arguments.map { |argument| convert_argument(argument) }
 
9
      send(node.expression, *arguments)
 
10
    end
 
11
 
 
12
    def convert_argument(argument)
 
13
      case argument
 
14
        when Expression, Union then render(argument)
 
15
        when Array then argument.map { |element| convert_argument(element) }
 
16
        when String then string_literal(argument)
 
17
        when Literal then argument.value
 
18
        else argument.to_s
 
19
      end
 
20
    end
 
21
 
 
22
    def string_literal(string)
 
23
      if string.include?("'")
 
24
        string = string.split("'", -1).map do |substr|
 
25
          "'#{substr}'"
 
26
        end.join(%q{,"'",})
 
27
        "concat(#{string})"
 
28
      else
 
29
        "'#{string}'"
 
30
      end
 
31
    end
 
32
 
 
33
    def this_node
 
34
      '.'
 
35
    end
 
36
 
 
37
    def descendant(parent, element_names)
 
38
      if element_names.length == 1
 
39
        "#{parent}//#{element_names.first}"
 
40
      elsif element_names.length > 1
 
41
        "#{parent}//*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]"
 
42
      else
 
43
        "#{parent}//*"
 
44
      end
 
45
    end
 
46
 
 
47
    def child(parent, element_names)
 
48
      if element_names.length == 1
 
49
        "#{parent}/#{element_names.first}"
 
50
      elsif element_names.length > 1
 
51
        "#{parent}/*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]"
 
52
      else
 
53
        "#{parent}/*"
 
54
      end
 
55
    end
 
56
 
 
57
    def axis(parent, name, tag_name)
 
58
      "#{parent}/#{name}::#{tag_name}"
 
59
    end
 
60
 
 
61
    def node_name(current)
 
62
      "name(#{current})"
 
63
    end
 
64
 
 
65
    def where(on, condition)
 
66
      "#{on}[#{condition}]"
 
67
    end
 
68
 
 
69
    def attribute(current, name)
 
70
      "#{current}/@#{name}"
 
71
    end
 
72
 
 
73
    def equality(one, two)
 
74
      "#{one} = #{two}"
 
75
    end
 
76
 
 
77
    def variable(name)
 
78
      "%{#{name}}"
 
79
    end
 
80
 
 
81
    def text(current)
 
82
      "#{current}/text()"
 
83
    end
 
84
 
 
85
    def normalized_space(current)
 
86
      "normalize-space(#{current})"
 
87
    end
 
88
 
 
89
    def literal(node)
 
90
      node
 
91
    end
 
92
 
 
93
    def css(current, selector)
 
94
      paths = Nokogiri::CSS.xpath_for(selector).map do |xpath_selector|
 
95
        "#{current}#{xpath_selector}"
 
96
      end
 
97
      union(paths)
 
98
    end
 
99
 
 
100
    def union(*expressions)
 
101
      expressions.join(' | ')
 
102
    end
 
103
 
 
104
    def anywhere(tag_name)
 
105
      "//#{tag_name}"
 
106
    end
 
107
 
 
108
    def contains(current, value)
 
109
      "contains(#{current}, #{value})"
 
110
    end
 
111
 
 
112
    def starts_with(current, value)
 
113
      "starts-with(#{current}, #{value})"
 
114
    end
 
115
 
 
116
    def and(one, two)
 
117
      "(#{one} and #{two})"
 
118
    end
 
119
 
 
120
    def or(one, two)
 
121
      "(#{one} or #{two})"
 
122
    end
 
123
 
 
124
    def one_of(current, values)
 
125
      values.map { |value| "#{current} = #{value}" }.join(' or ')
 
126
    end
 
127
 
 
128
    def next_sibling(current, element_names)
 
129
      if element_names.length == 1
 
130
        "#{current}/following-sibling::*[1]/self::#{element_names.first}"
 
131
      elsif element_names.length > 1
 
132
        "#{current}/following-sibling::*[1]/self::*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]"
 
133
      else
 
134
        "#{current}/following-sibling::*[1]/self::*"
 
135
      end
 
136
    end
 
137
 
 
138
    def previous_sibling(current, element_names)
 
139
      if element_names.length == 1
 
140
        "#{current}/preceding-sibling::*[1]/self::#{element_names.first}"
 
141
      elsif element_names.length > 1
 
142
        "#{current}/preceding-sibling::*[1]/self::*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]"
 
143
      else
 
144
        "#{current}/preceding-sibling::*[1]/self::*"
 
145
      end
 
146
    end
 
147
 
 
148
    def inverse(current)
 
149
      "not(#{current})"
 
150
    end
 
151
 
 
152
    def string_function(current)
 
153
      "string(#{current})"
 
154
    end
 
155
  end
 
156
end