Skip to content

Commit 5ca4f58

Browse files
authored
Merge pull request #221 from rubycdp/utils
Refactor Ferrum module
2 parents c0d52c0 + c742a89 commit 5ca4f58

21 files changed

+231
-182
lines changed

.rubocop.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,6 @@ Metrics/ModuleLength:
5353
Metrics/PerceivedComplexity:
5454
Max: 14
5555

56+
#require:
57+
# - rubocop-rake
58+
# - rubocop-rspec

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ a block with this page, after which the page is closed.
2626
- `Ferrum::Page#bypass_csp` accepts hash as argument `enabled: true` by default
2727
- `Ferrum::Context#has_target?` -> `Ferrum::Context#target?`
2828
- We now start looking for Chrome first instead of Chromium, the order for checking binaries has changed
29+
- Multiple methods are moved into `Utils`:
30+
- Ferrum.with_attempts -> Ferrum::Utils::Attempt.with_retry
31+
- Ferrum.started -> Ferrum::Utils::ElapsedTime.start
32+
- Ferrum.elapsed_time -> Ferrum::Utils::ElapsedTime.elapsed_time
33+
- Ferrum.monotonic_time -> Ferrum::Utils::ElapsedTime.monotonic_time
34+
- Ferrum.timeout? -> Ferrum::Utils::ElapsedTime.timeout?
35+
- Ferrum.windows? -> Ferrum::Utils::Platform.windows?
36+
- Ferrum.mac? -> Ferrum::Utils::Platform.mac?
37+
- Ferrum.mri? -> Ferrum::Utils::Platform.mri?
2938

3039
## [0.11](https://github.com/rubycdp/ferrum/compare/v0.10.2...v0.11) - (Mar 11, 2021) ##
3140

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ source "https://rubygems.org"
44

55
gem "byebug", "~> 11.0", platforms: %i[mri mingw x64_mingw]
66
gem "rubocop", "~> 1.22"
7+
gem "rubocop-rake", require: false
8+
gem "rubocop-rspec", require: false
79

810
gemspec

ferrum.gemspec

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ Gem::Specification.new do |s|
2222
"bug_tracker_uri" => "https://github.com/rubycdp/ferrum/issues",
2323
"documentation_uri" => "https://github.com/rubycdp/ferrum/blob/master/README.md",
2424
"changelog_uri" => "https://github.com/rubycdp/ferrum/blob/master/CHANGELOG.md",
25-
"source_code_uri" => "https://github.com/rubycdp/ferrum"
25+
"source_code_uri" => "https://github.com/rubycdp/ferrum",
26+
"rubygems_mfa_required" => "true"
2627
}
2728

2829
s.required_ruby_version = ">= 2.6.0"

lib/ferrum.rb

Lines changed: 4 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,161 +1,11 @@
11
# frozen_string_literal: true
22

3-
require "concurrent-ruby"
3+
require "ferrum/utils/platform"
4+
require "ferrum/utils/elapsed_time"
5+
require "ferrum/utils/attempt"
6+
require "ferrum/errors"
47
require "ferrum/browser"
58
require "ferrum/node"
69

710
module Ferrum
8-
class Error < StandardError; end
9-
10-
class NoSuchPageError < Error; end
11-
12-
class NoSuchTargetError < Error; end
13-
14-
class NotImplementedError < Error; end
15-
16-
class StatusError < Error
17-
def initialize(url, message = nil)
18-
super(message || "Request to #{url} failed to reach server, check DNS and server status")
19-
end
20-
end
21-
22-
class PendingConnectionsError < StatusError
23-
attr_reader :pendings
24-
25-
def initialize(url, pendings = [])
26-
@pendings = pendings
27-
28-
message = "Request to #{url} reached server, but there are still pending connections: #{pendings.join(', ')}"
29-
30-
super(url, message)
31-
end
32-
end
33-
34-
class TimeoutError < Error
35-
def message
36-
"Timed out waiting for response. It's possible that this happened " \
37-
"because something took a very long time (for example a page load " \
38-
"was slow). If so, setting the :timeout option to a higher value might " \
39-
"help."
40-
end
41-
end
42-
43-
class ScriptTimeoutError < Error
44-
def message
45-
"Timed out waiting for evaluated script to return a value"
46-
end
47-
end
48-
49-
class ProcessTimeoutError < Error
50-
attr_reader :output
51-
52-
def initialize(timeout, output)
53-
@output = output
54-
super("Browser did not produce websocket url within #{timeout} seconds, try to increase `:process_timeout`. See https://github.com/rubycdp/ferrum#customization")
55-
end
56-
end
57-
58-
class DeadBrowserError < Error
59-
def initialize(message = "Browser is dead or given window is closed")
60-
super
61-
end
62-
end
63-
64-
class NodeMovingError < Error
65-
def initialize(node, prev, current)
66-
@node = node
67-
@prev = prev
68-
@current = current
69-
super(message)
70-
end
71-
72-
def message
73-
"#{@node.inspect} that you're trying to click is moving, hence " \
74-
"we cannot. Previously it was at #{@prev.inspect} but now at " \
75-
"#{@current.inspect}."
76-
end
77-
end
78-
79-
class CoordinatesNotFoundError < Error
80-
def initialize(message = "Could not compute content quads")
81-
super
82-
end
83-
end
84-
85-
class BrowserError < Error
86-
attr_reader :response
87-
88-
def initialize(response)
89-
@response = response
90-
super(response["message"])
91-
end
92-
93-
def code
94-
response["code"]
95-
end
96-
97-
def data
98-
response["data"]
99-
end
100-
end
101-
102-
class NodeNotFoundError < BrowserError; end
103-
104-
class NoExecutionContextError < BrowserError
105-
def initialize(response = nil)
106-
response ||= { "message" => "There's no context available" }
107-
super(response)
108-
end
109-
end
110-
111-
class JavaScriptError < BrowserError
112-
attr_reader :class_name, :message, :stack_trace
113-
114-
def initialize(response, stack_trace = nil)
115-
@class_name, @message = response.values_at("className", "description")
116-
@stack_trace = stack_trace
117-
super(response.merge("message" => @message))
118-
end
119-
end
120-
121-
class << self
122-
def windows?
123-
RbConfig::CONFIG["host_os"] =~ /mingw|mswin|cygwin/
124-
end
125-
126-
def mac?
127-
RbConfig::CONFIG["host_os"] =~ /darwin/
128-
end
129-
130-
def mri?
131-
defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby"
132-
end
133-
134-
def started
135-
@started ||= monotonic_time
136-
end
137-
138-
def elapsed_time(start = nil)
139-
monotonic_time - (start || @started)
140-
end
141-
142-
def monotonic_time
143-
Concurrent.monotonic_time
144-
end
145-
146-
def timeout?(start, timeout)
147-
elapsed_time(start) > timeout
148-
end
149-
150-
def with_attempts(errors:, max:, wait:)
151-
attempts ||= 1
152-
yield
153-
rescue *Array(errors)
154-
raise if attempts >= max
155-
156-
attempts += 1
157-
sleep(wait)
158-
retry
159-
end
160-
end
16111
end

lib/ferrum/browser.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def crash
152152
private
153153

154154
def start
155-
Ferrum.started
155+
Utils::ElapsedTime.start
156156
@process = Process.start(@options)
157157
@client = Client.new(self, @process.ws_url)
158158
@contexts = Contexts.new(self)

lib/ferrum/browser/options/base.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ def except(*keys)
2424
end
2525

2626
def detect_path
27-
if Ferrum.mac?
27+
if Utils::Platform.mac?
2828
self.class::MAC_BIN_PATH.find { |n| File.exist?(n) }
29-
elsif Ferrum.windows?
29+
elsif Utils::Platform.windows?
3030
self.class::WINDOWS_BIN_PATH.find { |path| File.exist?(path) }
3131
else
3232
self.class::LINUX_BIN_PATH.find do |name|

lib/ferrum/browser/process.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ def self.start(*args)
3131

3232
def self.process_killer(pid)
3333
proc do
34-
if Ferrum.windows?
34+
if Utils::Platform.windows?
3535
# Process.kill is unreliable on Windows
3636
::Process.kill("KILL", pid) unless system("taskkill /f /t /pid #{pid} >NUL 2>NUL")
3737
else
3838
::Process.kill("USR1", pid)
39-
start = Ferrum.monotonic_time
39+
start = Utils::ElapsedTime.monotonic_time
4040
while ::Process.wait(pid, ::Process::WNOHANG).nil?
4141
sleep(WAIT_KILLED)
42-
next unless Ferrum.timeout?(start, KILL_TIMEOUT)
42+
next unless Utils::ElapsedTime.timeout?(start, KILL_TIMEOUT)
4343

4444
::Process.kill("KILL", pid)
4545
::Process.wait(pid)
@@ -88,7 +88,7 @@ def start
8888
begin
8989
read_io, write_io = IO.pipe
9090
process_options = { in: File::NULL }
91-
process_options[:pgroup] = true unless Ferrum.windows?
91+
process_options[:pgroup] = true unless Utils::Platform.windows?
9292
process_options[:out] = process_options[:err] = write_io
9393

9494
if @command.xvfb?
@@ -135,10 +135,10 @@ def remove_user_data_dir
135135

136136
def parse_ws_url(read_io, timeout)
137137
output = ""
138-
start = Ferrum.monotonic_time
138+
start = Utils::ElapsedTime.monotonic_time
139139
max_time = start + timeout
140140
regexp = %r{DevTools listening on (ws://.*)}
141-
while (now = Ferrum.monotonic_time) < max_time
141+
while (now = Utils::ElapsedTime.monotonic_time) < max_time
142142
begin
143143
output += read_io.read_nonblock(512)
144144
rescue IO::WaitReadable

lib/ferrum/browser/web_socket.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def on_message(event)
6161
output.sub!(/{"data":"(.*)"}/, %("Set FERRUM_LOGGING_SCREENSHOTS=true to see screenshots in Base64"))
6262
end
6363

64-
@logger&.puts(" ◀ #{Ferrum.elapsed_time} #{output}\n")
64+
@logger&.puts(" ◀ #{Utils::ElapsedTime.elapsed_time} #{output}\n")
6565
end
6666

6767
def on_close(_event)
@@ -74,7 +74,7 @@ def send_message(data)
7474

7575
json = data.to_json
7676
@driver.text(json)
77-
@logger&.puts("\n\n#{Ferrum.elapsed_time} #{json}")
77+
@logger&.puts("\n\n#{Utils::ElapsedTime.elapsed_time} #{json}")
7878
end
7979

8080
def write(data)

0 commit comments

Comments
 (0)