pincers 0.1.0 → 0.2.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: 9be2262d6757498e82ec195e8e8e5109226df675
4
- data.tar.gz: 73e0e4943ec46e3dcbd35a043dda468bbb1e75f2
3
+ metadata.gz: feda6bb5061f196c604a1dc79dfd32ec4bec842c
4
+ data.tar.gz: 54b99547bdb963def619ef399e39b166de4c6720
5
5
  SHA512:
6
- metadata.gz: a7fcc330eb821333f73e1d9f4989084e5d7a0d161703542725ab606a244ac10305f69430bb3522e1c7cc5d8a1746a8bb974f4d9585170aa27b59822980c9afd5
7
- data.tar.gz: 917e6139161b82a3a817b9fb6deb3d31295e60658e138d9004efcb8712f27f41e691c963fedc200c8de22d12c4d398ef5a0e4f2f1176c9523a68b0605b21ab53
6
+ metadata.gz: acc759a2464e7ec81ad88d75b44824e1f3d7dddeaa68511ce851a7e5bd4d06b5dc2c3410a1f92a362a4789a2d1e1950bf4a7889b15d063a1d12b51204b832da8
7
+ data.tar.gz: 084a161f77fe5e52eec66d84188a98b55dc70d945acdb8b3a5bce34f2ed70e57fba73be3f3768b90abf41fc0fedca87987e76fae05fd8a4177df26fd1cda0b98
@@ -20,10 +20,6 @@ module Pincers::Backend
20
20
  ensure_implementation :document_title
21
21
  end
22
22
 
23
- def document_source
24
- ensure_implementation :document_source
25
- end
26
-
27
23
  def fetch_cookies
28
24
  ensure_implementation :fetch_cookies
29
25
  end
@@ -52,6 +48,10 @@ module Pincers::Backend
52
48
  ensure_implementation :search_by_xpath
53
49
  end
54
50
 
51
+ def extract_element_tag(_element)
52
+ ensure_implementation :extract_element_tag
53
+ end
54
+
55
55
  def extract_element_text(_element)
56
56
  ensure_implementation :extract_element_text
57
57
  end
@@ -68,18 +68,30 @@ module Pincers::Backend
68
68
  ensure_implementation :clear_input
69
69
  end
70
70
 
71
- def fill_input(_element, _value)
72
- ensure_implementation :fill_input
71
+ def set_element_text(_element, _value)
72
+ ensure_implementation :set_element_text
73
+ end
74
+
75
+ def click_on_element(_element)
76
+ ensure_implementation :click_on_element
77
+ end
78
+
79
+ def switch_to_frame(_element)
80
+ ensure_implementation :switch_to_frame
81
+ end
82
+
83
+ def switch_to_top_frame
84
+ ensure_implementation :switch_to_top_frame
73
85
  end
74
86
 
75
- def load_frame_element(_element)
76
- ensure_implementation :load_frame_element
87
+ def switch_to_parent_frame
88
+ ensure_implementation :switch_to_parent_frame
77
89
  end
78
90
 
79
91
  private
80
92
 
81
93
  def ensure_implementation(_name)
82
- raise MissingFeatureError.new _name
94
+ raise Pincers::MissingFeatureError.new _name
83
95
  end
84
96
 
85
97
  end
@@ -4,6 +4,14 @@ module Pincers::Backend
4
4
 
5
5
  class Nokogiri < Base
6
6
 
7
+ def document_root
8
+ [document]
9
+ end
10
+
11
+ def document_title
12
+ document.title
13
+ end
14
+
7
15
  def search_by_css(_element, _selector)
8
16
  _element.css _selector
9
17
  end
@@ -12,16 +20,32 @@ module Pincers::Backend
12
20
  _element.xpath _selector
13
21
  end
14
22
 
23
+ def extract_element_tag(_element)
24
+ _element.name
25
+ end
26
+
15
27
  def extract_element_text(_element)
16
- # _element.text
28
+ _element.content
17
29
  end
18
30
 
19
31
  def extract_element_html(_element)
20
- # _element['outerHTML']
32
+ _element.to_html
21
33
  end
22
34
 
23
35
  def extract_element_attribute(_element, _name)
24
- # _element[_name]
36
+ _name = _name.to_sym
37
+
38
+ value = _element[_name]
39
+ value = checkbox_value_fix _element, value if _name == :value
40
+ value
41
+ end
42
+
43
+ private
44
+
45
+ def checkbox_value_fix(_element, _value)
46
+ if _value.nil? and _element.name.downcase == 'input' and ['checkbox', 'radio'].include? _element[:type].downcase
47
+ 'on'
48
+ else _value end
25
49
  end
26
50
 
27
51
  end
@@ -23,10 +23,6 @@ module Pincers::Backend
23
23
  @driver.title
24
24
  end
25
25
 
26
- def document_source
27
- @driver.page_source
28
- end
29
-
30
26
  def fetch_cookies
31
27
  @driver.manage.all_cookies
32
28
  end
@@ -55,30 +51,43 @@ module Pincers::Backend
55
51
  _element.find_elements xpath: _selector
56
52
  end
57
53
 
58
- def extract_element_text(_element)
54
+ def extract_element_tag(_element)
55
+ _element = ensure_element _element
56
+ _element.tag_name
57
+ end
59
58
 
59
+ def extract_element_text(_element)
60
+ _element = ensure_element _element
60
61
  _element.text
61
62
  end
62
63
 
63
64
  def extract_element_html(_element)
64
- if _element == @driver then @driver.page_source else _element.attribute('outerHTML') end
65
+ return @driver.page_source if _element == @driver
66
+ _element.attribute 'outerHTML'
65
67
  end
66
68
 
67
69
  def extract_element_attribute(_element, _name)
70
+ _element = ensure_element _element
68
71
  _element[_name]
69
72
  end
70
73
 
71
- def clear_input(_element)
74
+ def set_element_text(_element, _value)
75
+ _element = ensure_element _element
72
76
  _element.clear
77
+ _element.send_keys _value
73
78
  end
74
79
 
75
- def fill_input(_element, _value)
76
- _element.send_keys _value
80
+ def click_on_element(_element)
81
+ _element = ensure_element _element
82
+ _element.click
83
+ end
84
+
85
+ def switch_to_frame(_element)
86
+ @driver.switch_to.frame _element
77
87
  end
78
88
 
79
- def load_frame_element(_element)
80
- driver.switch_to.frame _element
81
- self
89
+ def switch_to_top_frame
90
+ @driver.switch_to.default_content
82
91
  end
83
92
 
84
93
  # wait contitions
@@ -103,6 +112,13 @@ module Pincers::Backend
103
112
  not _elements.any? { |e| e.displayed? }
104
113
  end
105
114
 
115
+ private
116
+
117
+ def ensure_element(_element)
118
+ return @driver.find_element tag_name: 'html' if _element == @driver
119
+ _element
120
+ end
121
+
106
122
  end
107
123
 
108
124
  end
@@ -32,16 +32,24 @@ module Pincers::Core
32
32
  wrap_errors { backend.document_title }
33
33
  end
34
34
 
35
- def source
36
- wrap_errors { backend.document_source }
37
- end
38
-
39
35
  def cookies
40
36
  @cookies ||= CookieJar.new backend
41
37
  end
42
38
 
43
- def goto(_url)
44
- wrap_errors { backend.navigate_to _url }
39
+ def goto(_urlOrOptions)
40
+ wrap_errors do
41
+ if _urlOrOptions.is_a? String
42
+ _urlOrOptions = { url: _urlOrOptions }
43
+ end
44
+
45
+ if _urlOrOptions.key? :frame
46
+ goto_frame _urlOrOptions[:frame]
47
+ elsif _urlOrOptions.key? :url
48
+ backend.navigate_to _urlOrOptions[:url]
49
+ else
50
+ raise ArgumentError.new "Must provide a valid target when calling 'goto'"
51
+ end
52
+ end
45
53
  self
46
54
  end
47
55
 
@@ -68,5 +76,22 @@ module Pincers::Core
68
76
  @config[:wait_interval]
69
77
  end
70
78
 
79
+ private
80
+
81
+ def goto_frame(_frame)
82
+ case _frame
83
+ when :top
84
+ backend.switch_to_top_frame
85
+ when :parent
86
+ backend.switch_to_parent_frame
87
+ when String
88
+ backend.switch_to_frame css(_frame).element!
89
+ when SearchContext
90
+ backend.switch_to_frame _frame.element!
91
+ else
92
+ raise ArgumentError.new "Invalid :frame option #{_frame.inspect}"
93
+ end
94
+ end
95
+
71
96
  end
72
97
  end
@@ -1,7 +1,12 @@
1
+ require 'pincers/extension/queries'
2
+ require 'pincers/extension/actions'
3
+
1
4
  module Pincers::Core
2
5
  class SearchContext
3
6
  include Enumerable
4
7
  extend Forwardable
8
+ include Pincers::Extension::Queries
9
+ include Pincers::Extension::Actions
5
10
 
6
11
  attr_accessor :parent, :elements
7
12
 
@@ -51,6 +56,10 @@ module Pincers::Core
51
56
  if elements.first.nil? then nil else wrap_elements [elements.first] end
52
57
  end
53
58
 
59
+ def first!
60
+ first or raise Pincers::EmptySetError.new(self)
61
+ end
62
+
54
63
  def last
55
64
  if elements.last.nil? then nil else wrap_elements [elements.last] end
56
65
  end
@@ -67,16 +76,15 @@ module Pincers::Core
67
76
  end
68
77
  end
69
78
 
70
- def text
79
+ def tag
71
80
  wrap_errors do
72
- backend.extract_element_text element!
81
+ backend.extract_element_tag(element!).downcase
73
82
  end
74
83
  end
75
84
 
76
- def classes
85
+ def text
77
86
  wrap_errors do
78
- class_attr = backend.extract_element_attribute element!, 'class'
79
- (class_attr || '').split(' ')
87
+ backend.extract_element_text element!
80
88
  end
81
89
  end
82
90
 
@@ -88,49 +96,22 @@ module Pincers::Core
88
96
 
89
97
  # Input related
90
98
 
91
- def set(_value)
99
+ def set_text(_value)
92
100
  wrap_errors do
93
- backend.clear_input element!
94
- backend.fill_input element!
101
+ backend.set_element_text element!, _value
95
102
  end
96
103
  end
97
104
 
98
- def select(_value)
99
- # TODO.
100
- end
101
-
102
- # context related
103
-
104
- def enter
105
+ def click
105
106
  wrap_errors do
106
- RootContext.new backend.load_frame_element(element!), root.config
107
+ backend.click_on_element element!
107
108
  end
108
109
  end
109
110
 
110
- # Any methods missing are forwarded to the main element (first)
111
-
112
- def method_missing(_method, *_args, &_block)
113
- wrap_errors do
114
- m = /^(.*)_all$/.match _method.to_s
115
- if m then
116
- return [] if empty?
117
- elements.map { |e| e.send(m[1], *_args, &_block) }
118
- else
119
- element!.send(_method, *_args, &_block)
120
- end
121
- end
122
- end
111
+ # context related
123
112
 
124
- def respond_to?(_method, _include_all=false)
125
- return true if super
126
- m = /^.*_all$/.match _method.to_s
127
- if m then
128
- return true if empty?
129
- elements.first.respond_to? m[1], _include_all
130
- else
131
- return true if empty?
132
- elements.first.respond_to? _method, _include_all
133
- end
113
+ def goto
114
+ root.goto frame: self
134
115
  end
135
116
 
136
117
  private
@@ -0,0 +1,56 @@
1
+ module Pincers::Extension
2
+ module Actions
3
+
4
+ def set(_value=true, _options={})
5
+
6
+ if _value.is_a? Hash
7
+ _options = _value
8
+ _value = true
9
+ end
10
+
11
+ case input_mode
12
+ when :text
13
+ set_text _value.to_s
14
+ when :select
15
+ return set_selected _value, _options
16
+ when :checkbox, :radio
17
+ return set_checked _value
18
+ when :button
19
+ click if _value
20
+ else
21
+ return false
22
+ end
23
+ true
24
+ end
25
+
26
+ private
27
+
28
+ def set_selected(_value, _options)
29
+ click
30
+ option = if _options.key? :by_value then
31
+ find_option_by_value _options.delete(:by_value), _options
32
+ else
33
+ find_option_by_label _value, _options
34
+ end
35
+
36
+ return false if option.nil? or option.selected?
37
+ option.click
38
+ true
39
+ end
40
+
41
+ def set_checked(_value)
42
+ return false if _value == checked?
43
+ click
44
+ true
45
+ end
46
+
47
+ def find_option_by_label(_label, _options)
48
+ css("option", _options).find { |o| o.text == _label }
49
+ end
50
+
51
+ def find_option_by_value(_value, _options)
52
+ css("option", _options).find { |o| o[:value] == _value.to_s }
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,45 @@
1
+ module Pincers::Extension
2
+ module Queries
3
+
4
+ TEXT_INPUTS = ['text', 'email', 'number', 'email', 'color', 'password', 'search', 'tel', 'url']
5
+
6
+ def value
7
+ case input_mode
8
+ when :checkbox, :radio
9
+ if checked? then self[:value] else nil end
10
+ else
11
+ self[:value]
12
+ end
13
+ end
14
+
15
+ [:selected, :checked, :disabled, :required].each do |attr_name|
16
+ define_method "#{attr_name}?" do
17
+ not self[attr_name].nil?
18
+ end
19
+ end
20
+
21
+ def classes
22
+ (self[:class] || '').split(' ')
23
+ end
24
+
25
+ def selected(_options={})
26
+ first!.css('option', _options).select { |opt| opt.selected? }
27
+ end
28
+
29
+ def checked(_options={})
30
+ first!.css('input', _options).select { |opt| opt.checked? }
31
+ end
32
+
33
+ def input_mode
34
+ return :select if tag == 'select'
35
+ return :button if tag == 'button' # TODO: button types
36
+ return :text if tag == 'textarea'
37
+ return nil if tag != 'input'
38
+
39
+ type = (self[:type] || 'text').downcase
40
+ return :text if TEXT_INPUTS.include? type
41
+ type.to_sym
42
+ end
43
+
44
+ end
45
+ end
@@ -1,3 +1,3 @@
1
1
  module Pincers
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pincers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ignacio Baixas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-11 00:00:00.000000000 Z
11
+ date: 2015-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: selenium-webdriver
@@ -178,6 +178,34 @@ dependencies:
178
178
  - - '>='
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rack
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - '>='
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - '>='
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: thin
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - '>='
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - '>='
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
181
209
  description:
182
210
  email:
183
211
  - ignacio@platan.us
@@ -191,6 +219,8 @@ files:
191
219
  - lib/pincers/core/root_context.rb
192
220
  - lib/pincers/core/search_context.rb
193
221
  - lib/pincers/errors.rb
222
+ - lib/pincers/extension/actions.rb
223
+ - lib/pincers/extension/queries.rb
194
224
  - lib/pincers/factory.rb
195
225
  - lib/pincers/support/configuration.rb
196
226
  - lib/pincers/support/cookie_jar.rb