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 +4 -4
- data/lib/xpath.rb +2 -0
- data/lib/xpath/dsl.rb +38 -29
- data/lib/xpath/expression.rb +3 -1
- data/lib/xpath/literal.rb +2 -0
- data/lib/xpath/renderer.rb +21 -11
- data/lib/xpath/union.rb +4 -2
- data/lib/xpath/version.rb +3 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/union_spec.rb +8 -9
- data/spec/xpath_spec.rb +181 -163
- metadata +20 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a243005210afa835c320ea204ab3105d0b253dfdb905d4ff53c8267e53a23d6d
|
4
|
+
data.tar.gz: 4978108857ddbd50e336926db82b6bb056656861572aa518654cff2dcadb2bc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e17ddd74ff29ac77050bec7cb5ee93f8b1c2386c56ea4390272d998540a69cf8f26f61541de3a583866b4531836d051e722ca93eabc9d52636e722aa78de491b
|
7
|
+
data.tar.gz: c75b155e85156faafa9e3ac63e7c16b7fbc20385b80ada25dcb5c0c680ea06fd06490a5d2e9096d68a51b22b62b06f5ad6b5d7b6e0191396e748bbd7e415d3ce
|
data/lib/xpath.rb
CHANGED
data/lib/xpath/dsl.rb
CHANGED
@@ -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.
|
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
|
-
[
|
105
|
-
[
|
106
|
-
[
|
107
|
-
[
|
108
|
-
[
|
109
|
-
[
|
110
|
-
[
|
111
|
-
[
|
112
|
-
[
|
113
|
-
[
|
114
|
-
[
|
115
|
-
[
|
116
|
-
[
|
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
|
-
|
128
|
-
|
129
|
-
|
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.
|
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,
|
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
|
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)
|
data/lib/xpath/expression.rb
CHANGED
@@ -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
|
data/lib/xpath/literal.rb
CHANGED
data/lib/xpath/renderer.rb
CHANGED
@@ -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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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(
|
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
|
-
|
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(
|
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
|
data/lib/xpath/union.rb
CHANGED
@@ -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
|
data/lib/xpath/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
data/spec/union_spec.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
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
|
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
|
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
|
-
|
data/spec/xpath_spec.rb
CHANGED
@@ -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
|
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
|
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
|
30
|
-
@results[1].text.should eq
|
31
|
+
@results[0].text.should eq 'Blah'
|
32
|
+
@results[1].text.should eq 'Bax'
|
31
33
|
end
|
32
34
|
|
33
|
-
it
|
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
|
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
|
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
|
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
|
58
|
-
@results[1].text.should eq
|
59
|
+
@results[0].text.should eq 'Blah'
|
60
|
+
@results[1].text.should eq 'Bax'
|
59
61
|
end
|
60
62
|
|
61
|
-
it
|
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
|
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
|
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
|
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
|
84
|
+
@results[0].text.should eq 'Blah'
|
83
85
|
end
|
84
86
|
|
85
|
-
it
|
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
|
89
|
+
@results[0][:id].should eq 'fooDiv'
|
88
90
|
end
|
89
91
|
end
|
90
92
|
|
91
93
|
describe '#next_sibling' do
|
92
|
-
it
|
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
|
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
|
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
|
119
|
+
@results[0].text.should eq 'Blah'
|
118
120
|
end
|
119
121
|
|
120
|
-
it
|
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
|
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
|
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
|
154
|
+
@results[0][:id].should eq 'foo'
|
154
155
|
end
|
155
156
|
|
156
|
-
it
|
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
|
162
|
+
@results[0][:id].should eq 'foo'
|
162
163
|
end
|
163
164
|
end
|
164
165
|
|
165
|
-
describe
|
166
|
-
it
|
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
|
171
|
-
@results[1].text.should eq
|
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
|
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
|
183
|
-
@results[1][:id].should eq
|
183
|
+
@results[0][:id].should eq 'foo'
|
184
|
+
@results[1][:id].should eq 'fooDiv'
|
184
185
|
end
|
185
186
|
|
186
|
-
it
|
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
|
192
|
+
@results[0][:id].should eq 'foo'
|
192
193
|
end
|
193
194
|
end
|
194
195
|
|
195
196
|
describe '#ends_with' do
|
196
|
-
it
|
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
|
202
|
-
@results[1][:id].should eq
|
202
|
+
@results[0][:id].should eq 'oof'
|
203
|
+
@results[1][:id].should eq 'viDoof'
|
203
204
|
end
|
204
205
|
|
205
|
-
it
|
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
|
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
|
226
|
-
it
|
227
|
-
@results = xpath { |x| x.descendant(:span).where(x.attr(:id) ==
|
228
|
-
@results.should eq
|
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
|
233
|
-
it
|
234
|
-
@results = xpath { |x| x.descendant(:span).where(x.attr(:id) ==
|
235
|
-
@results.should eq
|
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
|
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
|
249
|
-
@results = xpath { |x| x.descendant(:span).where(x.attr(:id) ==
|
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
|
256
|
-
@results = xpath { |x| x.descendant(:span).where(x.attr(:id) ==
|
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
|
263
|
-
xpath { |x| x.descendant(:div).where(:"@id = 'foo'") }.first[:title].should eq
|
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
|
267
|
-
xpath { |x| x.descendant(:div)[:"@id = 'foo'"] }.first[:title].should eq
|
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
|
271
|
-
XPath.descendant(:div).where(nil).to_s.should eq
|
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
|
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
|
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
|
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
|
291
|
-
xpath { |x| x.descendant(:div).where(x.attr(:id).equals('foo')) }.first[:title].should eq
|
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
|
295
|
-
xpath { |x| x.descendant(:div).where(x.attr(:id) == 'foo') }.first[:title].should eq
|
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
|
301
|
-
xpath { |x| x.descendant(:div).where(x.attr(:id).not_equals('bar')) }.first[:title].should eq
|
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
|
305
|
-
xpath { |x| x.descendant(:div).where(x.attr(:id) != 'bar') }.first[:title].should eq
|
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
|
312
|
-
xpath(:exact) { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should eq
|
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
|
317
|
-
xpath { |x| x.descendant(:div).where(x.attr(:id).is('foo')) }.first[:title].should eq
|
318
|
-
xpath { |x| x.descendant(:div).where(x.attr(:id).is('oo')) }.first[:title].should eq
|
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
|
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
|
329
|
-
@results[1].text.should eq
|
330
|
-
@results[2][:title].should eq
|
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
|
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
|
357
|
+
@results[0][:title].should eq 'monkey'
|
340
358
|
end
|
341
359
|
|
342
|
-
it
|
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
|
364
|
+
@results[0][:title].should eq 'monkey'
|
347
365
|
end
|
348
366
|
end
|
349
367
|
|
350
368
|
describe '#or' do
|
351
|
-
it
|
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
|
356
|
-
@results[1].text.should eq
|
373
|
+
@results[0][:title].should eq 'fooDiv'
|
374
|
+
@results[1].text.should eq 'Blah'
|
357
375
|
end
|
358
376
|
|
359
|
-
it
|
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
|
364
|
-
@results[1].text.should eq
|
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
|
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
|
372
|
-
@results[1][:title].should eq
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
436
|
-
it
|
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
|
439
|
-
@results[1].text.should eq
|
440
|
-
@results[2].text.should eq
|
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
|
445
|
-
it
|
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
|
448
|
-
@results[1].text.should eq
|
465
|
+
@results[0].text.should eq 'Bax'
|
466
|
+
@results[1].text.should eq 'Bax'
|
449
467
|
end
|
450
468
|
end
|
451
469
|
|
452
|
-
describe
|
453
|
-
it
|
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
|
473
|
+
@results[0][:id].should eq 'preference'
|
456
474
|
end
|
457
475
|
end
|
458
476
|
|
459
|
-
describe
|
460
|
-
it
|
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
|
463
|
-
@results[1].text.should eq
|
464
|
-
@results[2][:title].should eq
|
465
|
-
@results[3].text.should eq
|
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
|
470
|
-
it
|
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
|
473
|
-
@results[1][:title].should eq
|
490
|
+
@results[0].text.should eq 'Blah'
|
491
|
+
@results[1][:title].should eq 'gorilla'
|
474
492
|
end
|
475
493
|
end
|
476
494
|
|
477
|
-
describe
|
478
|
-
it
|
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
|
481
|
-
@results[1][:title].should eq
|
482
|
-
@results[2].text.should eq
|
483
|
-
@results[3].text.should eq
|
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
|
488
|
-
it
|
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
|
491
|
-
@results[1].text.should eq
|
508
|
+
@results[0][:title].should eq 'monkey'
|
509
|
+
@results[1].text.should eq 'Blah'
|
492
510
|
end
|
493
511
|
end
|
494
512
|
|
495
|
-
describe
|
496
|
-
it
|
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
|
499
|
-
@results[1][:title].should eq
|
516
|
+
@results[0][:id].should eq 'fooDiv'
|
517
|
+
@results[1][:title].should eq 'gorilla'
|
500
518
|
end
|
501
519
|
end
|
502
520
|
|
503
|
-
describe
|
504
|
-
it
|
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
|
507
|
-
@results[1][:title].should eq
|
524
|
+
@results[0][:id].should eq 'fooDiv'
|
525
|
+
@results[1][:title].should eq 'gorilla'
|
508
526
|
end
|
509
527
|
end
|
510
528
|
|
511
|
-
describe
|
512
|
-
it
|
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
|
515
|
-
@results[1][:title].should eq
|
532
|
+
@results[0][:id].should eq 'fooDiv'
|
533
|
+
@results[1][:title].should eq 'gorilla'
|
516
534
|
end
|
517
535
|
end
|
518
536
|
|
519
|
-
describe
|
520
|
-
it
|
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
|
523
|
-
@results[1].text.should eq
|
540
|
+
@results[0].text.should eq 'Bax'
|
541
|
+
@results[1].text.should eq 'Bax'
|
524
542
|
end
|
525
543
|
end
|
526
544
|
|
527
|
-
describe
|
528
|
-
it
|
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
|
531
|
-
@results[1][:title].should eq
|
532
|
-
@results[2][:title].should eq
|
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
|
537
|
-
it
|
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
|
540
|
-
@results[1].node_name.should eq
|
541
|
-
@results[2][:id].should eq
|
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.
|
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-
|
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:
|
29
|
+
name: pry
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
32
|
+
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
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: '
|
41
|
+
version: '0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
43
|
+
name: rake
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - ">="
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: 0
|
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
|
55
|
+
version: '0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
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:
|
71
|
+
name: yard
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
74
|
- - ">="
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
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:
|
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.
|
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.
|
125
|
+
rubygems_version: 2.7.7
|
126
126
|
signing_key:
|
127
127
|
specification_version: 4
|
128
128
|
summary: Generate XPath expressions from Ruby
|