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 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