xpath 1.0.0 → 2.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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