xpath 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12f29349abdcae71838e3a6c0f9f6d7eac41b378e2fbdc3bcd6996950b76da7e
4
- data.tar.gz: 819e1a3641e979a632bf9358609da87155920ca1fc07e89b089b4a30e3681d39
3
+ metadata.gz: a243005210afa835c320ea204ab3105d0b253dfdb905d4ff53c8267e53a23d6d
4
+ data.tar.gz: 4978108857ddbd50e336926db82b6bb056656861572aa518654cff2dcadb2bc7
5
5
  SHA512:
6
- metadata.gz: 5c6ee15be0134334b4cb7016b252da4985a8f356cba571b84078af03745c612b13640b1cc77617a5f80d90ab643b2401cfe08b5d96fe02affd010d627ede88a4
7
- data.tar.gz: 223c56e87b09e1cf7d89e44d8fe4ac1639ce91280392bbbe25fc8b78d6cbf19a613f1d87a9d6f4ace14ad4973c80fdd7a20cbd292f188ffa571e3b72a2145197
6
+ metadata.gz: e17ddd74ff29ac77050bec7cb5ee93f8b1c2386c56ea4390272d998540a69cf8f26f61541de3a583866b4531836d051e722ca93eabc9d52636e722aa78de491b
7
+ data.tar.gz: c75b155e85156faafa9e3ac63e7c16b7fbc20385b80ada25dcb5c0c680ea06fd06490a5d2e9096d68a51b22b62b06f5ad6b5d7b6e0191396e748bbd7e415d3ce
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'nokogiri'
2
4
 
3
5
  require 'xpath/dsl'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module XPath
2
4
  module DSL
3
5
  def current
@@ -80,11 +82,11 @@ module XPath
80
82
  # boolean
81
83
  :boolean, :not, :true, :false, :lang,
82
84
  # number
83
- :number, :sum, :floor, :ceiling, :round,
84
- ]
85
+ :number, :sum, :floor, :ceiling, :round
86
+ ].freeze
85
87
 
86
88
  METHODS.each do |key|
87
- name = key.to_s.gsub("_", "-").to_sym
89
+ name = key.to_s.tr('_', '-').to_sym
88
90
  define_method key do |*args|
89
91
  method(name, *args)
90
92
  end
@@ -101,20 +103,20 @@ module XPath
101
103
  alias_method :n, :normalize_space
102
104
 
103
105
  OPERATORS = [
104
- [:equals, :"=", :==],
105
- [:or, :or, :|],
106
- [:and, :and, :&],
107
- [:not_equals, :!=, :!=],
108
- [:lte, :<=, :<=],
109
- [:lt, :<, :<],
110
- [:gte, :>=, :>=],
111
- [:gt, :>, :>],
112
- [:plus, :+],
113
- [:minus, :-],
114
- [:multiply, :*, :*],
115
- [:divide, :div, :/],
116
- [:mod, :mod, :%],
117
- ]
106
+ %i[equals = ==],
107
+ %i[or or |],
108
+ %i[and and &],
109
+ %i[not_equals != !=],
110
+ %i[lte <= <=],
111
+ %i[lt < <],
112
+ %i[gte >= >=],
113
+ %i[gt > >],
114
+ %i[plus +],
115
+ %i[minus -],
116
+ %i[multiply * *],
117
+ %i[divide div /],
118
+ %i[mod mod %]
119
+ ].freeze
118
120
 
119
121
  OPERATORS.each do |(name, operator, alias_name)|
120
122
  define_method name do |rhs|
@@ -123,14 +125,14 @@ module XPath
123
125
  alias_method alias_name, name if alias_name
124
126
  end
125
127
 
126
- AXES = [
127
- :ancestor, :ancestor_or_self, :attribute, :descendant_or_self,
128
- :following, :following_sibling, :namespace, :parent, :preceding,
129
- :preceding_sibling, :self,
130
- ]
128
+ AXES = %i[
129
+ ancestor ancestor_or_self attribute descendant_or_self
130
+ following following_sibling namespace parent preceding
131
+ preceding_sibling self
132
+ ].freeze
131
133
 
132
134
  AXES.each do |key|
133
- name = key.to_s.gsub("_", "-").to_sym
135
+ name = key.to_s.tr('_', '-').to_sym
134
136
  define_method key do |*element_names|
135
137
  axis(name, *element_names)
136
138
  end
@@ -143,15 +145,22 @@ module XPath
143
145
  end
144
146
 
145
147
  def contains_word(word)
146
- function(:concat, " ", current.normalize_space, " ").contains(" #{word} ")
148
+ function(:concat, ' ', current.normalize_space, ' ').contains(" #{word} ")
149
+ end
150
+
151
+ UPPERCASE_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'
152
+ LOWERCASE_LETTERS = 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'
153
+
154
+ def lowercase
155
+ method(:translate, UPPERCASE_LETTERS, LOWERCASE_LETTERS)
156
+ end
157
+
158
+ def uppercase
159
+ method(:translate, LOWERCASE_LETTERS, UPPERCASE_LETTERS)
147
160
  end
148
161
 
149
162
  def one_of(*expressions)
150
- expressions.map do |e|
151
- current.equals(e)
152
- end.reduce do |a, b|
153
- a.or(b)
154
- end
163
+ expressions.map { |e| current.equals(e) }.reduce(:or)
155
164
  end
156
165
 
157
166
  def next_sibling(*expressions)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module XPath
2
4
  class Expression
3
5
  attr_accessor :expression, :arguments
@@ -12,7 +14,7 @@ module XPath
12
14
  self
13
15
  end
14
16
 
15
- def to_xpath(type=nil)
17
+ def to_xpath(type = nil)
16
18
  Renderer.render(self, type)
17
19
  end
18
20
  alias_method :to_s, :to_xpath
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module XPath
2
4
  class Literal
3
5
  attr_reader :value
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module XPath
2
4
  class Renderer
3
5
  def self.render(node, type)
@@ -15,11 +17,11 @@ module XPath
15
17
 
16
18
  def convert_argument(argument)
17
19
  case argument
18
- when Expression, Union then render(argument)
19
- when Array then argument.map { |element| convert_argument(element) }
20
- when String then string_literal(argument)
21
- when Literal then argument.value
22
- else argument.to_s
20
+ when Expression, Union then render(argument)
21
+ when Array then argument.map { |element| convert_argument(element) }
22
+ when String then string_literal(argument)
23
+ when Literal then argument.value
24
+ else argument.to_s
23
25
  end
24
26
  end
25
27
 
@@ -27,7 +29,7 @@ module XPath
27
29
  if string.include?("'")
28
30
  string = string.split("'", -1).map do |substr|
29
31
  "'#{substr}'"
30
- end.join(%q{,"'",})
32
+ end.join(%q(,"'",))
31
33
  "concat(#{string})"
32
34
  else
33
35
  "'#{string}'"
@@ -51,7 +53,7 @@ module XPath
51
53
  end
52
54
 
53
55
  def anywhere(element_names)
54
- with_element_conditions("//", element_names)
56
+ with_element_conditions('//', element_names)
55
57
  end
56
58
 
57
59
  def where(on, condition)
@@ -59,7 +61,11 @@ module XPath
59
61
  end
60
62
 
61
63
  def attribute(current, name)
62
- "#{current}/@#{name}"
64
+ if valid_xml_name?(name)
65
+ "#{current}/@#{name}"
66
+ else
67
+ "#{current}/attribute::*[local-name(.) = #{string_literal(name)}]"
68
+ end
63
69
  end
64
70
 
65
71
  def binary_operator(name, left, right)
@@ -68,7 +74,7 @@ module XPath
68
74
 
69
75
  def is(one, two)
70
76
  if @type == :exact
71
- binary_operator("=", one, two)
77
+ binary_operator('=', one, two)
72
78
  else
73
79
  function(:contains, one, two)
74
80
  end
@@ -98,7 +104,7 @@ module XPath
98
104
  end
99
105
 
100
106
  def function(name, *arguments)
101
- "#{name}(#{arguments.join(", ")})"
107
+ "#{name}(#{arguments.join(', ')})"
102
108
  end
103
109
 
104
110
  private
@@ -107,10 +113,14 @@ module XPath
107
113
  if element_names.length == 1
108
114
  "#{expression}#{element_names.first}"
109
115
  elsif element_names.length > 1
110
- "#{expression}*[#{element_names.map { |e| "self::#{e}" }.join(" | ")}]"
116
+ "#{expression}*[#{element_names.map { |e| "self::#{e}" }.join(' | ')}]"
111
117
  else
112
118
  "#{expression}*"
113
119
  end
114
120
  end
121
+
122
+ def valid_xml_name?(name)
123
+ name =~ /^[a-zA-Z_:][a-zA-Z0-9_:\.\-]*$/
124
+ end
115
125
  end
116
126
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module XPath
2
4
  class Union
3
5
  include Enumerable
@@ -17,11 +19,11 @@ module XPath
17
19
  arguments.each(&block)
18
20
  end
19
21
 
20
- def method_missing(*args)
22
+ def method_missing(*args) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
21
23
  XPath::Union.new(*arguments.map { |e| e.send(*args) })
22
24
  end
23
25
 
24
- def to_xpath(type=nil)
26
+ def to_xpath(type = nil)
25
27
  Renderer.render(self, type)
26
28
  end
27
29
  alias_method :to_s, :to_xpath
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module XPath
2
- VERSION = '3.1.0'
4
+ VERSION = '3.2.0'
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'xpath'
2
4
  require 'pry'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe XPath::Union do
@@ -5,7 +7,7 @@ describe XPath::Union do
5
7
  let(:doc) { Nokogiri::HTML(template) }
6
8
 
7
9
  describe '#expressions' do
8
- it "should return the expressions" do
10
+ it 'should return the expressions' do
9
11
  @expr1 = XPath.generate { |x| x.descendant(:p) }
10
12
  @expr2 = XPath.generate { |x| x.descendant(:div) }
11
13
  @collection = XPath::Union.new(@expr1, @expr2)
@@ -14,7 +16,7 @@ describe XPath::Union do
14
16
  end
15
17
 
16
18
  describe '#each' do
17
- it "should iterate through the expressions" do
19
+ it 'should iterate through the expressions' do
18
20
  @expr1 = XPath.generate { |x| x.descendant(:p) }
19
21
  @expr2 = XPath.generate { |x| x.descendant(:div) }
20
22
  @collection = XPath::Union.new(@expr1, @expr2)
@@ -25,16 +27,16 @@ describe XPath::Union do
25
27
  end
26
28
 
27
29
  describe '#map' do
28
- it "should map the expressions" do
30
+ it 'should map the expressions' do
29
31
  @expr1 = XPath.generate { |x| x.descendant(:p) }
30
32
  @expr2 = XPath.generate { |x| x.descendant(:div) }
31
33
  @collection = XPath::Union.new(@expr1, @expr2)
32
- @collection.map { |expr| expr.expression }.should eq [:descendant, :descendant]
34
+ @collection.map(&:expression).should eq %i[descendant descendant]
33
35
  end
34
36
  end
35
37
 
36
38
  describe '#to_xpath' do
37
- it "should create a valid xpath expression" do
39
+ it 'should create a valid xpath expression' do
38
40
  @expr1 = XPath.generate { |x| x.descendant(:p) }
39
41
  @expr2 = XPath.generate { |x| x.descendant(:div).where(x.attr(:id) == 'foo') }
40
42
  @collection = XPath::Union.new(@expr1, @expr2)
@@ -45,9 +47,8 @@ describe XPath::Union do
45
47
  end
46
48
  end
47
49
 
48
-
49
50
  describe '#where and others' do
50
- it "should be delegated to the individual expressions" do
51
+ it 'should be delegated to the individual expressions' do
51
52
  @expr1 = XPath.generate { |x| x.descendant(:p) }
52
53
  @expr2 = XPath.generate { |x| x.descendant(:div) }
53
54
  @collection = XPath::Union.new(@expr1, @expr2)
@@ -59,6 +60,4 @@ describe XPath::Union do
59
60
  @results[0][:id].should eq 'fooDiv'
60
61
  end
61
62
  end
62
-
63
63
  end
64
-
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  require 'nokogiri'
@@ -14,23 +16,23 @@ describe XPath do
14
16
  let(:template) { File.read(File.expand_path('fixtures/simple.html', File.dirname(__FILE__))) }
15
17
  let(:doc) { Nokogiri::HTML(template) }
16
18
 
17
- def xpath(type=nil, &block)
19
+ def xpath(type = nil, &block)
18
20
  doc.xpath XPath.generate(&block).to_xpath(type)
19
21
  end
20
22
 
21
- it "should work as a mixin" do
23
+ it 'should work as a mixin' do
22
24
  xpath = Thingy.new.foo_div.to_xpath
23
25
  doc.xpath(xpath).first[:title].should eq 'fooDiv'
24
26
  end
25
27
 
26
28
  describe '#descendant' do
27
- it "should find nodes that are nested below the current node" do
29
+ it 'should find nodes that are nested below the current node' do
28
30
  @results = xpath { |x| x.descendant(:p) }
29
- @results[0].text.should eq "Blah"
30
- @results[1].text.should eq "Bax"
31
+ @results[0].text.should eq 'Blah'
32
+ @results[1].text.should eq 'Bax'
31
33
  end
32
34
 
33
- it "should not find nodes outside the context" do
35
+ it 'should not find nodes outside the context' do
34
36
  @results = xpath do |x|
35
37
  foo_div = x.descendant(:div).where(x.attr(:id) == 'foo')
36
38
  x.descendant(:p).where(x.attr(:id) == foo_div.attr(:title))
@@ -38,13 +40,13 @@ describe XPath do
38
40
  @results[0].should be_nil
39
41
  end
40
42
 
41
- it "should find multiple kinds of nodes" do
43
+ it 'should find multiple kinds of nodes' do
42
44
  @results = xpath { |x| x.descendant(:p, :ul) }
43
45
  @results[0].text.should eq 'Blah'
44
46
  @results[3].text.should eq 'A list'
45
47
  end
46
48
 
47
- it "should find all nodes when no arguments given" do
49
+ it 'should find all nodes when no arguments given' do
48
50
  @results = xpath { |x| x.descendant[x.attr(:id) == 'foo'].descendant }
49
51
  @results[0].text.should eq 'Blah'
50
52
  @results[4].text.should eq 'A list'
@@ -52,24 +54,24 @@ describe XPath do
52
54
  end
53
55
 
54
56
  describe '#child' do
55
- it "should find nodes that are nested directly below the current node" do
57
+ it 'should find nodes that are nested directly below the current node' do
56
58
  @results = xpath { |x| x.descendant(:div).child(:p) }
57
- @results[0].text.should eq "Blah"
58
- @results[1].text.should eq "Bax"
59
+ @results[0].text.should eq 'Blah'
60
+ @results[1].text.should eq 'Bax'
59
61
  end
60
62
 
61
- it "should not find nodes that are nested further down below the current node" do
63
+ it 'should not find nodes that are nested further down below the current node' do
62
64
  @results = xpath { |x| x.child(:p) }
63
65
  @results[0].should be_nil
64
66
  end
65
67
 
66
- it "should find multiple kinds of nodes" do
68
+ it 'should find multiple kinds of nodes' do
67
69
  @results = xpath { |x| x.descendant(:div).child(:p, :ul) }
68
70
  @results[0].text.should eq 'Blah'
69
71
  @results[3].text.should eq 'A list'
70
72
  end
71
73
 
72
- it "should find all nodes when no arguments given" do
74
+ it 'should find all nodes when no arguments given' do
73
75
  @results = xpath { |x| x.descendant[x.attr(:id) == 'foo'].child }
74
76
  @results[0].text.should eq 'Blah'
75
77
  @results[3].text.should eq 'A list'
@@ -77,19 +79,19 @@ describe XPath do
77
79
  end
78
80
 
79
81
  describe '#axis' do
80
- it "should find nodes given the xpath axis" do
82
+ it 'should find nodes given the xpath axis' do
81
83
  @results = xpath { |x| x.axis(:descendant, :p) }
82
- @results[0].text.should eq "Blah"
84
+ @results[0].text.should eq 'Blah'
83
85
  end
84
86
 
85
- it "should find nodes given the xpath axis without a specific tag" do
87
+ it 'should find nodes given the xpath axis without a specific tag' do
86
88
  @results = xpath { |x| x.descendant(:div)[x.attr(:id) == 'foo'].axis(:descendant) }
87
- @results[0][:id].should eq "fooDiv"
89
+ @results[0][:id].should eq 'fooDiv'
88
90
  end
89
91
  end
90
92
 
91
93
  describe '#next_sibling' do
92
- it "should find nodes which are immediate siblings of the current node" do
94
+ it 'should find nodes which are immediate siblings of the current node' do
93
95
  xpath { |x| x.descendant(:p)[x.attr(:id) == 'fooDiv'].next_sibling(:p) }.first.text.should eq 'Bax'
94
96
  xpath { |x| x.descendant(:p)[x.attr(:id) == 'fooDiv'].next_sibling(:ul, :p) }.first.text.should eq 'Bax'
95
97
  xpath { |x| x.descendant(:p)[x.attr(:title) == 'monkey'].next_sibling(:ul, :p) }.first.text.should eq 'A list'
@@ -99,7 +101,7 @@ describe XPath do
99
101
  end
100
102
 
101
103
  describe '#previous_sibling' do
102
- it "should find nodes which are exactly preceding the current node" do
104
+ it 'should find nodes which are exactly preceding the current node' do
103
105
  xpath { |x| x.descendant(:p)[x.attr(:id) == 'wooDiv'].previous_sibling(:p) }.first.text.should eq 'Bax'
104
106
  xpath { |x| x.descendant(:p)[x.attr(:id) == 'wooDiv'].previous_sibling(:ul, :p) }.first.text.should eq 'Bax'
105
107
  xpath { |x| x.descendant(:p)[x.attr(:title) == 'gorilla'].previous_sibling(:ul, :p) }.first.text.should eq 'A list'
@@ -109,17 +111,17 @@ describe XPath do
109
111
  end
110
112
 
111
113
  describe '#anywhere' do
112
- it "should find nodes regardless of the context" do
114
+ it 'should find nodes regardless of the context' do
113
115
  @results = xpath do |x|
114
116
  foo_div = x.anywhere(:div).where(x.attr(:id) == 'foo')
115
117
  x.descendant(:p).where(x.attr(:id) == foo_div.attr(:title))
116
118
  end
117
- @results[0].text.should eq "Blah"
119
+ @results[0].text.should eq 'Blah'
118
120
  end
119
121
 
120
- it "should find multiple kinds of nodes regardless of the context" do
122
+ it 'should find multiple kinds of nodes regardless of the context' do
121
123
  @results = xpath do |x|
122
- context=x.descendant(:div).where(x.attr(:id)=='woo')
124
+ context = x.descendant(:div).where(x.attr(:id) == 'woo')
123
125
  context.anywhere(:p, :ul)
124
126
  end
125
127
 
@@ -129,9 +131,9 @@ describe XPath do
129
131
  @results[6].text.should eq 'Bax'
130
132
  end
131
133
 
132
- it "should find all nodes when no arguments given regardless of the context" do
134
+ it 'should find all nodes when no arguments given regardless of the context' do
133
135
  @results = xpath do |x|
134
- context=x.descendant(:div).where(x.attr(:id)=='woo')
136
+ context = x.descendant(:div).where(x.attr(:id) == 'woo')
135
137
  context.anywhere
136
138
  end
137
139
  @results[0].name.should eq 'html'
@@ -142,72 +144,89 @@ describe XPath do
142
144
  @results[13].text.should eq 'A list'
143
145
  @results[15].text.should eq 'Bax'
144
146
  end
145
-
146
147
  end
147
148
 
148
149
  describe '#contains' do
149
- it "should find nodes that contain the given string" do
150
+ it 'should find nodes that contain the given string' do
150
151
  @results = xpath do |x|
151
152
  x.descendant(:div).where(x.attr(:title).contains('ooD'))
152
153
  end
153
- @results[0][:id].should eq "foo"
154
+ @results[0][:id].should eq 'foo'
154
155
  end
155
156
 
156
- it "should find nodes that contain the given expression" do
157
+ it 'should find nodes that contain the given expression' do
157
158
  @results = xpath do |x|
158
159
  expression = x.anywhere(:div).where(x.attr(:title) == 'fooDiv').attr(:id)
159
160
  x.descendant(:div).where(x.attr(:title).contains(expression))
160
161
  end
161
- @results[0][:id].should eq "foo"
162
+ @results[0][:id].should eq 'foo'
162
163
  end
163
164
  end
164
165
 
165
- describe "#contains_word" do
166
- it "should find nodes that contain the given word in its entirety" do
166
+ describe '#contains_word' do
167
+ it 'should find nodes that contain the given word in its entirety' do
167
168
  @results = xpath do |x|
168
169
  x.descendant.where(x.attr(:class).contains_word('fish'))
169
170
  end
170
- @results[0].text.should eq "Bax"
171
- @results[1].text.should eq "llama"
171
+ @results[0].text.should eq 'Bax'
172
+ @results[1].text.should eq 'llama'
172
173
  @results.length.should eq 2
173
174
  end
174
175
  end
175
176
 
176
177
  describe '#starts_with' do
177
- it "should find nodes that begin with the given string" do
178
+ it 'should find nodes that begin with the given string' do
178
179
  @results = xpath do |x|
179
180
  x.descendant(:*).where(x.attr(:id).starts_with('foo'))
180
181
  end
181
182
  @results.size.should eq 2
182
- @results[0][:id].should eq "foo"
183
- @results[1][:id].should eq "fooDiv"
183
+ @results[0][:id].should eq 'foo'
184
+ @results[1][:id].should eq 'fooDiv'
184
185
  end
185
186
 
186
- it "should find nodes that contain the given expression" do
187
+ it 'should find nodes that contain the given expression' do
187
188
  @results = xpath do |x|
188
189
  expression = x.anywhere(:div).where(x.attr(:title) == 'fooDiv').attr(:id)
189
190
  x.descendant(:div).where(x.attr(:title).starts_with(expression))
190
191
  end
191
- @results[0][:id].should eq "foo"
192
+ @results[0][:id].should eq 'foo'
192
193
  end
193
194
  end
194
195
 
195
196
  describe '#ends_with' do
196
- it "should find nodes that end with the given string" do
197
+ it 'should find nodes that end with the given string' do
197
198
  @results = xpath do |x|
198
199
  x.descendant(:*).where(x.attr(:id).ends_with('oof'))
199
200
  end
200
201
  @results.size.should eq 2
201
- @results[0][:id].should eq "oof"
202
- @results[1][:id].should eq "viDoof"
202
+ @results[0][:id].should eq 'oof'
203
+ @results[1][:id].should eq 'viDoof'
203
204
  end
204
205
 
205
- it "should find nodes that contain the given expression" do
206
+ it 'should find nodes that contain the given expression' do
206
207
  @results = xpath do |x|
207
208
  expression = x.anywhere(:div).where(x.attr(:title) == 'viDoof').attr(:id)
208
209
  x.descendant(:div).where(x.attr(:title).ends_with(expression))
209
210
  end
210
- @results[0][:id].should eq "oof"
211
+ @results[0][:id].should eq 'oof'
212
+ end
213
+ end
214
+
215
+ describe '#uppercase' do
216
+ it 'should match uppercased text' do
217
+ @results = xpath do |x|
218
+ x.descendant(:div).where(x.attr(:title).uppercase == 'VIDOOF')
219
+ end
220
+ @results[0][:id].should eq 'oof'
221
+ end
222
+ end
223
+
224
+ describe '#lowercase' do
225
+ it 'should match lowercased text' do
226
+ @results = xpath do |x|
227
+ x.descendant(:div).where(x.attr(:title).lowercase == 'vidoof')
228
+ end
229
+ @results[0][:id].should eq 'oof'
211
230
  end
212
231
  end
213
232
 
@@ -222,177 +241,176 @@ describe XPath do
222
241
  end
223
242
 
224
243
  describe '#substring' do
225
- context "when called with one argument" do
226
- it "should select the part of a string after the specified character" do
227
- @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == "substring").text.substring(7) }
228
- @results.should eq "there"
244
+ context 'when called with one argument' do
245
+ it 'should select the part of a string after the specified character' do
246
+ @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == 'substring').text.substring(7) }
247
+ @results.should eq 'there'
229
248
  end
230
249
  end
231
250
 
232
- context "when called with two arguments" do
233
- it "should select the part of a string after the specified character, up to the given length" do
234
- @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == "substring").text.substring(2, 4) }
235
- @results.should eq "ello"
251
+ context 'when called with two arguments' do
252
+ it 'should select the part of a string after the specified character, up to the given length' do
253
+ @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == 'substring').text.substring(2, 4) }
254
+ @results.should eq 'ello'
236
255
  end
237
256
  end
238
257
  end
239
258
 
240
259
  describe '#function' do
241
- it "should call the given xpath function" do
260
+ it 'should call the given xpath function' do
242
261
  @results = xpath { |x| x.function(:boolean, x.function(:true) == x.function(:false)) }
243
262
  @results.should eq false
244
263
  end
245
264
  end
246
265
 
247
266
  describe '#method' do
248
- it "should call the given xpath function with the current node as the first argument" do
249
- @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == "string-length").text.method(:"string-length") }
267
+ it 'should call the given xpath function with the current node as the first argument' do
268
+ @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == 'string-length').text.method(:"string-length") }
250
269
  @results.should eq 11
251
270
  end
252
271
  end
253
272
 
254
273
  describe '#string_length' do
255
- it "should return the length of a string" do
256
- @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == "string-length").text.string_length }
274
+ it 'should return the length of a string' do
275
+ @results = xpath { |x| x.descendant(:span).where(x.attr(:id) == 'string-length').text.string_length }
257
276
  @results.should eq 11
258
277
  end
259
278
  end
260
279
 
261
280
  describe '#where' do
262
- it "should limit the expression to find only certain nodes" do
263
- xpath { |x| x.descendant(:div).where(:"@id = 'foo'") }.first[:title].should eq "fooDiv"
281
+ it 'should limit the expression to find only certain nodes' do
282
+ xpath { |x| x.descendant(:div).where(:"@id = 'foo'") }.first[:title].should eq 'fooDiv'
264
283
  end
265
284
 
266
- it "should be aliased as []" do
267
- xpath { |x| x.descendant(:div)[:"@id = 'foo'"] }.first[:title].should eq "fooDiv"
285
+ it 'should be aliased as []' do
286
+ xpath { |x| x.descendant(:div)[:"@id = 'foo'"] }.first[:title].should eq 'fooDiv'
268
287
  end
269
288
 
270
- it "should be a no-op when nil condition is passed" do
271
- XPath.descendant(:div).where(nil).to_s.should eq ".//div"
289
+ it 'should be a no-op when nil condition is passed' do
290
+ XPath.descendant(:div).where(nil).to_s.should eq './/div'
272
291
  end
273
292
  end
274
293
 
275
294
  describe '#inverse' do
276
- it "should invert the expression" do
295
+ it 'should invert the expression' do
277
296
  xpath { |x| x.descendant(:p).where(x.attr(:id).equals('fooDiv').inverse) }.first.text.should eq 'Bax'
278
297
  end
279
298
 
280
- it "should be aliased as the unary tilde" do
299
+ it 'should be aliased as the unary tilde' do
281
300
  xpath { |x| x.descendant(:p).where(~x.attr(:id).equals('fooDiv')) }.first.text.should eq 'Bax'
282
301
  end
283
302
 
284
- it "should be aliased as the unary bang" do
303
+ it 'should be aliased as the unary bang' do
285
304
  xpath { |x| x.descendant(:p).where(!x.attr(:id).equals('fooDiv')) }.first.text.should eq 'Bax'
286
305
  end
287
306
  end
288
307
 
289
308
  describe '#equals' do
290
- it "should limit the expression to find only certain nodes" do
291
- xpath { |x| x.descendant(:div).where(x.attr(:id).equals('foo')) }.first[:title].should eq "fooDiv"
309
+ it 'should limit the expression to find only certain nodes' do
310
+ xpath { |x| x.descendant(:div).where(x.attr(:id).equals('foo')) }.first[:title].should eq 'fooDiv'
292
311
  end
293
312
 
294
- it "should be aliased as ==" do
295
- xpath { |x| x.descendant(:div).where(x.attr(:id) == 'foo') }.first[:title].should eq "fooDiv"
313
+ it 'should be aliased as ==' do
314
+ xpath { |x| x.descendant(:div).where(x.attr(:id) == 'foo') }.first[:title].should eq 'fooDiv'
296
315
  end
297
316
  end
298
317
 
299
318
  describe '#not_equals' do
300
- it "should match only when not equal" do
301
- xpath { |x| x.descendant(:div).where(x.attr(:id).not_equals('bar')) }.first[:title].should eq "fooDiv"
319
+ it 'should match only when not equal' do
320
+ xpath { |x| x.descendant(:div).where(x.attr(:id).not_equals('bar')) }.first[:title].should eq 'fooDiv'
302
321
  end
303
322
 
304
- it "should be aliased as !=" do
305
- xpath { |x| x.descendant(:div).where(x.attr(:id) != 'bar') }.first[:title].should eq "fooDiv"
323
+ it 'should be aliased as !=' do
324
+ xpath { |x| x.descendant(:div).where(x.attr(:id) != 'bar') }.first[:title].should eq 'fooDiv'
306
325
  end
307
326
  end
308
327
 
309
-
310
328
  describe '#is' do
311
- it "uses equality when :exact given" do
312
- xpath(:exact) { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should eq "fooDiv"
329
+ it 'uses equality when :exact given' do
330
+ xpath(:exact) { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should eq 'fooDiv'
313
331
  xpath(:exact) { |x| x.descendant(:div).where(x.attr(:id).is('oo')) }.first.should be_nil
314
332
  end
315
333
 
316
- it "uses substring matching otherwise" do
317
- xpath { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should eq "fooDiv"
318
- xpath { |x| x.descendant(:div).where(x.attr(:id).is('oo')) }.first[:title].should eq "fooDiv"
334
+ it 'uses substring matching otherwise' do
335
+ xpath { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should eq 'fooDiv'
336
+ xpath { |x| x.descendant(:div).where(x.attr(:id).is('oo')) }.first[:title].should eq 'fooDiv'
319
337
  end
320
338
  end
321
339
 
322
340
  describe '#one_of' do
323
- it "should return all nodes where the condition matches" do
341
+ it 'should return all nodes where the condition matches' do
324
342
  @results = xpath do |x|
325
343
  p = x.anywhere(:div).where(x.attr(:id) == 'foo').attr(:title)
326
344
  x.descendant(:*).where(x.attr(:id).one_of('foo', p, 'baz'))
327
345
  end
328
- @results[0][:title].should eq "fooDiv"
329
- @results[1].text.should eq "Blah"
330
- @results[2][:title].should eq "bazDiv"
346
+ @results[0][:title].should eq 'fooDiv'
347
+ @results[1].text.should eq 'Blah'
348
+ @results[2][:title].should eq 'bazDiv'
331
349
  end
332
350
  end
333
351
 
334
352
  describe '#and' do
335
- it "should find all nodes in both expression" do
353
+ it 'should find all nodes in both expression' do
336
354
  @results = xpath do |x|
337
355
  x.descendant(:*).where(x.contains('Bax').and(x.attr(:title).equals('monkey')))
338
356
  end
339
- @results[0][:title].should eq "monkey"
357
+ @results[0][:title].should eq 'monkey'
340
358
  end
341
359
 
342
- it "should be aliased as ampersand (&)" do
360
+ it 'should be aliased as ampersand (&)' do
343
361
  @results = xpath do |x|
344
362
  x.descendant(:*).where(x.contains('Bax') & x.attr(:title).equals('monkey'))
345
363
  end
346
- @results[0][:title].should eq "monkey"
364
+ @results[0][:title].should eq 'monkey'
347
365
  end
348
366
  end
349
367
 
350
368
  describe '#or' do
351
- it "should find all nodes in either expression" do
369
+ it 'should find all nodes in either expression' do
352
370
  @results = xpath do |x|
353
371
  x.descendant(:*).where(x.attr(:id).equals('foo').or(x.attr(:id).equals('fooDiv')))
354
372
  end
355
- @results[0][:title].should eq "fooDiv"
356
- @results[1].text.should eq "Blah"
373
+ @results[0][:title].should eq 'fooDiv'
374
+ @results[1].text.should eq 'Blah'
357
375
  end
358
376
 
359
- it "should be aliased as pipe (|)" do
377
+ it 'should be aliased as pipe (|)' do
360
378
  @results = xpath do |x|
361
379
  x.descendant(:*).where(x.attr(:id).equals('foo') | x.attr(:id).equals('fooDiv'))
362
380
  end
363
- @results[0][:title].should eq "fooDiv"
364
- @results[1].text.should eq "Blah"
381
+ @results[0][:title].should eq 'fooDiv'
382
+ @results[1].text.should eq 'Blah'
365
383
  end
366
384
  end
367
385
 
368
386
  describe '#attr' do
369
- it "should be an attribute" do
387
+ it 'should be an attribute' do
370
388
  @results = xpath { |x| x.descendant(:div).where(x.attr(:id)) }
371
- @results[0][:title].should eq "barDiv"
372
- @results[1][:title].should eq "fooDiv"
389
+ @results[0][:title].should eq 'barDiv'
390
+ @results[1][:title].should eq 'fooDiv'
373
391
  end
374
392
  end
375
393
 
376
394
  describe '#css' do
377
- it "should find nodes by the given CSS selector" do
395
+ it 'should find nodes by the given CSS selector' do
378
396
  @results = xpath { |x| x.css('#preference p') }
379
397
  @results[0].text.should eq 'allamas'
380
398
  @results[1].text.should eq 'llama'
381
399
  end
382
400
 
383
- it "should respect previous expression" do
401
+ it 'should respect previous expression' do
384
402
  @results = xpath { |x| x.descendant[x.attr(:id) == 'moar'].css('p') }
385
403
  @results[0].text.should eq 'chimp'
386
404
  @results[1].text.should eq 'flamingo'
387
405
  end
388
406
 
389
- it "should be composable" do
407
+ it 'should be composable' do
390
408
  @results = xpath { |x| x.css('#moar').descendant(:p) }
391
409
  @results[0].text.should eq 'chimp'
392
410
  @results[1].text.should eq 'flamingo'
393
411
  end
394
412
 
395
- it "should allow comma separated selectors" do
413
+ it 'should allow comma separated selectors' do
396
414
  @results = xpath { |x| x.descendant[x.attr(:id) == 'moar'].css('div, p') }
397
415
  @results[0].text.should eq 'chimp'
398
416
  @results[1].text.should eq 'elephant'
@@ -402,12 +420,12 @@ describe XPath do
402
420
 
403
421
  describe '#qname' do
404
422
  it "should match the node's name" do
405
- xpath { |x| x.descendant(:*).where(x.qname == 'ul') }.first.text.should eq "A list"
423
+ xpath { |x| x.descendant(:*).where(x.qname == 'ul') }.first.text.should eq 'A list'
406
424
  end
407
425
  end
408
426
 
409
427
  describe '#union' do
410
- it "should create a union expression" do
428
+ it 'should create a union expression' do
411
429
  @expr1 = XPath.generate { |x| x.descendant(:p) }
412
430
  @expr2 = XPath.generate { |x| x.descendant(:div) }
413
431
  @collection = @expr1.union(@expr2)
@@ -419,7 +437,7 @@ describe XPath do
419
437
  @results[0][:id].should eq 'fooDiv'
420
438
  end
421
439
 
422
- it "should be aliased as +" do
440
+ it 'should be aliased as +' do
423
441
  @expr1 = XPath.generate { |x| x.descendant(:p) }
424
442
  @expr2 = XPath.generate { |x| x.descendant(:div) }
425
443
  @collection = @expr1 + @expr2
@@ -432,113 +450,113 @@ describe XPath do
432
450
  end
433
451
  end
434
452
 
435
- describe "#last" do
436
- it "returns the number of elements in the context" do
453
+ describe '#last' do
454
+ it 'returns the number of elements in the context' do
437
455
  @results = xpath { |x| x.descendant(:p)[XPath.position() == XPath.last()] }
438
- @results[0].text.should eq "Bax"
439
- @results[1].text.should eq "Blah"
440
- @results[2].text.should eq "llama"
456
+ @results[0].text.should eq 'Bax'
457
+ @results[1].text.should eq 'Blah'
458
+ @results[2].text.should eq 'llama'
441
459
  end
442
460
  end
443
461
 
444
- describe "#position" do
445
- it "returns the position of elements in the context" do
462
+ describe '#position' do
463
+ it 'returns the position of elements in the context' do
446
464
  @results = xpath { |x| x.descendant(:p)[XPath.position() == 2] }
447
- @results[0].text.should eq "Bax"
448
- @results[1].text.should eq "Bax"
465
+ @results[0].text.should eq 'Bax'
466
+ @results[1].text.should eq 'Bax'
449
467
  end
450
468
  end
451
469
 
452
- describe "#count" do
453
- it "counts the number of occurrences" do
470
+ describe '#count' do
471
+ it 'counts the number of occurrences' do
454
472
  @results = xpath { |x| x.descendant(:div)[x.descendant(:p).count == 2] }
455
- @results[0][:id].should eq "preference"
473
+ @results[0][:id].should eq 'preference'
456
474
  end
457
475
  end
458
476
 
459
- describe "#lte" do
460
- it "checks lesser than or equal" do
477
+ describe '#lte' do
478
+ it 'checks lesser than or equal' do
461
479
  @results = xpath { |x| x.descendant(:p)[XPath.position() <= 2] }
462
- @results[0].text.should eq "Blah"
463
- @results[1].text.should eq "Bax"
464
- @results[2][:title].should eq "gorilla"
465
- @results[3].text.should eq "Bax"
480
+ @results[0].text.should eq 'Blah'
481
+ @results[1].text.should eq 'Bax'
482
+ @results[2][:title].should eq 'gorilla'
483
+ @results[3].text.should eq 'Bax'
466
484
  end
467
485
  end
468
486
 
469
- describe "#lt" do
470
- it "checks lesser than" do
487
+ describe '#lt' do
488
+ it 'checks lesser than' do
471
489
  @results = xpath { |x| x.descendant(:p)[XPath.position() < 2] }
472
- @results[0].text.should eq "Blah"
473
- @results[1][:title].should eq "gorilla"
490
+ @results[0].text.should eq 'Blah'
491
+ @results[1][:title].should eq 'gorilla'
474
492
  end
475
493
  end
476
494
 
477
- describe "#gte" do
478
- it "checks greater than or equal" do
495
+ describe '#gte' do
496
+ it 'checks greater than or equal' do
479
497
  @results = xpath { |x| x.descendant(:p)[XPath.position() >= 2] }
480
- @results[0].text.should eq "Bax"
481
- @results[1][:title].should eq "monkey"
482
- @results[2].text.should eq "Bax"
483
- @results[3].text.should eq "Blah"
498
+ @results[0].text.should eq 'Bax'
499
+ @results[1][:title].should eq 'monkey'
500
+ @results[2].text.should eq 'Bax'
501
+ @results[3].text.should eq 'Blah'
484
502
  end
485
503
  end
486
504
 
487
- describe "#gt" do
488
- it "checks greater than" do
505
+ describe '#gt' do
506
+ it 'checks greater than' do
489
507
  @results = xpath { |x| x.descendant(:p)[XPath.position() > 2] }
490
- @results[0][:title].should eq "monkey"
491
- @results[1].text.should eq "Blah"
508
+ @results[0][:title].should eq 'monkey'
509
+ @results[1].text.should eq 'Blah'
492
510
  end
493
511
  end
494
512
 
495
- describe "#plus" do
496
- it "adds stuff" do
513
+ describe '#plus' do
514
+ it 'adds stuff' do
497
515
  @results = xpath { |x| x.descendant(:p)[XPath.position().plus(1) == 2] }
498
- @results[0][:id].should eq "fooDiv"
499
- @results[1][:title].should eq "gorilla"
516
+ @results[0][:id].should eq 'fooDiv'
517
+ @results[1][:title].should eq 'gorilla'
500
518
  end
501
519
  end
502
520
 
503
- describe "#minus" do
504
- it "subtracts stuff" do
521
+ describe '#minus' do
522
+ it 'subtracts stuff' do
505
523
  @results = xpath { |x| x.descendant(:p)[XPath.position().minus(1) == 0] }
506
- @results[0][:id].should eq "fooDiv"
507
- @results[1][:title].should eq "gorilla"
524
+ @results[0][:id].should eq 'fooDiv'
525
+ @results[1][:title].should eq 'gorilla'
508
526
  end
509
527
  end
510
528
 
511
- describe "#multiply" do
512
- it "multiplies stuff" do
529
+ describe '#multiply' do
530
+ it 'multiplies stuff' do
513
531
  @results = xpath { |x| x.descendant(:p)[XPath.position() * 3 == 3] }
514
- @results[0][:id].should eq "fooDiv"
515
- @results[1][:title].should eq "gorilla"
532
+ @results[0][:id].should eq 'fooDiv'
533
+ @results[1][:title].should eq 'gorilla'
516
534
  end
517
535
  end
518
536
 
519
- describe "#divide" do
520
- it "divides stuff" do
537
+ describe '#divide' do
538
+ it 'divides stuff' do
521
539
  @results = xpath { |x| x.descendant(:p)[XPath.position() / 2 == 1] }
522
- @results[0].text.should eq "Bax"
523
- @results[1].text.should eq "Bax"
540
+ @results[0].text.should eq 'Bax'
541
+ @results[1].text.should eq 'Bax'
524
542
  end
525
543
  end
526
544
 
527
- describe "#mod" do
528
- it "take modulo" do
545
+ describe '#mod' do
546
+ it 'take modulo' do
529
547
  @results = xpath { |x| x.descendant(:p)[XPath.position() % 2 == 1] }
530
- @results[0].text.should eq "Blah"
531
- @results[1][:title].should eq "monkey"
532
- @results[2][:title].should eq "gorilla"
548
+ @results[0].text.should eq 'Blah'
549
+ @results[1][:title].should eq 'monkey'
550
+ @results[2][:title].should eq 'gorilla'
533
551
  end
534
552
  end
535
553
 
536
- describe "#ancestor" do
537
- it "finds ancestor nodes" do
554
+ describe '#ancestor' do
555
+ it 'finds ancestor nodes' do
538
556
  @results = xpath { |x| x.descendant(:p)[1].ancestor }
539
- @results[0].node_name.should eq "html"
540
- @results[1].node_name.should eq "body"
541
- @results[2][:id].should eq "foo"
557
+ @results[0].node_name.should eq 'html'
558
+ @results[1].node_name.should eq 'body'
559
+ @results[2][:id].should eq 'foo'
542
560
  end
543
561
  end
544
562
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xpath
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Nicklas
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - gem-public_cert.pem
12
- date: 2018-05-26 00:00:00.000000000 Z
12
+ date: 2018-10-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -26,61 +26,61 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  version: '1.8'
28
28
  - !ruby/object:Gem::Dependency
29
- name: rspec
29
+ name: pry
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: '3.0'
34
+ version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - "~>"
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '3.0'
41
+ version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
- name: yard
43
+ name: rake
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: 0.5.8
48
+ version: '0'
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - ">="
54
54
  - !ruby/object:Gem::Version
55
- version: 0.5.8
55
+ version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
- name: rake
57
+ name: rspec
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - ">="
60
+ - - "~>"
61
61
  - !ruby/object:Gem::Version
62
- version: '0'
62
+ version: '3.0'
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - ">="
67
+ - - "~>"
68
68
  - !ruby/object:Gem::Version
69
- version: '0'
69
+ version: '3.0'
70
70
  - !ruby/object:Gem::Dependency
71
- name: pry
71
+ name: yard
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - ">="
75
75
  - !ruby/object:Gem::Version
76
- version: '0'
76
+ version: 0.5.8
77
77
  type: :development
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
- version: '0'
83
+ version: 0.5.8
84
84
  description: XPath is a Ruby DSL for generating XPath expressions
85
85
  email:
86
86
  - jonas.nicklas@gmail.com
@@ -114,7 +114,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '2.2'
117
+ version: '2.3'
118
118
  required_rubygems_version: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - ">="
@@ -122,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
122
  version: '0'
123
123
  requirements: []
124
124
  rubyforge_project:
125
- rubygems_version: 2.7.6
125
+ rubygems_version: 2.7.7
126
126
  signing_key:
127
127
  specification_version: 4
128
128
  summary: Generate XPath expressions from Ruby