domino 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -0
- data/.travis.yml +2 -0
- data/Gemfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +17 -2
- data/Rakefile +0 -0
- data/domino.gemspec +1 -2
- data/lib/domino.rb +85 -30
- data/test/domino_test.rb +56 -26
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f53dbf7a0e24f6b9fe707570a47a60a4a6dcdfaa
|
4
|
+
data.tar.gz: 783a69aedf7543b0e78c0e64c431ce4165252709
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 764cc8f1e20079d75ae4c66ec4266884431498a6ddc853926c3d74df5a836b8d11f45085c847880d716d19ef5ee5ef0cda315b19678b4fa633514d82a8847973
|
7
|
+
data.tar.gz: 61f0c02649ac0a6f6f19937345ee995751f9eca029baecc6c5febc2a66a4a4b095edeccf1279dd4e075de7461cfcd82b01fe5c4c8f18f8d28a7bbaa2891ad407
|
data/.gitignore
CHANGED
File without changes
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
File without changes
|
data/LICENSE.txt
CHANGED
File without changes
|
data/README.md
CHANGED
@@ -15,7 +15,7 @@ module Dom
|
|
15
15
|
attribute :author_name # selector defaults to .author-name
|
16
16
|
attribute :body, '.post-body' # example of selector override
|
17
17
|
|
18
|
-
# pass a block if you want to
|
18
|
+
# pass a block if you want to convert the value
|
19
19
|
attribute :comments do |text|
|
20
20
|
text.to_i
|
21
21
|
end
|
@@ -23,6 +23,21 @@ module Dom
|
|
23
23
|
attribute :posted_at do |text|
|
24
24
|
Date.parse(text)
|
25
25
|
end
|
26
|
+
|
27
|
+
# Combination selector is a boolean that combines with the root node. Boolean.
|
28
|
+
# You can find a post that also has the .active class.
|
29
|
+
attribute :active, "&.active"
|
30
|
+
|
31
|
+
|
32
|
+
# Combination selector for a data attribute. Finds the value of the data attribute
|
33
|
+
# on the root node. You can convert it with a callback like any other attribute.
|
34
|
+
attribute :rating, "&[data-rating]", &:to_i
|
35
|
+
|
36
|
+
# Combination selector for a data attribute with no value set. Must convert to
|
37
|
+
# boolean in the callback.
|
38
|
+
attribute :blah, "&[data-blah]" do |a|
|
39
|
+
!a.nil?
|
40
|
+
end
|
26
41
|
end
|
27
42
|
end
|
28
43
|
```
|
@@ -71,7 +86,7 @@ module Dom
|
|
71
86
|
selector "#accounts li"
|
72
87
|
# Returns this node text
|
73
88
|
def text
|
74
|
-
|
89
|
+
node.text
|
75
90
|
end
|
76
91
|
end
|
77
92
|
end
|
data/Rakefile
CHANGED
File without changes
|
data/domino.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
Gem::Specification.new do |gem|
|
3
3
|
gem.name = "domino"
|
4
|
-
gem.version = "0.
|
4
|
+
gem.version = "0.8.0"
|
5
5
|
gem.platform = Gem::Platform::RUBY
|
6
6
|
gem.authors = ["Nick Gauthier"]
|
7
7
|
gem.email = ["ngauthier@gmail.com"]
|
@@ -23,4 +23,3 @@ Gem::Specification.new do |gem|
|
|
23
23
|
gem.add_development_dependency('rake')
|
24
24
|
gem.add_development_dependency('simplecov')
|
25
25
|
end
|
26
|
-
|
data/lib/domino.rb
CHANGED
@@ -9,6 +9,12 @@ require 'set'
|
|
9
9
|
# attribute :title # selector defaults to .title
|
10
10
|
# attribute :body, '.post-body' # example of selector override
|
11
11
|
#
|
12
|
+
# # can define attributes on the selected node
|
13
|
+
# attribute :uuid, "&[data-uuid]"
|
14
|
+
#
|
15
|
+
# # can define states based on classes of the selected node
|
16
|
+
# attribute :active, "&.active"
|
17
|
+
#
|
12
18
|
# # accepts blocks as callbacks these are run only if attribute exists
|
13
19
|
# attribute :comments do |text|
|
14
20
|
# text.to_i
|
@@ -39,7 +45,7 @@ class Domino
|
|
39
45
|
extend Capybara::DSL
|
40
46
|
|
41
47
|
# Namespaced Domino::Error
|
42
|
-
class Error < StandardError
|
48
|
+
class Error < StandardError; end
|
43
49
|
|
44
50
|
# Direct access to the capybara node, in case you need
|
45
51
|
# anything special
|
@@ -57,7 +63,7 @@ class Domino
|
|
57
63
|
|
58
64
|
# Get an array of all the Dominos
|
59
65
|
def all
|
60
|
-
map{|
|
66
|
+
map { |domino| domino }
|
61
67
|
end
|
62
68
|
|
63
69
|
# Returns Domino for capybara node matching selector.
|
@@ -79,14 +85,14 @@ class Domino
|
|
79
85
|
#
|
80
86
|
# Raises an error if no matching node is found.
|
81
87
|
def find_by!(attributes)
|
82
|
-
find_by(attributes)
|
88
|
+
find_by(attributes) || raise(Capybara::ElementNotFound)
|
83
89
|
end
|
84
90
|
|
85
91
|
# Returns collection of Dominos for capybara node matching all attributes.
|
86
92
|
def where(attributes)
|
87
|
-
select do |
|
93
|
+
select do |domino|
|
88
94
|
attributes.all? do |key, value|
|
89
|
-
|
95
|
+
domino.send(key) == value if domino.respond_to?(key)
|
90
96
|
end
|
91
97
|
end
|
92
98
|
end
|
@@ -103,11 +109,11 @@ class Domino
|
|
103
109
|
end
|
104
110
|
|
105
111
|
def attributes
|
106
|
-
|
112
|
+
attribute_definitions.keys
|
107
113
|
end
|
108
114
|
|
109
|
-
def
|
110
|
-
@
|
115
|
+
def attribute_definitions
|
116
|
+
@attribute_definitions ||= {}
|
111
117
|
end
|
112
118
|
|
113
119
|
# Define an attribute for this Domino
|
@@ -126,22 +132,16 @@ class Domino
|
|
126
132
|
# Dom::Post.find_by_title("First Post")
|
127
133
|
# Dom::Post.find_by_title(/^First/)
|
128
134
|
def attribute(attribute, selector = nil, &callback)
|
129
|
-
|
130
|
-
callbacks[attribute] = callback
|
135
|
+
selector ||= %(.#{attribute.to_s.tr('_', '-')})
|
131
136
|
|
132
|
-
|
137
|
+
attribute_definitions[attribute] = Attribute.new(attribute, selector, &callback)
|
133
138
|
|
134
139
|
class_eval %{
|
135
140
|
def #{attribute}
|
136
|
-
value
|
137
|
-
if value && self.class.callbacks[:#{attribute}].is_a?(Proc)
|
138
|
-
self.class.callbacks[:#{attribute}].call(value)
|
139
|
-
else
|
140
|
-
value
|
141
|
-
end
|
141
|
+
self.class.attribute_definitions[:#{attribute}].value(node)
|
142
142
|
end
|
143
143
|
def self.find_by_#{attribute}(value)
|
144
|
-
find_by_attribute(
|
144
|
+
find_by_attribute(:#{attribute}, value)
|
145
145
|
end
|
146
146
|
}
|
147
147
|
end
|
@@ -155,39 +155,94 @@ class Domino
|
|
155
155
|
end
|
156
156
|
|
157
157
|
# Internal method for finding nodes by a selector
|
158
|
-
def find_by_attribute(
|
159
|
-
detect
|
158
|
+
def find_by_attribute(attribute, value)
|
159
|
+
detect do |domino|
|
160
|
+
attribute_definitions[attribute].match_value?(domino.node, value)
|
161
|
+
end
|
160
162
|
end
|
161
163
|
|
162
|
-
def require_selector!
|
163
|
-
raise Domino::Error
|
164
|
+
def require_selector!
|
165
|
+
raise Domino::Error, 'You must define a selector' if @selector.nil?
|
164
166
|
end
|
165
167
|
end
|
166
168
|
|
167
|
-
# Get the text of the first dom element matching a selector
|
169
|
+
# Get the text of the first dom element matching a selector:
|
168
170
|
#
|
169
171
|
# Dom::Post.all.first.attribute('.title')
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
172
|
+
#
|
173
|
+
# Or get the value of the attribute of this dom element:
|
174
|
+
#
|
175
|
+
# Dom::Post.all.first.attribute('&[href]')
|
176
|
+
def attribute(selector, &callback)
|
177
|
+
Attribute.new(nil, selector, &callback).value(node)
|
174
178
|
end
|
175
179
|
|
176
180
|
# Dom id for this object.
|
177
181
|
def id
|
178
|
-
|
182
|
+
node['id'].nil? ? nil : %(##{node['id']})
|
179
183
|
end
|
180
184
|
|
181
185
|
def attributes
|
182
|
-
self.class.attributes.
|
186
|
+
self.class.attributes.each_with_object({}) do |attribute, memo|
|
183
187
|
memo[attribute] = send(attribute)
|
184
|
-
memo
|
185
188
|
end
|
186
189
|
end
|
187
190
|
|
188
191
|
private
|
192
|
+
|
189
193
|
# Store the capybara node internally
|
190
194
|
def initialize(node)
|
191
195
|
@node = node
|
192
196
|
end
|
197
|
+
|
198
|
+
class Attribute
|
199
|
+
attr_reader :name, :selector, :callback
|
200
|
+
|
201
|
+
def initialize(name, selector = nil, &callback)
|
202
|
+
@callback = callback
|
203
|
+
@name = name
|
204
|
+
@selector = selector || %(.#{name.to_s.tr('_', '-')})
|
205
|
+
end
|
206
|
+
|
207
|
+
def value(node)
|
208
|
+
val = value_before_typecast(node)
|
209
|
+
|
210
|
+
if val && callback.is_a?(Proc)
|
211
|
+
callback.call(val)
|
212
|
+
else
|
213
|
+
val
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Get the text of the first dom element matching a selector
|
218
|
+
#
|
219
|
+
# Dom::Post.all.first.attribute('.title')
|
220
|
+
def value_before_typecast(node)
|
221
|
+
if combinator?
|
222
|
+
node[node_attribute_key] || node.matches_css?(combinator)
|
223
|
+
else
|
224
|
+
node.find(selector).text
|
225
|
+
end
|
226
|
+
rescue Capybara::ElementNotFound
|
227
|
+
nil
|
228
|
+
end
|
229
|
+
|
230
|
+
def match_value?(node, value)
|
231
|
+
value === value(node)
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def combinator?
|
237
|
+
selector[0] == "&".freeze
|
238
|
+
end
|
239
|
+
|
240
|
+
def combinator
|
241
|
+
@combinator ||= selector.sub(/&/, "") if combinator?
|
242
|
+
end
|
243
|
+
|
244
|
+
def node_attribute_key
|
245
|
+
@node_attribute_key ||= combinator.match(/(?<=\[).+?(?=\])/) { |m| m[0] }
|
246
|
+
end
|
247
|
+
end
|
193
248
|
end
|
data/test/domino_test.rb
CHANGED
@@ -8,33 +8,33 @@ require 'minitest/autorun'
|
|
8
8
|
require 'minitest/mock'
|
9
9
|
|
10
10
|
class TestApplication
|
11
|
-
def call(
|
12
|
-
[200, {
|
11
|
+
def call(_env)
|
12
|
+
[200, { 'Content-Type' => 'text/plain' }, [%(
|
13
13
|
<html>
|
14
14
|
<body>
|
15
15
|
<h1>Here are people and animals</h1>
|
16
16
|
<div id='people'>
|
17
|
-
<div class='person'>
|
17
|
+
<div class='person active' data-rank="1" data-uuid="e94bb2d3-71d2-4efb-abd4-ebc0cb58d19f">
|
18
18
|
<h2 class='name'>Alice</h2>
|
19
19
|
<p class='last-name'>Cooper</p>
|
20
20
|
<p class='bio'>Alice is fun</p>
|
21
21
|
<p class='fav-color'>Blue</p>
|
22
22
|
<p class='age'>23</p>
|
23
23
|
</div>
|
24
|
-
<div class='person'>
|
24
|
+
<div class='person' data-rank="3" data-uuid="05bf319e-8d6a-43c2-be37-2dad8ddbe5af">
|
25
25
|
<h2 class='name'>Bob</h2>
|
26
26
|
<p class='last-name'>Marley</p>
|
27
27
|
<p class='bio'>Bob is smart</p>
|
28
28
|
<p class='fav-color'>Red</p>
|
29
29
|
<p class='age'>52</p>
|
30
30
|
</div>
|
31
|
-
<div class='person'>
|
31
|
+
<div class='person' data-rank="2" data-uuid="4abcdeff-1d36-44a9-a05e-8fc57564d2c4">
|
32
32
|
<h2 class='name'>Charlie</h2>
|
33
33
|
<p class='last-name'>Murphy</p>
|
34
34
|
<p class='bio'>Charlie is wild</p>
|
35
35
|
<p class='fav-color'>Red</p>
|
36
36
|
</div>
|
37
|
-
<div class='person'>
|
37
|
+
<div class='person' data-rank="7" data-blocked data-uuid="2afccde0-5d13-41c7-ab01-7f37fb2fe3ee">
|
38
38
|
<h2 class='name'>Donna</h2>
|
39
39
|
<p class='last-name'>Summer</p>
|
40
40
|
<p class='bio'>Donna is quiet</p>
|
@@ -46,25 +46,27 @@ class TestApplication
|
|
46
46
|
</div>
|
47
47
|
</body>
|
48
48
|
</html>
|
49
|
-
|
49
|
+
)]]
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
Capybara.app = TestApplication.new
|
54
54
|
|
55
|
-
|
56
55
|
class DominoTest < MiniTest::Unit::TestCase
|
57
56
|
include Capybara::DSL
|
58
57
|
module Dom
|
59
58
|
class Person < Domino
|
60
59
|
selector '#people .person'
|
60
|
+
|
61
61
|
attribute :name
|
62
62
|
attribute :last_name
|
63
63
|
attribute :biography, '.bio'
|
64
64
|
attribute :favorite_color, '.fav-color'
|
65
|
-
attribute :age
|
66
|
-
|
67
|
-
|
65
|
+
attribute :age, &:to_i
|
66
|
+
attribute :rank, '&[data-rank]', &:to_i
|
67
|
+
attribute :active, '&.active'
|
68
|
+
attribute :uuid, '&[data-uuid]'
|
69
|
+
attribute(:blocked, '&[data-blocked]') { |a| !a.nil? }
|
68
70
|
end
|
69
71
|
|
70
72
|
class Animal < Domino
|
@@ -95,14 +97,14 @@ class DominoTest < MiniTest::Unit::TestCase
|
|
95
97
|
|
96
98
|
assert_equal 4, Dom::Person.all.size
|
97
99
|
|
98
|
-
red_people = Dom::Person.select{|p| p.favorite_color == 'Red'}
|
100
|
+
red_people = Dom::Person.select { |p| p.favorite_color == 'Red' }
|
99
101
|
assert_equal 2, red_people.count
|
100
102
|
|
101
103
|
assert_equal(
|
102
|
-
%w
|
103
|
-
Dom::Person.sort
|
104
|
+
%w[Donna Alice Bob Charlie],
|
105
|
+
Dom::Person.sort do |a, b|
|
104
106
|
a.favorite_color.to_s <=> b.favorite_color.to_s
|
105
|
-
|
107
|
+
end.map(&:name)
|
106
108
|
)
|
107
109
|
end
|
108
110
|
|
@@ -132,16 +134,20 @@ class DominoTest < MiniTest::Unit::TestCase
|
|
132
134
|
assert_equal 'Charlie', Dom::Person.find_by_biography(/wild/).name
|
133
135
|
end
|
134
136
|
|
137
|
+
def test_find_by_data_combinator_attribute_regex
|
138
|
+
assert_equal 'Charlie', Dom::Person.find_by_uuid(/abcdef/).name
|
139
|
+
end
|
140
|
+
|
135
141
|
def test_node_properties
|
136
142
|
assert_equal 'ACME', Dom::Receipt.first.node['data-store']
|
137
143
|
end
|
138
144
|
|
139
145
|
def test_attributes
|
140
|
-
assert_equal({name: 'Alice', last_name: 'Cooper', biography: 'Alice is fun', favorite_color: 'Blue', age: 23}, Dom::Person.first.attributes)
|
146
|
+
assert_equal({ name: 'Alice', last_name: 'Cooper', biography: 'Alice is fun', favorite_color: 'Blue', age: 23, rank: 1, active: true, uuid: 'e94bb2d3-71d2-4efb-abd4-ebc0cb58d19f', blocked: false }, Dom::Person.first.attributes)
|
141
147
|
end
|
142
148
|
|
143
149
|
def test_callback
|
144
|
-
assert_equal 23, Dom::Person.find_by_name(
|
150
|
+
assert_equal 23, Dom::Person.find_by_name('Alice').age
|
145
151
|
end
|
146
152
|
|
147
153
|
def test_find_bang
|
@@ -165,50 +171,74 @@ class DominoTest < MiniTest::Unit::TestCase
|
|
165
171
|
end
|
166
172
|
|
167
173
|
def test_find_by_with_multiple_attributes
|
168
|
-
assert_equal 'Alice', Dom::Person.find_by(biography: 'Alice is fun', age: 23, favorite_color: 'Blue').name
|
174
|
+
assert_equal 'Alice', Dom::Person.find_by(biography: 'Alice is fun', age: 23, favorite_color: 'Blue', rank: 1).name
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_find_by_without_match
|
178
|
+
assert_nil Dom::Person.find_by(foo: 'bar')
|
169
179
|
end
|
170
180
|
|
171
181
|
def test_find_by_without_selector
|
172
182
|
assert_raises Domino::Error do
|
173
|
-
Dom::NoSelector.find_by(foo:
|
183
|
+
Dom::NoSelector.find_by(foo: 'bar')
|
174
184
|
end
|
175
185
|
end
|
176
186
|
|
187
|
+
def test_find_by_class_combinator_attribute
|
188
|
+
assert_equal 'Alice', Dom::Person.find_by(active: true).name
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_find_by_data_key_combinator_attribute
|
192
|
+
assert_equal 'Donna', Dom::Person.find_by(blocked: true).name
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_find_by_data_combinator_attribute
|
196
|
+
assert_equal 'Charlie', Dom::Person.find_by(rank: 2).name
|
197
|
+
end
|
198
|
+
|
177
199
|
def test_find_by_bang
|
178
200
|
assert_equal 'Alice', Dom::Person.find_by!(biography: 'Alice is fun').name
|
179
201
|
end
|
180
202
|
|
181
203
|
def test_find_by_bang_with_multiple_attributes
|
182
|
-
assert_equal 'Alice', Dom::Person.find_by!(biography: 'Alice is fun', age: 23, favorite_color: 'Blue').name
|
204
|
+
assert_equal 'Alice', Dom::Person.find_by!(biography: 'Alice is fun', age: 23, favorite_color: 'Blue', rank: 1).name
|
183
205
|
end
|
184
206
|
|
185
207
|
def test_find_by_bang_without_selector
|
186
208
|
assert_raises Domino::Error do
|
187
|
-
Dom::NoSelector.find_by(foo:
|
209
|
+
Dom::NoSelector.find_by(foo: 'bar')
|
188
210
|
end
|
189
211
|
end
|
190
212
|
|
191
213
|
def test_find_by_bang_without_match
|
192
214
|
assert_raises Capybara::ElementNotFound do
|
193
|
-
Dom::Person.find_by!(foo:
|
215
|
+
Dom::Person.find_by!(foo: 'bar')
|
194
216
|
end
|
195
217
|
end
|
196
218
|
|
197
219
|
def test_where_with_single_attribute
|
198
|
-
assert_equal %w
|
220
|
+
assert_equal %w[Bob Charlie], Dom::Person.where(favorite_color: 'Red').map(&:name)
|
199
221
|
end
|
200
222
|
|
201
223
|
def test_where_with_multiple_attributes
|
202
|
-
assert_equal %w
|
224
|
+
assert_equal %w[Alice], Dom::Person.where(age: 23, favorite_color: 'Blue').map(&:name)
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_where_with_class_combinator_attribute
|
228
|
+
assert_equal %w[Bob Charlie Donna], Dom::Person.where(active: false).map(&:name)
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_where_with_data_key_combinator_attribute
|
232
|
+
assert_equal %w[Donna], Dom::Person.where(blocked: true).map(&:name)
|
203
233
|
end
|
204
234
|
|
205
235
|
def test_where_without_match
|
206
|
-
assert_equal [], Dom::Person.where(favorite_color:
|
236
|
+
assert_equal [], Dom::Person.where(favorite_color: 'Yellow')
|
207
237
|
end
|
208
238
|
|
209
239
|
def test_where_without_selector
|
210
240
|
assert_raises Domino::Error do
|
211
|
-
Dom::NoSelector.where(foo:
|
241
|
+
Dom::NoSelector.where(foo: 'bar')
|
212
242
|
end
|
213
243
|
end
|
214
244
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: domino
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Gauthier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
104
|
version: '0'
|
105
105
|
requirements: []
|
106
106
|
rubyforge_project:
|
107
|
-
rubygems_version: 2.
|
107
|
+
rubygems_version: 2.6.14
|
108
108
|
signing_key:
|
109
109
|
specification_version: 4
|
110
110
|
summary: View abstraction for integration testing
|