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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -0
- data/lib/xpath.rb +7 -6
- data/lib/xpath/dsl.rb +6 -2
- data/lib/xpath/expression.rb +2 -2
- data/lib/xpath/html.rb +12 -12
- data/lib/xpath/renderer.rb +22 -4
- data/lib/xpath/union.rb +2 -2
- data/lib/xpath/version.rb +1 -1
- data/spec/fixtures/simple.html +36 -30
- data/spec/html_spec.rb +88 -30
- data/spec/spec_helper.rb +0 -3
- data/spec/xpath_spec.rb +41 -2
- metadata +35 -23
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -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
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
data/lib/xpath.rb
CHANGED
@@ -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
|
data/lib/xpath/dsl.rb
CHANGED
@@ -29,8 +29,8 @@ module XPath
|
|
29
29
|
Expression.new(:previous_sibling, current, expressions)
|
30
30
|
end
|
31
31
|
|
32
|
-
def anywhere(
|
33
|
-
Expression.new(:anywhere,
|
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
|
data/lib/xpath/expression.rb
CHANGED
data/lib/xpath/html.rb
CHANGED
@@ -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.
|
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)[
|
25
|
-
button += descendant(:button)[
|
26
|
-
button += descendant(:input)[
|
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.
|
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).
|
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.
|
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).
|
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.
|
171
|
-
locate_field += descendant(:label)[string.n.
|
172
|
-
locate_field
|
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
|
data/lib/xpath/renderer.rb
CHANGED
@@ -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(
|
105
|
-
|
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)
|
data/lib/xpath/union.rb
CHANGED
data/lib/xpath/version.rb
CHANGED
data/spec/fixtures/simple.html
CHANGED
@@ -1,39 +1,45 @@
|
|
1
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
25
|
-
|
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
|
-
|
35
|
+
of
|
32
36
|
whitespace
|
33
|
-
</p>
|
34
|
-
|
35
|
-
<div id="moar">
|
36
|
-
|
37
|
-
|
38
|
-
|
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>
|
data/spec/html_spec.rb
CHANGED
@@ -11,7 +11,8 @@ describe XPath::HTML do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def all(*args)
|
14
|
-
|
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
|
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")
|
63
|
-
it("finds buttons by value")
|
64
|
-
it("finds buttons by approximate value")
|
65
|
-
it("finds buttons by alt attribute")
|
66
|
-
it("finds buttons by
|
67
|
-
it("finds buttons by
|
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")
|
226
|
-
it("
|
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
|
232
|
-
it("
|
233
|
-
it("casts to string")
|
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
|
239
|
-
it("finds
|
240
|
-
it("
|
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
|
data/spec/spec_helper.rb
CHANGED
data/spec/xpath_spec.rb
CHANGED
@@ -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:
|
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
|
-
|
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:
|
133
|
+
version: 1.3.1
|
122
134
|
requirements: []
|
123
135
|
rubyforge_project: xpath
|
124
|
-
rubygems_version:
|
136
|
+
rubygems_version: 2.0.0
|
125
137
|
signing_key:
|
126
|
-
specification_version:
|
138
|
+
specification_version: 4
|
127
139
|
summary: Generate XPath expressions from Ruby
|
128
140
|
test_files: []
|
129
141
|
has_rdoc:
|
metadata.gz.sig
ADDED
Binary file
|