xpath 1.0.0 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fa3780f7051aea4aeb24f2369c9970e37e57fc26
4
+ data.tar.gz: 1013b0ea9dd73e6c0fd154d05554aee3cc33647f
5
+ SHA512:
6
+ metadata.gz: 94cc925887e165918779ef3ae6bde568813e6234eb7a6793b83bf3b5d3aec6b8f6c1a31d71e484acefe9f6352fc345acc49842ab50e5284f272c90ca83a3e2d8
7
+ data.tar.gz: 18cfdf1cd3c576cbd8aa8736afa2260c83eb647e74a97bbc4b3a7f6f8f993c96a6ab4eb5b0eabe739ba327a08d281d8d61d4ccd946848e921f2544d5f4f51efc
Binary file
@@ -0,0 +1,2 @@
1
+ ��
2
+ {t<�o��>l�n-��H�"��?8�x@A#v���I] dY%�B��AYag���%l�ջiR�+dd��")�'��gG�B��f�>�m?Q;�s��;R2�]�h�����x�����F!z�xz�a��yA�2�n�f%���l�����ni�@ ���
@@ -1,12 +1,13 @@
1
1
  require 'nokogiri'
2
2
 
3
+ require 'xpath/dsl'
4
+ require 'xpath/expression'
5
+ require 'xpath/literal'
6
+ require 'xpath/union'
7
+ require 'xpath/renderer'
8
+ require 'xpath/html'
9
+
3
10
  module XPath
4
- autoload :Expression, 'xpath/expression'
5
- autoload :Literal, 'xpath/literal'
6
- autoload :Union, 'xpath/union'
7
- autoload :Renderer, 'xpath/renderer'
8
- autoload :HTML, 'xpath/html'
9
- autoload :DSL, 'xpath/dsl'
10
11
 
11
12
  extend XPath::DSL::TopLevel
12
13
  include XPath::DSL::TopLevel
@@ -29,8 +29,8 @@ module XPath
29
29
  Expression.new(:previous_sibling, current, expressions)
30
30
  end
31
31
 
32
- def anywhere(expression)
33
- Expression.new(:anywhere, expression)
32
+ def anywhere(*expressions)
33
+ Expression.new(:anywhere, expressions)
34
34
  end
35
35
 
36
36
  def attr(expression)
@@ -75,6 +75,10 @@ module XPath
75
75
  end
76
76
  alias_method :==, :equals
77
77
 
78
+ def is(expression)
79
+ Expression.new(:is, current, expression)
80
+ end
81
+
78
82
  def or(expression)
79
83
  Expression.new(:or, current, expression)
80
84
  end
@@ -12,8 +12,8 @@ module XPath
12
12
  self
13
13
  end
14
14
 
15
- def to_xpath
16
- Renderer.render(self)
15
+ def to_xpath(type=nil)
16
+ Renderer.render(self, type)
17
17
  end
18
18
  alias_method :to_s, :to_xpath
19
19
  end
@@ -1,6 +1,6 @@
1
1
  module XPath
2
2
  module HTML
3
- include XPath
3
+ include XPath::DSL::TopLevel
4
4
  extend self
5
5
 
6
6
  # Match an `a` link element.
@@ -11,7 +11,7 @@ module XPath
11
11
  def link(locator)
12
12
  locator = locator.to_s
13
13
  link = descendant(:a)[attr(:href)]
14
- link[attr(:id).equals(locator) | string.n.contains(locator) | attr(:title).contains(locator) | descendant(:img)[attr(:alt).contains(locator)]]
14
+ link[attr(:id).equals(locator) | string.n.is(locator) | attr(:title).is(locator) | descendant(:img)[attr(:alt).is(locator)]]
15
15
  end
16
16
 
17
17
  # Match a `submit`, `image`, or `button` element.
@@ -21,9 +21,9 @@ module XPath
21
21
  #
22
22
  def button(locator)
23
23
  locator = locator.to_s
24
- button = descendant(:input)[~attr(:disabled)][attr(:type).one_of('submit', 'reset', 'image', 'button')][attr(:id).equals(locator) | attr(:value).contains(locator) | attr(:title).contains(locator)]
25
- button += descendant(:button)[~attr(:disabled)][attr(:id).equals(locator) | attr(:value).contains(locator) | string.n.contains(locator) | attr(:title).contains(locator)]
26
- button += descendant(:input)[~attr(:disabled)][attr(:type).equals('image')][attr(:alt).contains(locator)]
24
+ button = descendant(:input)[attr(:type).one_of('submit', 'reset', 'image', 'button')][attr(:id).equals(locator) | attr(:value).is(locator) | attr(:title).is(locator)]
25
+ button += descendant(:button)[attr(:id).equals(locator) | attr(:value).is(locator) | string.n.is(locator) | attr(:title).is(locator)]
26
+ button += descendant(:input)[attr(:type).equals('image')][attr(:alt).is(locator)]
27
27
  end
28
28
 
29
29
 
@@ -44,7 +44,7 @@ module XPath
44
44
  #
45
45
  def fieldset(locator)
46
46
  locator = locator.to_s
47
- descendant(:fieldset)[attr(:id).equals(locator) | child(:legend)[string.n.contains(locator)]]
47
+ descendant(:fieldset)[attr(:id).equals(locator) | child(:legend)[string.n.is(locator)]]
48
48
  end
49
49
 
50
50
 
@@ -128,7 +128,7 @@ module XPath
128
128
  #
129
129
  def optgroup(locator)
130
130
  locator = locator.to_s
131
- descendant(:optgroup)[attr(:label).contains(locator)]
131
+ descendant(:optgroup)[attr(:label).is(locator)]
132
132
  end
133
133
 
134
134
 
@@ -139,7 +139,7 @@ module XPath
139
139
  #
140
140
  def option(locator)
141
141
  locator = locator.to_s
142
- descendant(:option)[string.n.equals(locator)]
142
+ descendant(:option)[string.n.is(locator)]
143
143
  end
144
144
 
145
145
 
@@ -152,7 +152,7 @@ module XPath
152
152
  #
153
153
  def table(locator)
154
154
  locator = locator.to_s
155
- descendant(:table)[attr(:id).equals(locator) | descendant(:caption).contains(locator)]
155
+ descendant(:table)[attr(:id).equals(locator) | descendant(:caption).is(locator)]
156
156
  end
157
157
 
158
158
  # Match any 'dd' element.
@@ -167,9 +167,9 @@ module XPath
167
167
  protected
168
168
 
169
169
  def locate_field(xpath, locator)
170
- locate_field = xpath[attr(:id).equals(locator) | attr(:name).equals(locator) | attr(:placeholder).equals(locator) | attr(:id).equals(anywhere(:label)[string.n.contains(locator)].attr(:for))]
171
- locate_field += descendant(:label)[string.n.contains(locator)].descendant(xpath)
172
- locate_field[~attr(:disabled)]
170
+ locate_field = xpath[attr(:id).equals(locator) | attr(:name).equals(locator) | attr(:placeholder).equals(locator) | attr(:id).equals(anywhere(:label)[string.n.is(locator)].attr(:for))]
171
+ locate_field += descendant(:label)[string.n.is(locator)].descendant(xpath)
172
+ locate_field
173
173
  end
174
174
  end
175
175
  end
@@ -1,7 +1,11 @@
1
1
  module XPath
2
2
  class Renderer
3
- def self.render(node)
4
- new.render(node)
3
+ def self.render(node, type)
4
+ new(type).render(node)
5
+ end
6
+
7
+ def initialize(type)
8
+ @type = type
5
9
  end
6
10
 
7
11
  def render(node)
@@ -74,6 +78,14 @@ module XPath
74
78
  "#{one} = #{two}"
75
79
  end
76
80
 
81
+ def is(one, two)
82
+ if @type == :exact
83
+ equality(one, two)
84
+ else
85
+ contains(one, two)
86
+ end
87
+ end
88
+
77
89
  def variable(name)
78
90
  "%{#{name}}"
79
91
  end
@@ -101,8 +113,14 @@ module XPath
101
113
  expressions.join(' | ')
102
114
  end
103
115
 
104
- def anywhere(tag_name)
105
- "//#{tag_name}"
116
+ def anywhere(element_names)
117
+ if element_names.length == 1
118
+ "//#{element_names.first}"
119
+ elsif element_names.length > 1
120
+ "//*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]"
121
+ else
122
+ "//*"
123
+ end
106
124
  end
107
125
 
108
126
  def contains(current, value)
@@ -21,8 +21,8 @@ module XPath
21
21
  XPath::Union.new(*arguments.map { |e| e.send(*args) })
22
22
  end
23
23
 
24
- def to_xpath
25
- Renderer.render(self)
24
+ def to_xpath(type=nil)
25
+ Renderer.render(self, type)
26
26
  end
27
27
  alias_method :to_s, :to_xpath
28
28
  end
@@ -1,3 +1,3 @@
1
1
  module XPath
2
- VERSION = '1.0.0'
2
+ VERSION = '2.0.0.beta1'
3
3
  end
@@ -1,39 +1,45 @@
1
- <div id="bar" title="barDiv">
1
+ <!doctype html>
2
+ <html>
3
+ <head></head>
4
+ <body>
5
+ <div id="bar" title="barDiv">
2
6
 
3
- </div>
7
+ </div>
4
8
 
5
- <div title="noId"></div>
9
+ <div title="noId"></div>
6
10
 
7
- <div id="foo" title="fooDiv" data="id">
8
- <p id="fooDiv">Blah</p>
9
- <p>Bax</p>
10
- <p title="monkey">Bax</p>
11
- <ul><li>A list</li></ul>
12
- </div>
11
+ <div id="foo" title="fooDiv" data="id">
12
+ <p id="fooDiv">Blah</p>
13
+ <p>Bax</p>
14
+ <p title="monkey">Bax</p>
15
+ <ul><li>A list</li></ul>
16
+ </div>
13
17
 
14
- <div id="woo" title="wooDiv" data="id">
15
- <ul><li>A list</li></ul>
16
- <p title="gorilla">Bax</p>
17
- <p>Bax</p>
18
- <p id="wooDiv">Blah</p>
19
- </div>
18
+ <div id="woo" title="wooDiv" data="id">
19
+ <ul><li>A list</li></ul>
20
+ <p title="gorilla">Bax</p>
21
+ <p>Bax</p>
22
+ <p id="wooDiv">Blah</p>
23
+ </div>
20
24
 
21
- <div id="baz" title="bazDiv"></div>
25
+ <div id="baz" title="bazDiv"></div>
22
26
 
23
- <div id="preference">
24
- <p id="is-fuzzy">allamas</p>
25
- <p id="is-exact">llama</p>
26
- </div>
27
+ <div id="preference">
28
+ <p id="is-fuzzy">allamas</p>
29
+ <p id="is-exact">llama</p>
30
+ </div>
27
31
 
28
- <p id="whitespace">
29
- A lot
32
+ <p id="whitespace">
33
+ A lot
30
34
 
31
- of
35
+ of
32
36
  whitespace
33
- </p>
34
-
35
- <div id="moar">
36
- <p id="impchay">chimp</p>
37
- <div id="elephantay">elephant</div>
38
- <p id="amingoflay">flamingo</p>
39
- </div>
37
+ </p>
38
+
39
+ <div id="moar">
40
+ <p id="impchay">chimp</p>
41
+ <div id="elephantay">elephant</div>
42
+ <p id="amingoflay">flamingo</p>
43
+ </div>
44
+ </body>
45
+ </html>
@@ -11,7 +11,8 @@ describe XPath::HTML do
11
11
  end
12
12
 
13
13
  def all(*args)
14
- doc.xpath(XPath::HTML.send(subject, *args).to_s).map { |node| node[:data] }
14
+ type = example.metadata[:type]
15
+ doc.xpath(XPath::HTML.send(subject, *args).to_xpath(type)).map { |node| node[:data] }
15
16
  end
16
17
 
17
18
  describe '#link' do
@@ -21,7 +22,7 @@ describe XPath::HTML do
21
22
  it("finds links by content") { get('An awesome link').should == 'link-text' }
22
23
  it("finds links by content regardless of whitespace") { get('My whitespaced link').should == 'link-whitespace' }
23
24
  it("finds links with child tags by content") { get('An emphatic link').should == 'link-children' }
24
- it("finds links by the content of theur child tags") { get('emphatic').should == 'link-children' }
25
+ it("finds links by the content of their child tags") { get('emphatic').should == 'link-children' }
25
26
  it("finds links by approximate content") { get('awesome').should == 'link-text' }
26
27
  it("finds links by title") { get('My title').should == 'link-title' }
27
28
  it("finds links by approximate title") { get('title').should == 'link-title' }
@@ -29,6 +30,15 @@ describe XPath::HTML do
29
30
  it("finds links by image's approximate alt attribute") { get('Alt').should == 'link-img' }
30
31
  it("does not find links without href attriutes") { get('Wrong Link').should be_nil }
31
32
  it("casts to string") { get(:'some-id').should == 'link-id' }
33
+
34
+ context "with exact match", :type => :exact do
35
+ it("finds links by content") { get('An awesome link').should == 'link-text' }
36
+ it("does not find links by approximate content") { get('awesome').should be_nil }
37
+ it("finds links by title") { get('My title').should == 'link-title' }
38
+ it("does not find links by approximate title") { get('title').should be_nil }
39
+ it("finds links by image's alt attribute") { get('Alt link').should == 'link-img' }
40
+ it("does not find links by image's approximate alt attribute") { get('Alt').should be_nil }
41
+ end
32
42
  end
33
43
 
34
44
  describe '#button' do
@@ -40,6 +50,13 @@ describe XPath::HTML do
40
50
  it("finds buttons by approximate value") { get('mit-with-val').should == 'value-submit' }
41
51
  it("finds buttons by title") { get('My submit title').should == 'title-submit' }
42
52
  it("finds buttons by approximate title") { get('submit title').should == 'title-submit' }
53
+
54
+ context "with exact match", :type => :exact do
55
+ it("finds buttons by value") { get('submit-with-value').should == 'value-submit' }
56
+ it("does not find buttons by approximate value") { get('mit-with-val').should be_nil }
57
+ it("finds buttons by title") { get('My submit title').should == 'title-submit' }
58
+ it("does not find buttons by approximate title") { get('submit title').should be_nil }
59
+ end
43
60
  end
44
61
 
45
62
  context "with reset type" do
@@ -48,6 +65,13 @@ describe XPath::HTML do
48
65
  it("finds buttons by approximate value") { get('set-with-val').should == 'value-reset' }
49
66
  it("finds buttons by title") { get('My reset title').should == 'title-reset' }
50
67
  it("finds buttons by approximate title") { get('reset title').should == 'title-reset' }
68
+
69
+ context "with exact match", :type => :exact do
70
+ it("finds buttons by value") { get('reset-with-value').should == 'value-reset' }
71
+ it("does not find buttons by approximate value") { get('set-with-val').should be_nil }
72
+ it("finds buttons by title") { get('My reset title').should == 'title-reset' }
73
+ it("does not find buttons by approximate title") { get('reset title').should be_nil }
74
+ end
51
75
  end
52
76
 
53
77
  context "with button type" do
@@ -56,15 +80,32 @@ describe XPath::HTML do
56
80
  it("finds buttons by approximate value") { get('ton-with-val').should == 'value-button' }
57
81
  it("finds buttons by title") { get('My button title').should == 'title-button' }
58
82
  it("finds buttons by approximate title") { get('button title').should == 'title-button' }
83
+
84
+ context "with exact match", :type => :exact do
85
+ it("finds buttons by value") { get('button-with-value').should == 'value-button' }
86
+ it("does not find buttons by approximate value") { get('ton-with-val').should be_nil }
87
+ it("finds buttons by title") { get('My button title').should == 'title-button' }
88
+ it("does not find buttons by approximate title") { get('button title').should be_nil }
89
+ end
59
90
  end
60
91
 
61
92
  context "with image type" do
62
- it("finds buttons by id") { get('imgbut-with-id').should == 'id-imgbut' }
63
- it("finds buttons by value") { get('imgbut-with-value').should == 'value-imgbut' }
64
- it("finds buttons by approximate value") { get('gbut-with-val').should == 'value-imgbut' }
65
- it("finds buttons by alt attribute") { get('imgbut-with-alt').should == 'alt-imgbut' }
66
- it("finds buttons by title") { get('My imgbut title').should == 'title-imgbut' }
67
- it("finds buttons by approximate title") { get('imgbut title').should == 'title-imgbut' }
93
+ it("finds buttons by id") { get('imgbut-with-id').should == 'id-imgbut' }
94
+ it("finds buttons by value") { get('imgbut-with-value').should == 'value-imgbut' }
95
+ it("finds buttons by approximate value") { get('gbut-with-val').should == 'value-imgbut' }
96
+ it("finds buttons by alt attribute") { get('imgbut-with-alt').should == 'alt-imgbut' }
97
+ it("finds buttons by approximate alt attribute") { get('mgbut-with-al').should == 'alt-imgbut' }
98
+ it("finds buttons by title") { get('My imgbut title').should == 'title-imgbut' }
99
+ it("finds buttons by approximate title") { get('imgbut title').should == 'title-imgbut' }
100
+
101
+ context "with exact match", :type => :exact do
102
+ it("finds buttons by value") { get('imgbut-with-value').should == 'value-imgbut' }
103
+ it("does not find buttons by approximate value") { get('gbut-with-val').should be_nil }
104
+ it("finds buttons by alt attribute") { get('imgbut-with-alt').should == 'alt-imgbut' }
105
+ it("does not find buttons by approximate alt attribute") { get('mgbut-with-al').should be_nil }
106
+ it("finds buttons by title") { get('My imgbut title').should == 'title-imgbut' }
107
+ it("does not find buttons by approximate title") { get('imgbut title').should be_nil }
108
+ end
68
109
  end
69
110
 
70
111
  context "with button tag" do
@@ -78,13 +119,21 @@ describe XPath::HTML do
78
119
  it("finds buttons by text of their children") { get('emphatic').should == 'btag-with-children' }
79
120
  it("finds buttons by title") { get('My btag title').should == 'title-btag' }
80
121
  it("finds buttons by approximate title") { get('btag title').should == 'title-btag' }
122
+
123
+ context "with exact match", :type => :exact do
124
+ it("finds buttons by value") { get('btag-with-value').should == 'value-btag' }
125
+ it("does not find buttons by approximate value") { get('tag-with-val').should be_nil }
126
+ it("finds buttons by text") { get('btag-with-text').should == 'text-btag' }
127
+ it("does not find buttons by approximate text ") { get('tag-with-tex').should be_nil }
128
+ it("finds buttons by title") { get('My btag title').should == 'title-btag' }
129
+ it("does not find buttons by approximate title") { get('btag title').should be_nil }
130
+ end
81
131
  end
82
132
 
83
133
  context "with unkown type" do
84
134
  it("does not find the button") { get('schmoo button').should be_nil }
85
135
  end
86
136
 
87
- it("") { get('disabled-submit').should be_nil }
88
137
  it("casts to string") { get(:'tag-with-tex').should == 'text-btag' }
89
138
  end
90
139
 
@@ -97,6 +146,11 @@ describe XPath::HTML do
97
146
  it("accepts approximate legends") { get('Legend').should == 'fieldset-legend' }
98
147
  it("finds nested fieldsets by legend") { get('Inner legend').should == 'fieldset-inner' }
99
148
  it("casts to string") { get(:'Inner legend').should == 'fieldset-inner' }
149
+
150
+ context "with exact match", :type => :exact do
151
+ it("finds fieldsets by legend") { get('Some Legend').should == 'fieldset-legend' }
152
+ it("does not find by approximate legends") { get('Legend').should be_nil }
153
+ end
100
154
  end
101
155
 
102
156
  describe '#field' do
@@ -159,15 +213,6 @@ describe XPath::HTML do
159
213
  it("does not find hidden fields") { get('Input hidden with parent label').should be_nil }
160
214
  end
161
215
 
162
- context "is diabled" do
163
- it("does not find inputs with no type") { get('input-disabled').should be_nil }
164
- it("does not find inputs with text type") { get('input-text-disabled').should be_nil }
165
- it("does not find inputs with password type") { get('input-password-disabled').should be_nil }
166
- it("does not find inputs with custom type") { get('input-custom-disabled').should be_nil }
167
- it("does not find textareas") { get('textarea-disabled').should be_nil }
168
- it("does not find select boxes") { get('select-disabled').should be_nil }
169
- end
170
-
171
216
  it("casts to string") { get(:'select-with-id').should == 'select-with-id-data' }
172
217
  end
173
218
 
@@ -186,7 +231,6 @@ describe XPath::HTML do
186
231
  it("finds selects by name") { get('select-with-name').should == 'select-with-name-data' }
187
232
  it("finds selects by label") { get('Select with label').should == 'select-with-label-data' }
188
233
  it("finds selects by parent label") { get('Select with parent label').should == 'select-with-parent-label-data' }
189
- it("does not find disabled selects") { get('select-disabled').should be_nil }
190
234
  it("casts to string") { get(:'Select with parent label').should == 'select-with-parent-label-data' }
191
235
  end
192
236
 
@@ -196,7 +240,6 @@ describe XPath::HTML do
196
240
  it("finds checkboxes by name") { get('input-checkbox-with-name').should == 'input-checkbox-with-name-data' }
197
241
  it("finds checkboxes by label") { get('Input checkbox with label').should == 'input-checkbox-with-label-data' }
198
242
  it("finds checkboxes by parent label") { get('Input checkbox with parent label').should == 'input-checkbox-with-parent-label-data' }
199
- it("does not find disabled") { get('input-checkbox-disabled').should be_nil }
200
243
  it("casts to string") { get(:'Input checkbox with parent label').should == 'input-checkbox-with-parent-label-data' }
201
244
  end
202
245
 
@@ -206,7 +249,6 @@ describe XPath::HTML do
206
249
  it("finds radio buttons by name") { get('input-radio-with-name').should == 'input-radio-with-name-data' }
207
250
  it("finds radio buttons by label") { get('Input radio with label').should == 'input-radio-with-label-data' }
208
251
  it("finds radio buttons by parent label") { get('Input radio with parent label').should == 'input-radio-with-parent-label-data' }
209
- it("does not find disabled") { get('input-radio-disabled').should be_nil }
210
252
  it("casts to string") { get(:'Input radio with parent label').should == 'input-radio-with-parent-label-data' }
211
253
  end
212
254
 
@@ -216,28 +258,44 @@ describe XPath::HTML do
216
258
  it("finds file fields by name") { get('input-file-with-name').should == 'input-file-with-name-data' }
217
259
  it("finds file fields by label") { get('Input file with label').should == 'input-file-with-label-data' }
218
260
  it("finds file fields by parent label") { get('Input file with parent label').should == 'input-file-with-parent-label-data' }
219
- it("does not find disabled") { get('input-file-disabled').should be_nil }
220
261
  it("casts to string") { get(:'Input file with parent label').should == 'input-file-with-parent-label-data' }
221
262
  end
222
263
 
223
264
  describe "#optgroup" do
224
265
  subject { :optgroup }
225
- it("finds optgroups by label") { get('Group A').should == 'optgroup-a' }
226
- it("casts to string") { get(:'Group A').should == 'optgroup-a' }
266
+ it("finds optgroups by label") { get('Group A').should == 'optgroup-a' }
267
+ it("finds optgroups by approximate label") { get('oup A').should == 'optgroup-a' }
268
+ it("casts to string") { get(:'Group A').should == 'optgroup-a' }
269
+
270
+ context "with exact match", :type => :exact do
271
+ it("finds by label") { get('Group A').should == 'optgroup-a' }
272
+ it("does not find by approximate label") { get('oup A').should be_nil }
273
+ end
227
274
  end
228
275
 
229
276
  describe '#option' do
230
277
  subject{ :option }
231
- it("finds options by text") { get('Option with text').should == 'option-with-text-data' }
232
- it("does not find option by partial text") { get('Option with').should be_nil }
233
- it("casts to string") { get(:'Option with text').should == 'option-with-text-data' }
278
+ it("finds by text") { get('Option with text').should == 'option-with-text-data' }
279
+ it("finds by approximate text") { get('Option with').should == 'option-with-text-data' }
280
+ it("casts to string") { get(:'Option with text').should == 'option-with-text-data' }
281
+
282
+ context "with exact match", :type => :exact do
283
+ it("finds by text") { get('Option with text').should == 'option-with-text-data' }
284
+ it("does not find by approximate text") { get('Option with').should be_nil }
285
+ end
234
286
  end
235
287
 
236
288
  describe "#table" do
237
289
  subject {:table}
238
- it("finds tables by id") { get('table-with-id').should == 'table-with-id-data' }
239
- it("finds tables by caption") { get('Table with caption').should == 'table-with-caption-data' }
240
- it("casts to string") { get(:'Table with caption').should == 'table-with-caption-data' }
290
+ it("finds by id") { get('table-with-id').should == 'table-with-id-data' }
291
+ it("finds by caption") { get('Table with caption').should == 'table-with-caption-data' }
292
+ it("finds by approximate caption") { get('Table with').should == 'table-with-caption-data' }
293
+ it("casts to string") { get(:'Table with caption').should == 'table-with-caption-data' }
294
+
295
+ context "with exact match", :type => :exact do
296
+ it("finds by caption") { get('Table with caption').should == 'table-with-caption-data' }
297
+ it("does not find by approximate caption") { get('Table with').should be_nil }
298
+ end
241
299
  end
242
300
 
243
301
  describe "#definition_description" do
@@ -1,4 +1 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
3
-
4
1
  require 'xpath'
@@ -14,8 +14,8 @@ describe XPath do
14
14
  let(:template) { File.read(File.expand_path('fixtures/simple.html', File.dirname(__FILE__))) }
15
15
  let(:doc) { Nokogiri::HTML(template) }
16
16
 
17
- def xpath(&block)
18
- doc.xpath XPath.generate(&block).to_xpath
17
+ def xpath(type=nil, &block)
18
+ doc.xpath XPath.generate(&block).to_xpath(type)
19
19
  end
20
20
 
21
21
  it "should work as a mixin" do
@@ -116,6 +116,33 @@ describe XPath do
116
116
  end
117
117
  @results[0].text.should == "Blah"
118
118
  end
119
+
120
+ it "should find multiple kinds of nodes regardless of the context" do
121
+ @results = xpath do |x|
122
+ context=x.descendant(:div).where(x.attr(:id)=='woo')
123
+ context.anywhere(:p, :ul)
124
+ end
125
+
126
+ @results[0].text.should == 'Blah'
127
+ @results[3].text.should == 'A list'
128
+ @results[4].text.should == 'A list'
129
+ @results[6].text.should == 'Bax'
130
+ end
131
+
132
+ it "should find all nodes when no arguments given regardless of the context" do
133
+ @results = xpath do |x|
134
+ context=x.descendant(:div).where(x.attr(:id)=='woo')
135
+ context.anywhere
136
+ end
137
+ @results[0].name.should == 'html'
138
+ @results[1].name.should == 'head'
139
+ @results[2].name.should == 'body'
140
+ @results[6].text.should == 'Blah'
141
+ @results[10].text.should == 'A list'
142
+ @results[13].text.should == 'A list'
143
+ @results[15].text.should == 'Bax'
144
+ end
145
+
119
146
  end
120
147
 
121
148
  describe '#contains' do
@@ -194,6 +221,18 @@ describe XPath do
194
221
  end
195
222
  end
196
223
 
224
+ describe '#is' do
225
+ it "uses equality when :exact given" do
226
+ xpath(:exact) { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should == "fooDiv"
227
+ xpath(:exact) { |x| x.descendant(:div).where(x.attr(:id).is('oo')) }.first.should be_nil
228
+ end
229
+
230
+ it "uses substring matching otherwise" do
231
+ xpath { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should == "fooDiv"
232
+ xpath { |x| x.descendant(:div).where(x.attr(:id).is('oo')) }.first[:title].should == "fooDiv"
233
+ end
234
+ end
235
+
197
236
  describe '#one_of' do
198
237
  it "should return all nodes where the condition matches" do
199
238
  @results = xpath do |x|
metadata CHANGED
@@ -1,20 +1,40 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xpath
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
5
- prerelease:
4
+ version: 2.0.0.beta1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jonas Nicklas
9
8
  autorequire:
10
9
  bindir: bin
11
- cert_chain: []
12
- date: 2012-11-14 00:00:00.000000000 Z
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDhTCCAm2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMRYwFAYDVQQDDA1qb25h
14
+ cy5uaWNrbGFzMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZ
15
+ FgNjb20wHhcNMTMwMzE2MDEzMTExWhcNMTQwMzE2MDEzMTExWjBEMRYwFAYDVQQD
16
+ DA1qb25hcy5uaWNrbGFzMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJ
17
+ k/IsZAEZFgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+B9mx
18
+ 0TVkvXIN31JC4s4Ni6mchJL/98h+euMIENt5LoxceYlijP0nGdYHAMoA2CUl7E+J
19
+ /Km3W1ziSC0Mr3YIqCwp4fygP1woyRKRYmoyBRZdW5JiPAQzYxXaib0+BCB+JhSm
20
+ Rev2+BaHJuRRKWq+S3bzZ61U6RMVp/tAfeInXOQdvm3ycyhOGWx6XpEW2ON6oRDl
21
+ mBuAM8b9hjpOAzFXh3OLXBC9zq5Z5pl2frlfAVB2hKztwiEiNkGjx/qBXixvo7du
22
+ Mx+O296WpLuuWwrOaIsR3Q37aNvLBvieh74D9QJjcwR3Mr0RRQLbXxNGsSQa6gY4
23
+ l9j0EtUVSDZB54H5AgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAd
24
+ BgNVHQ4EFgQUf8GtjwnaRtSqgvJDzCc3Ta7LHMswIgYDVR0RBBswGYEXam9uYXMu
25
+ bmlja2xhc0BnbWFpbC5jb20wIgYDVR0SBBswGYEXam9uYXMubmlja2xhc0BnbWFp
26
+ bC5jb20wDQYJKoZIhvcNAQEFBQADggEBAGlsnpcev4fu+FDAygbObfc73pltKnQF
27
+ Ewy88+HgJ4AhjwHER7OWDVMwh6vHkmEep1rhLnNWGztD/ym5iFk4FGIz1D5J7TqQ
28
+ k4v2w+Oje3YW/pSAGgAVPGCCrlqiw4hKZUzPob8NWhuS4tKDPWMGBQx3ZSRyqILc
29
+ /WQ/FmnbVa9xRUo+RWiP9TpzKQJiR3BP9OpVrRx13m0euFxzTi6ikJzC45Q3Dq5V
30
+ iQxUmCCRsJVcsSFORJLdWNVqzBOWZRnqrLDunzouCbcqziNWk8KqjZCr5itRi319
31
+ /2kZgwc32FHlCdCBXkhElEHT/bGCFk2+ajnmWRtqZpz/poTgEehiIUY=
32
+ -----END CERTIFICATE-----
33
+ date: 2013-03-16 00:00:00.000000000 Z
13
34
  dependencies:
14
35
  - !ruby/object:Gem::Dependency
15
36
  name: nokogiri
16
37
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
38
  requirements:
19
39
  - - ~>
20
40
  - !ruby/object:Gem::Version
@@ -22,7 +42,6 @@ dependencies:
22
42
  type: :runtime
23
43
  prerelease: false
24
44
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
45
  requirements:
27
46
  - - ~>
28
47
  - !ruby/object:Gem::Version
@@ -30,7 +49,6 @@ dependencies:
30
49
  - !ruby/object:Gem::Dependency
31
50
  name: rspec
32
51
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
52
  requirements:
35
53
  - - ~>
36
54
  - !ruby/object:Gem::Version
@@ -38,7 +56,6 @@ dependencies:
38
56
  type: :development
39
57
  prerelease: false
40
58
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
59
  requirements:
43
60
  - - ~>
44
61
  - !ruby/object:Gem::Version
@@ -46,33 +63,29 @@ dependencies:
46
63
  - !ruby/object:Gem::Dependency
47
64
  name: yard
48
65
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
66
  requirements:
51
- - - ! '>='
67
+ - - '>='
52
68
  - !ruby/object:Gem::Version
53
69
  version: 0.5.8
54
70
  type: :development
55
71
  prerelease: false
56
72
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
73
  requirements:
59
- - - ! '>='
74
+ - - '>='
60
75
  - !ruby/object:Gem::Version
61
76
  version: 0.5.8
62
77
  - !ruby/object:Gem::Dependency
63
78
  name: rake
64
79
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
80
  requirements:
67
- - - ! '>='
81
+ - - '>='
68
82
  - !ruby/object:Gem::Version
69
83
  version: '0'
70
84
  type: :development
71
85
  prerelease: false
72
86
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
87
  requirements:
75
- - - ! '>='
88
+ - - '>='
76
89
  - !ruby/object:Gem::Version
77
90
  version: '0'
78
91
  description: XPath is a Ruby DSL for generating XPath expressions
@@ -101,6 +114,7 @@ files:
101
114
  - README.md
102
115
  homepage: http://github.com/jnicklas/xpath
103
116
  licenses: []
117
+ metadata: {}
104
118
  post_install_message:
105
119
  rdoc_options:
106
120
  - --main
@@ -108,22 +122,20 @@ rdoc_options:
108
122
  require_paths:
109
123
  - lib
110
124
  required_ruby_version: !ruby/object:Gem::Requirement
111
- none: false
112
125
  requirements:
113
- - - ! '>='
126
+ - - '>='
114
127
  - !ruby/object:Gem::Version
115
128
  version: '0'
116
129
  required_rubygems_version: !ruby/object:Gem::Requirement
117
- none: false
118
130
  requirements:
119
- - - ! '>='
131
+ - - '>'
120
132
  - !ruby/object:Gem::Version
121
- version: '0'
133
+ version: 1.3.1
122
134
  requirements: []
123
135
  rubyforge_project: xpath
124
- rubygems_version: 1.8.24
136
+ rubygems_version: 2.0.0
125
137
  signing_key:
126
- specification_version: 3
138
+ specification_version: 4
127
139
  summary: Generate XPath expressions from Ruby
128
140
  test_files: []
129
141
  has_rdoc:
Binary file