xpath 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,6 +1,7 @@
1
1
  = XPath
2
2
 
3
- XPath is a Ruby DSL around a subset of XPath 1.0. It's primary purpose is to facilitate writing complex XPath queries from Ruby code.
3
+ XPath is a Ruby DSL around a subset of XPath 1.0. It's primary purpose is to
4
+ facilitate writing complex XPath queries from Ruby code.
4
5
 
5
6
  == Generating expressions
6
7
 
@@ -8,7 +9,8 @@ To create quick, one of expressions, XPath.generate can be used:
8
9
 
9
10
  XPath.generate { |x| x.descendant(:ul)[x.attr(:id) == 'foo'] }
10
11
 
11
- However for more complex expressions, it is probably ore convenient to include the XPath module into your own class or module:
12
+ However for more complex expressions, it is probably ore convenient to include
13
+ the XPath module into your own class or module:
12
14
 
13
15
  module MyXPaths
14
16
  include XPath
@@ -22,8 +24,33 @@ However for more complex expressions, it is probably ore convenient to include t
22
24
  end
23
25
  end
24
26
 
25
- Both ways return an XPath::Expression instance, which can be further modified. To convert the expression to a string, just call #to_s on it.
27
+ Both ways return an XPath::Expression instance, which can be further modified.
28
+ To convert the expression to a string, just call #to_s on it.
26
29
 
27
30
  == HTML
28
31
 
29
32
  XPath comes with a set of premade XPaths for use with HTML documents.
33
+
34
+ == License
35
+
36
+ (The MIT License)
37
+
38
+ Copyright © 2010 Jonas Nicklas
39
+
40
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
41
+ this software and associated documentation files (the ‘Software’), to deal in
42
+ the Software without restriction, including without limitation the rights to
43
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
44
+ of the Software, and to permit persons to whom the Software is furnished to do
45
+ so, subject to the following conditions:
46
+
47
+ The above copyright notice and this permission notice shall be included in all
48
+ copies or substantial portions of the Software.
49
+
50
+ THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
52
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
53
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
54
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
55
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
56
+ SOFTWARE.
@@ -126,14 +126,15 @@ module XPath
126
126
  end
127
127
 
128
128
  def to_xpath(predicate=nil)
129
- @expression = @expression.to_xpath(predicate) unless @expression.is_a?(String)
130
- if @expression.include?("'")
131
- @expression = @expression.split("'", -1).map do |substr|
129
+ string = @expression
130
+ string = @expression.to_xpath(predicate) unless @expression.is_a?(String)
131
+ if string.include?("'")
132
+ string = string.split("'", -1).map do |substr|
132
133
  "'#{substr}'"
133
134
  end.join(%q{,"'",})
134
- "concat(#{@expression})"
135
+ "concat(#{string})"
135
136
  else
136
- "'#{@expression}'"
137
+ "'#{string}'"
137
138
  end
138
139
  end
139
140
  end
data/lib/xpath/html.rb CHANGED
@@ -3,8 +3,9 @@ module XPath
3
3
  include XPath
4
4
  extend self
5
5
 
6
- def link(locator)
7
- link = descendant(:a)[attr(:href)]
6
+ def link(locator, options={})
7
+ href = options[:href]
8
+ link = descendant(:a)[href ? attr(:href).equals(href) : attr(:href)]
8
9
  link[attr(:id).equals(locator) | string.n.is(locator) | attr(:title).is(locator) | descendant(:img)[attr(:alt).is(locator)]]
9
10
  end
10
11
 
@@ -23,7 +24,7 @@ module XPath
23
24
  end
24
25
 
25
26
  def fieldset(locator)
26
- descendant(:fieldset)[attr(:id).equals(locator) | descendant(:legend)[text.is(locator)]]
27
+ descendant(:fieldset)[attr(:id).equals(locator) | descendant(:legend)[string.n.is(locator)]]
27
28
  end
28
29
 
29
30
  def field(locator, options={})
@@ -46,11 +47,11 @@ module XPath
46
47
  xpath = locate_field(descendant(:select), locator)
47
48
 
48
49
  options[:options].each do |option|
49
- xpath = xpath[descendant(:option).text.equals(option)]
50
+ xpath = xpath[descendant(:option).equals(option)]
50
51
  end if options[:options]
51
52
 
52
53
  [options[:selected]].flatten.each do |option|
53
- xpath = xpath[descendant(:option)[attr(:selected)].text.equals(option)]
54
+ xpath = xpath[descendant(:option)[attr(:selected)].equals(option)]
54
55
  end if options[:selected]
55
56
 
56
57
  xpath
@@ -68,8 +69,12 @@ module XPath
68
69
  locate_field(descendant(:input)[attr(:type).equals('file')], locator)
69
70
  end
70
71
 
72
+ def optgroup(name)
73
+ descendant(:optgroup)[attr(:label).is(name)]
74
+ end
75
+
71
76
  def option(name)
72
- descendant(:option)[text.n.is(name)]
77
+ descendant(:option)[string.n.is(name)]
73
78
  end
74
79
 
75
80
  def table(locator, options={})
@@ -87,9 +92,9 @@ module XPath
87
92
  end
88
93
 
89
94
  def table_row(cells)
90
- cell_conditions = child(:td, :th)[text.equals(cells.first)]
95
+ cell_conditions = child(:td, :th)[string.n.equals(cells.first)]
91
96
  cells.drop(1).each do |cell|
92
- cell_conditions = cell_conditions.next_sibling(:td, :th)[text.equals(cell)]
97
+ cell_conditions = cell_conditions.next_sibling(:td, :th)[string.n.equals(cell)]
93
98
  end
94
99
  cell_conditions
95
100
  end
@@ -97,12 +102,12 @@ module XPath
97
102
  protected
98
103
 
99
104
  def locate_field(xpath, locator)
100
- locate_field = xpath[attr(:id).equals(locator) | attr(:name).equals(locator) | attr(:id).equals(anywhere(:label)[text.is(locator)].attr(:for))]
101
- locate_field += descendant(:label)[text.is(locator)].descendant(xpath)
105
+ locate_field = xpath[attr(:id).equals(locator) | attr(:name).equals(locator) | attr(:id).equals(anywhere(:label)[string.n.is(locator)].attr(:for))]
106
+ locate_field += descendant(:label)[string.n.is(locator)].descendant(xpath)
102
107
  end
103
108
 
104
109
  def field_value(value)
105
- (text.is(value) & tag(:textarea)) | (attr(:value).equals(value) & ~tag(:textarea))
110
+ (string.n.is(value) & tag(:textarea)) | (attr(:value).equals(value) & ~tag(:textarea))
106
111
  end
107
112
 
108
113
  end
data/lib/xpath/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module XPath
2
- VERSION = '0.1.2'
2
+ VERSION = '0.1.3'
3
3
  end
@@ -9,6 +9,7 @@
9
9
  <a title="This title" data="link-exact" href="#foo">A link</a>
10
10
  <a href="#bar" data="link-img-fuzzy"><img src="foo.png" alt="An image that is beautiful"/></a>
11
11
  <a href="#foo" data="link-img-exact"><img src="foo.ong" alt="An image"/></a>
12
+ <a href="http://www.example.com" data="link-href">Href-ed link</a>
12
13
  <a>Wrong Link</a>
13
14
  <a href="#spacey" data="link-whitespace"> My
14
15
 
@@ -54,15 +55,32 @@
54
55
  </button>
55
56
 
56
57
  <input type="schmoo" value="schmoo button" data="schmoo"/>
58
+ <label for="text-with-id">Label text <input type="text" id="text-with-id" data="id-text" value="monkey"/></label>
59
+ <label for="problem-text-with-id">Label text's got an apostrophe <input type="text" id="problem-text-with-id" data="id-problem-text" value="monkey"/></label>
57
60
  </p>
58
61
 
59
62
  <p>
60
63
  <fieldset id="some-fieldset-id" data="fieldset-id"></fieldset>
61
64
  <fieldset data="fieldset-legend"><legend>Some Legend</legend></fieldset>
65
+ <fieldset data="fieldset-legend-span"><legend><span>Span Legend</span></legend></fieldset>
62
66
  <fieldset data="fieldset-fuzzy"><legend>Long legend yo</legend></fieldset>
63
67
  <fieldset data="fieldset-exact"><legend>Long legend</legend></fieldset>
64
68
  </p>
65
69
 
66
70
  <p>
71
+ <select>
72
+ <optgroup label="Group A" data="optgroup-a"></optgroup>
73
+ <optgroup label="Group B" data="optgroup-b"></optgroup>
74
+ </select>
75
+ </p>
67
76
 
77
+ <p>
78
+ <table id="whitespaced-table" data="table-with-whitespace">
79
+ <tr>
80
+ <td data="cell-whitespaced">I have
81
+ <span>nested whitespace</span>
82
+ </td>
83
+ <td>I don't</td>
84
+ </tr>
85
+ </table>
68
86
  </p>
@@ -27,6 +27,6 @@ A lot
27
27
 
28
28
  <div id="moar">
29
29
  <p id="impchay">chimp</p>
30
- <p id="amingoflay">flamingo</p>
31
30
  <div id="elephantay">elephant</div>
31
+ <p id="amingoflay">flamingo</p>
32
32
  </div>
data/spec/html_spec.rb CHANGED
@@ -33,6 +33,8 @@ describe XPath::HTML do
33
33
  it("finds links by image's approximate alt attribute") { get('Alt').should == 'link-img' }
34
34
  it("prefers exact matches of image's alt attribute") { all('An image').should == ['link-img-exact', 'link-img-fuzzy'] }
35
35
  it("does not find links without href attriutes") { get('Wrong Link').should be_nil }
36
+ it("finds links with an href") { get("Href-ed link", :href => 'http://www.example.com').should == 'link-href' }
37
+ it("does not find links with an incorrect href") { get("Href-ed link", :href => 'http://www.somewhere.com').should be_nil }
36
38
  end
37
39
 
38
40
  describe '#button' do
@@ -81,10 +83,11 @@ describe XPath::HTML do
81
83
  describe '#fieldset' do
82
84
  subject { :fieldset }
83
85
 
84
- it("finds fieldsets by id") { get('some-fieldset-id').should == 'fieldset-id' }
85
- it("finds fieldsets by legend") { get('Some Legend').should == 'fieldset-legend' }
86
- it("accepts approximate legends") { get('Legend').should == 'fieldset-legend' }
87
- it("prefers exact legend") { all('Long legend').should == ['fieldset-exact', 'fieldset-fuzzy'] }
86
+ it("finds fieldsets by id") { get('some-fieldset-id').should == 'fieldset-id' }
87
+ it("finds fieldsets by legend") { get('Some Legend').should == 'fieldset-legend' }
88
+ it("finds fieldsets by legend child tags") { get('Span Legend').should == 'fieldset-legend-span' }
89
+ it("accepts approximate legends") { get('Legend').should == 'fieldset-legend' }
90
+ it("prefers exact legend") { all('Long legend').should == ['fieldset-exact', 'fieldset-fuzzy'] }
88
91
  end
89
92
 
90
93
  describe '#field' do
@@ -124,14 +127,15 @@ describe XPath::HTML do
124
127
  end
125
128
 
126
129
  context "by parent label" do
127
- it("finds inputs with text type") {}
128
- it("finds inputs with password type") {}
129
- it("finds inputs with custom type") {}
130
- it("finds textareas") {}
131
- it("finds select boxes") {}
132
- it("does not find submit buttons") {}
133
- it("does not find image buttons") {}
134
- it("does not find hidden fields") {}
130
+ it("finds inputs with text type") { get('Label text').should == 'id-text' }
131
+ it("finds inputs where label has problem chars") { get("Label text's got an apostrophe").should == 'id-problem-text' }
132
+ it("finds inputs with password type") {}
133
+ it("finds inputs with custom type") {}
134
+ it("finds textareas") {}
135
+ it("finds select boxes") {}
136
+ it("does not find submit buttons") {}
137
+ it("does not find image buttons") {}
138
+ it("does not find hidden fields") {}
135
139
  end
136
140
 
137
141
  context "with :with option" do
@@ -158,6 +162,23 @@ describe XPath::HTML do
158
162
  end
159
163
 
160
164
  describe '#fillable_field' do
165
+ subject{ :fillable_field }
166
+ context "by parent label" do
167
+ it("finds inputs with text type") { get('Label text').should == 'id-text' }
168
+ it("finds inputs where label has problem chars") { get("Label text's got an apostrophe").should == 'id-problem-text' }
169
+ end
170
+
171
+ end
172
+
173
+ describe "#optgroup" do
174
+ subject { :optgroup }
175
+
176
+ it("finds optgroups by label") { get('Group A').should == 'optgroup-a' }
177
+ end
178
+
179
+ describe "#table" do
180
+ subject {:table}
161
181
 
182
+ it("finds cell content regardless of whitespace") {get('whitespaced-table', :rows => [["I have nested whitespace", "I don't"]]).should == 'table-with-whitespace'}
162
183
  end
163
184
  end
data/spec/xpath_spec.rb CHANGED
@@ -265,11 +265,17 @@ describe XPath do
265
265
  @results[1].text.should == 'flamingo'
266
266
  end
267
267
 
268
+ it "should be composable" do
269
+ @results = xpath { |x| x.css('#moar').descendant(:p) }
270
+ @results[0].text.should == 'chimp'
271
+ @results[1].text.should == 'flamingo'
272
+ end
273
+
268
274
  it "should allow comma separated selectors" do
269
275
  @results = xpath { |x| x.descendant[x.attr(:id) == 'moar'].css('div, p') }
270
276
  @results[0].text.should == 'chimp'
271
- @results[1].text.should == 'flamingo'
272
- @results[2].text.should == 'elephant'
277
+ @results[1].text.should == 'elephant'
278
+ @results[2].text.should == 'flamingo'
273
279
  end
274
280
  end
275
281
 
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 2
9
- version: 0.1.2
8
+ - 3
9
+ version: 0.1.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jonas Nicklas
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-10-08 00:00:00 +02:00
17
+ date: 2011-01-09 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency