unobtainium 0.3.5 → 0.4.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: 869c9481a4c19f67aad597d81ea044008012a2a3
4
- data.tar.gz: 61af815e9e9ec60a432966efd2b0c7348848341f
3
+ metadata.gz: 97948bc83a14acdbe6c71e330e66e907d2a19fe7
4
+ data.tar.gz: 33ad8b54a05cd91a90935896378bdba28d9f12cb
5
5
  SHA512:
6
- metadata.gz: 1e1309efacab5bd98dcb243eba59f3c8327537d5006449d73ed68e3d78e2112936386ac4f2bb635fa9e9d636389cfc4123ac79a7a2feebb3c0b52247d654d100
7
- data.tar.gz: e7a91f3b0a399159d691bed04a0648967cdd16835041c2aec8e4dfa454c5a66e3f3cfb8bee7db273a1cc49bab2b06274f99ba7b6a08ecd87b228adf2b7484ae5
6
+ metadata.gz: 63da85ce1551f33687e11cbb1d59577303907797e8c0cf1a935d692d9922cfb8cf8ace0f30bdd4badc5f97245cc5449127f734952865e3121bc0c58f60266987
7
+ data.tar.gz: a737bd06d28b979976cd56ac4bd82ab7f918b21d32b6a84a036bb0b1706e9a6103580fa0acef97ce60533d161d5eb45fd77515df3c8e99e84438278b639954e8
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- unobtainium (0.3.5)
4
+ unobtainium (0.4.0)
5
5
  sys-proctable (~> 1.0)
6
6
 
7
7
  GEM
@@ -79,7 +79,7 @@ GEM
79
79
  simplecov-html (0.10.0)
80
80
  sys-proctable (1.0.0)
81
81
  tomlrb (1.2.1)
82
- unicode-display_width (1.0.3)
82
+ unicode-display_width (1.0.5)
83
83
  websocket (1.2.3)
84
84
  yard (0.8.7.6)
85
85
 
@@ -88,7 +88,7 @@ PLATFORMS
88
88
 
89
89
  DEPENDENCIES
90
90
  appium_lib
91
- bundler (~> 1.11)
91
+ bundler (~> 1.12)
92
92
  codeclimate-test-reporter
93
93
  cucumber
94
94
  phantomjs
@@ -101,4 +101,4 @@ DEPENDENCIES
101
101
  yard (~> 0.8)
102
102
 
103
103
  BUNDLED WITH
104
- 1.11.2
104
+ 1.12.1
data/README.md CHANGED
@@ -79,9 +79,20 @@ The configuration file knows two configuration variables:
79
79
  See the documentation on [configuration features](docs/CONFIGURATION.md) for
80
80
  details.
81
81
 
82
- ## Development
82
+ # Development
83
83
 
84
84
  - [driver development](docs/DRIVERS.md)
85
+ - [driver module development](docs/DRIVER_MODULES.md)
86
+
87
+ # Additional Drivers
88
+
89
+ - [unobtainium-nokogiri](https://github.com/jfinkhaeuser/unobtainium-nokogiri) is
90
+ a nokogiri-based driver for entirely browserless access to XML and HTML files
91
+ and pages.
92
+ - [unobtainium-faraday](https://github.com/jfinkhaeuser/unobtainium-faraday) is
93
+ a faraday-based driver for dealing with RESTish APIs.
94
+ - [unobtainium-kramdown](https://github.com/jfinkhaeuser/unobtainium-kramdown) is
95
+ a faraday-based driver for dealing with Markdown structured text.
85
96
 
86
97
  # Credits
87
98
  This gem is inspired by [LapisLazuli](https://github.com/spriteCloud/lapis-lazuli),
@@ -0,0 +1,66 @@
1
+ # Driver Modules
2
+
3
+ Driver modules are a way for extending drivers from other gems. It really is
4
+ little more than a glorified version of Ruby's `extend` mechanism, but fairly
5
+ convenient.
6
+
7
+ Suppose you're using any of the built-in drivers with the Selenium API. That
8
+ API is fairly verbose when it comes to e.g. handling waiting for an element to
9
+ appear. You have to create a `Wait` object and use it to loop over `#find_element`
10
+ until a timeout occurs or the latter returns an element.
11
+
12
+ Much simpler to just have a `#wait` method, no?
13
+
14
+ ```ruby
15
+ module WaitModule
16
+ def wait
17
+ # some clever implementation
18
+ end # wait
19
+ end # module WaitModule
20
+ ```
21
+
22
+ You can just extend the driver that unobtainium returns, of course:
23
+
24
+ ```ruby
25
+ drv = driver(:firefox)
26
+ drv.extend(WaitModule)
27
+ ```
28
+
29
+ However, you will have to do this for every driver you instanciate. So let's
30
+ simplify this a bit.
31
+
32
+ ## Module Registration
33
+
34
+ Instead of having to extend every driver yourself, unobtainium allows you to
35
+ register your `WaitModule` with the `Driver` class, and unobtainium takes care
36
+ of the extension for you:
37
+
38
+ ```ruby
39
+ ::Unobtainium::Driver.register_module(WaitModule, __FILE__)
40
+ drv = driver(:firefox)
41
+ drv.respond_to?(:wait) # => true
42
+ ```
43
+
44
+ ## Module Matching
45
+
46
+ The only problem with the above is that our hypothetical `#wait` function relies
47
+ heavily on the driver behaving like Selenium, having e.g. a `#find_element`
48
+ function. So unobtainium also allows your module implementation to decide whether
49
+ it wants to extend a particular driver instance or not.
50
+
51
+ ```ruby
52
+ module WaitModule
53
+ class << self
54
+ def matches?(impl)
55
+ # Only extend drivers with (at least) a `#find_element` method.
56
+ impl.respond_to?(:find_element)
57
+ end
58
+ end # class << self
59
+
60
+ def wait
61
+ # some clever implementation
62
+ end # wait
63
+ end # module WaitModule
64
+ ```
65
+
66
+ In fact, `#matches?` is a mandatory method for module implementations.
@@ -70,6 +70,41 @@ module Unobtainium
70
70
  @@drivers[klass] = fpath
71
71
  end
72
72
 
73
+ ##
74
+ # Add a new driver module. The first parameter is the class itself, the
75
+ # second should be a file path pointing to the file where the class is
76
+ # defined. You would typically pass `__FILE__` for the second parameter.
77
+ #
78
+ # Driver modules must implement the class methods listed in `MODULE_METHODS`.
79
+ #
80
+ # @param klass (Class) Driver implementation class to register.
81
+ # @param path (String) Implementation path of the driver class.
82
+ def register_module(klass, path)
83
+ # We need to deal with absolute paths only
84
+ fpath = File.absolute_path(path)
85
+
86
+ # Figure out if the class implements all the methods we need; we're not
87
+ # checking for anything else.
88
+ klass_methods = klass.methods - klass.instance_methods - Object.methods
89
+
90
+ if MODULE_METHODS - klass_methods != []
91
+ raise LoadError, "Driver module #{klass.name} is not implementing all "\
92
+ "of the class methods #{MODULE_METHODS}, aborting!"
93
+ end
94
+
95
+ # The second question is whether the same class is already known, or
96
+ # whether a class with the same name but under a different location is
97
+ # known.
98
+ if @@modules.include?(klass) and @@modules[klass] != fpath
99
+ raise LoadError, "Driver module #{klass.name} is duplicated in file "\
100
+ "'#{fpath}'; previous definition is here: "\
101
+ "'#{@@modules[klass]}'"
102
+ end
103
+
104
+ # If all of that was ok, we can register the implementation.
105
+ @@modules[klass] = fpath
106
+ end
107
+
73
108
  private :new
74
109
 
75
110
  ##
@@ -174,8 +209,8 @@ module Unobtainium
174
209
 
175
210
  ##
176
211
  # Map any missing method to the driver implementation
177
- def respond_to?(meth)
178
- if not @impl.nil? and @impl.respond_to?(meth)
212
+ def respond_to_missing?(meth, include_private = false)
213
+ if not @impl.nil? and @impl.respond_to?(meth, include_private)
179
214
  return true
180
215
  end
181
216
  return super
@@ -205,12 +240,20 @@ module Unobtainium
205
240
 
206
241
  # Great, instanciate!
207
242
  @impl = driver_klass.create(@label, @options)
243
+
244
+ # Now also extend this implementation with all the modues that match
245
+ @@modules.each do |klass, _|
246
+ if klass.matches?(@impl)
247
+ @impl.extend(klass)
248
+ end
249
+ end
208
250
  end
209
251
 
210
252
  # Class variables have their place, rubocop... still, err on the strict
211
253
  # side and just skip this check here.
212
254
  # rubocop:disable Style/ClassVars
213
255
  @@drivers = {}
256
+ @@modules = {}
214
257
  # rubocop:enable Style/ClassVars
215
258
 
216
259
  # Methods that drivers must implement
@@ -219,5 +262,10 @@ module Unobtainium
219
262
  :ensure_preconditions,
220
263
  :create
221
264
  ].freeze
265
+
266
+ # Methods that driver modules must implement
267
+ MODULE_METHODS = [
268
+ :matches?
269
+ ].freeze
222
270
  end # class Driver
223
271
  end # module Unobtainium
@@ -154,8 +154,8 @@ module Unobtainium
154
154
 
155
155
  ##
156
156
  # Map any missing method to the Hash implementation
157
- def respond_to?(meth)
158
- if not @data.nil? and @data.respond_to?(meth)
157
+ def respond_to_missing?(meth, include_private = false)
158
+ if not @data.nil? and @data.respond_to?(meth, include_private)
159
159
  return true
160
160
  end
161
161
  return super
@@ -8,5 +8,5 @@
8
8
  #
9
9
  module Unobtainium
10
10
  # The current release version
11
- VERSION = "0.3.5".freeze
11
+ VERSION = "0.4.0".freeze
12
12
  end
@@ -5,6 +5,33 @@ require_relative './mock_driver.rb'
5
5
  class FakeDriver
6
6
  end # class FakeDriver
7
7
 
8
+ module TestModule
9
+ class << self
10
+ def matches?(_)
11
+ # Always match!
12
+ true
13
+ end
14
+ end # class << self
15
+
16
+ def my_module_func
17
+ end
18
+ end # module TestModule
19
+
20
+ module NonMatchingTestModule
21
+ class << self
22
+ def matches?(_)
23
+ # Never match!
24
+ false
25
+ end
26
+ end # class << self
27
+
28
+ def does_not_exist
29
+ end
30
+ end # module NonMatchingTestModule
31
+
32
+ module FakeModule
33
+ end # module FakeModule
34
+
8
35
  describe ::Unobtainium::Driver do
9
36
  before :each do
10
37
  ::Unobtainium::Driver.register_implementation(MockDriver, "mock_driver.rb")
@@ -18,7 +45,8 @@ describe ::Unobtainium::Driver do
18
45
 
19
46
  it "refuses to register the same driver twice from different locations" do
20
47
  expect do
21
- ::Unobtainium::Driver.register_implementation(MockDriver, __FILE__)
48
+ ::Unobtainium::Driver.register_implementation(MockDriver, __FILE__ + '1')
49
+ ::Unobtainium::Driver.register_implementation(MockDriver, __FILE__ + '2')
22
50
  end.to raise_error(LoadError)
23
51
  end
24
52
 
@@ -62,4 +90,46 @@ describe ::Unobtainium::Driver do
62
90
  drv = ::Unobtainium::Driver.create(:mock, foo: 42)
63
91
  expect(drv.passed_options).to eql foo: 42
64
92
  end
93
+
94
+ describe 'modules' do
95
+ it 'will register a module' do
96
+ expect do
97
+ ::Unobtainium::Driver.register_module(TestModule, __FILE__)
98
+ end.not_to raise_error(LoadError)
99
+ end
100
+
101
+ it 'refuses to register the same module twice' do
102
+ expect do
103
+ ::Unobtainium::Driver.register_module(TestModule, __FILE__ + '1')
104
+ ::Unobtainium::Driver.register_module(TestModule, __FILE__ + '2')
105
+ end.to raise_error(LoadError)
106
+ end
107
+
108
+ it 'refuses to register a module with the wrong interface' do
109
+ expect do
110
+ ::Unobtainium::Driver.register_module(FakeModule, __FILE__)
111
+ end.to raise_error(LoadError)
112
+ end
113
+
114
+ it 'extends a driver with a registered module' do
115
+ expect do
116
+ ::Unobtainium::Driver.register_module(TestModule, __FILE__)
117
+ end.not_to raise_error(LoadError)
118
+
119
+ drv = ::Unobtainium::Driver.create(:mock)
120
+
121
+ expect(drv.respond_to?(:my_module_func)).to be_truthy
122
+ end
123
+
124
+ it 'does not extend a driver with a non-matching module' do
125
+ expect do
126
+ ::Unobtainium::Driver.register_module(TestModule, __FILE__)
127
+ ::Unobtainium::Driver.register_module(NonMatchingTestModule, __FILE__)
128
+ end.not_to raise_error(LoadError)
129
+
130
+ drv = ::Unobtainium::Driver.create(:mock)
131
+
132
+ expect(drv.respond_to?(:does_not_exist)).to be_falsy
133
+ end
134
+ end
65
135
  end
@@ -42,7 +42,7 @@ Gem::Specification.new do |spec|
42
42
  spec.requirements = "Either or all of 'selenium-webdriver', 'appium_lib', "\
43
43
  "'phantomjs'"
44
44
 
45
- spec.add_development_dependency "bundler", "~> 1.11"
45
+ spec.add_development_dependency "bundler", "~> 1.12"
46
46
  spec.add_development_dependency "rubocop", "~> 0.39"
47
47
  spec.add_development_dependency "rake", "~> 11.1"
48
48
  spec.add_development_dependency "rspec", "~> 3.4"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unobtainium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jens Finkhaeuser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-27 00:00:00.000000000 Z
11
+ date: 2016-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.11'
19
+ version: '1.12'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.11'
26
+ version: '1.12'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rubocop
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -186,6 +186,7 @@ files:
186
186
  - config/config.yml
187
187
  - docs/CONFIGURATION.md
188
188
  - docs/DRIVERS.md
189
+ - docs/DRIVER_MODULES.md
189
190
  - features/step_definitions/steps.rb
190
191
  - features/support/env.rb
191
192
  - features/world.feature