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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8e011d8bc68c0c8ae737dca7043ba829256b5cb6
4
- data.tar.gz: 71e4c55f827b3a608e3ecd754b665ee37dc02cbb
3
+ metadata.gz: f53dbf7a0e24f6b9fe707570a47a60a4a6dcdfaa
4
+ data.tar.gz: 783a69aedf7543b0e78c0e64c431ce4165252709
5
5
  SHA512:
6
- metadata.gz: f4f2e5bd103f116d0f0bc2eedd120536abe9bd9e7aee8b3fb3eaaa592a404b376d6977db952bd4152884d286acd5deff2f8cd62becdbd388f5a60d385741a4a3
7
- data.tar.gz: 711b95a1769bb2c17782cb539b76706dbdf1e041444ac3d574c93e6b2e9f83b52de509dfe91e4f91cf2278ce12a0aea02d04c1317bdd634ae76fbd6012d77103
6
+ metadata.gz: 764cc8f1e20079d75ae4c66ec4266884431498a6ddc853926c3d74df5a836b8d11f45085c847880d716d19ef5ee5ef0cda315b19678b4fa633514d82a8847973
7
+ data.tar.gz: 61f0c02649ac0a6f6f19937345ee995751f9eca029baecc6c5febc2a66a4a4b095edeccf1279dd4e075de7461cfcd82b01fe5c4c8f18f8d28a7bbaa2891ad407
data/.gitignore CHANGED
File without changes
data/.travis.yml CHANGED
@@ -3,5 +3,7 @@ rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
5
  - 2.1.2
6
+ - 2.4.3
7
+ - 2.5.0
6
8
  - jruby
7
9
  - ruby
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 modify the value
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
- node.text
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.7.1"
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 ; end
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{|node| node}
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) or raise Capybara::ElementNotFound
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 |node|
93
+ select do |domino|
88
94
  attributes.all? do |key, value|
89
- node.send(key) == value if node.respond_to?(key)
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
- @attributes ||= []
112
+ attribute_definitions.keys
107
113
  end
108
114
 
109
- def callbacks
110
- @callbacks ||= {}
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
- attributes << attribute
130
- callbacks[attribute] = callback
135
+ selector ||= %(.#{attribute.to_s.tr('_', '-')})
131
136
 
132
- selector ||= %{.#{attribute.to_s.gsub("_", "-")}}
137
+ attribute_definitions[attribute] = Attribute.new(attribute, selector, &callback)
133
138
 
134
139
  class_eval %{
135
140
  def #{attribute}
136
- value = attribute(%{#{selector}})
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(%{#{selector}}, value)
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(selector, value)
159
- detect{|node| value === node.attribute(selector) }
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!(&block)
163
- raise Domino::Error.new("You must define a selector") if @selector.nil?
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
- def attribute(selector)
171
- @node.find(selector).text
172
- rescue Capybara::ElementNotFound
173
- nil
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
- @node['id'].nil? ? nil : %{##{@node['id']}}
182
+ node['id'].nil? ? nil : %(##{node['id']})
179
183
  end
180
184
 
181
185
  def attributes
182
- self.class.attributes.inject({}) do |memo, attribute|
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(env)
12
- [200, {"Content-Type" => "text/plain"}, [%{
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 do |text|
66
- text.to_i
67
- end
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(Donna Alice Bob Charlie),
103
- Dom::Person.sort{|a,b|
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
- }.map(&:name)
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("Alice").age
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: "bar")
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: "bar")
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: "bar")
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(Bob Charlie), Dom::Person.where(favorite_color: "Red").map(&:name)
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(Alice), Dom::Person.where(age: 23, favorite_color: 'Blue').map(&:name)
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: "Yellow")
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: "bar")
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.7.1
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: 2015-09-04 00:00:00.000000000 Z
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.4.8
107
+ rubygems_version: 2.6.14
108
108
  signing_key:
109
109
  specification_version: 4
110
110
  summary: View abstraction for integration testing