domino 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|