proxy_fetcher 0.10.2 → 0.15.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 +4 -4
- data/CHANGELOG.md +22 -1
- data/Gemfile +8 -5
- data/Rakefile +7 -3
- data/gemfiles/nokogiri.gemfile +8 -6
- data/gemfiles/oga.gemfile +8 -6
- data/lib/proxy_fetcher.rb +46 -35
- data/lib/proxy_fetcher/client/client.rb +10 -3
- data/lib/proxy_fetcher/client/request.rb +4 -4
- data/lib/proxy_fetcher/configuration.rb +24 -19
- data/lib/proxy_fetcher/document.rb +0 -9
- data/lib/proxy_fetcher/document/adapters.rb +1 -1
- data/lib/proxy_fetcher/document/adapters/abstract_adapter.rb +3 -12
- data/lib/proxy_fetcher/document/adapters/nokogiri_adapter.rb +1 -1
- data/lib/proxy_fetcher/document/adapters/oga_adapter.rb +1 -1
- data/lib/proxy_fetcher/document/node.rb +2 -2
- data/lib/proxy_fetcher/exceptions.rb +6 -6
- data/lib/proxy_fetcher/manager.rb +42 -9
- data/lib/proxy_fetcher/providers/base.rb +43 -22
- data/lib/proxy_fetcher/providers/free_proxy_list.rb +9 -10
- data/lib/proxy_fetcher/providers/free_proxy_list_socks.rb +58 -0
- data/lib/proxy_fetcher/providers/free_proxy_list_ssl.rb +7 -15
- data/lib/proxy_fetcher/providers/free_proxy_list_us.rb +54 -0
- data/lib/proxy_fetcher/providers/http_tunnel.rb +11 -19
- data/lib/proxy_fetcher/providers/mtpro.rb +43 -0
- data/lib/proxy_fetcher/providers/proxy_list.rb +8 -16
- data/lib/proxy_fetcher/providers/proxypedia.rb +48 -0
- data/lib/proxy_fetcher/providers/proxyscrape_http.rb +65 -0
- data/lib/proxy_fetcher/providers/proxyscrape_socks4.rb +65 -0
- data/lib/proxy_fetcher/providers/proxyscrape_socks5.rb +65 -0
- data/lib/proxy_fetcher/providers/xroxy.rb +9 -17
- data/lib/proxy_fetcher/proxy.rb +16 -4
- data/lib/proxy_fetcher/utils/http_client.rb +7 -12
- data/lib/proxy_fetcher/utils/proxy_list_validator.rb +3 -1
- data/lib/proxy_fetcher/utils/proxy_validator.rb +21 -9
- data/lib/proxy_fetcher/version.rb +3 -3
- data/proxy_fetcher.gemspec +21 -16
- data/spec/fixtures/proxies.txt +14 -0
- data/spec/proxy_fetcher/client/client_spec.rb +72 -57
- data/spec/proxy_fetcher/configuration_spec.rb +11 -11
- data/spec/proxy_fetcher/document/adapters_spec.rb +8 -8
- data/spec/proxy_fetcher/document/node_spec.rb +4 -4
- data/spec/proxy_fetcher/manager_spec.rb +18 -0
- data/spec/proxy_fetcher/providers/base_spec.rb +9 -9
- data/spec/proxy_fetcher/providers/multiple_providers_spec.rb +4 -4
- data/spec/proxy_fetcher/providers/proxy_classes_spec.rb +28 -0
- data/spec/proxy_fetcher/proxy_spec.rb +14 -14
- data/spec/proxy_fetcher/version_spec.rb +2 -0
- data/spec/spec_helper.rb +10 -10
- data/spec/support/manager_examples.rb +21 -21
- metadata +27 -17
- data/lib/proxy_fetcher/providers/gather_proxy.rb +0 -58
- data/spec/proxy_fetcher/providers/free_proxy_list_spec.rb +0 -13
- data/spec/proxy_fetcher/providers/free_proxy_list_ssl_spec.rb +0 -11
- data/spec/proxy_fetcher/providers/gather_proxy_spec.rb +0 -11
- data/spec/proxy_fetcher/providers/http_tunnel_spec.rb +0 -11
- data/spec/proxy_fetcher/providers/proxy_list_spec.rb +0 -11
- data/spec/proxy_fetcher/providers/xroxy_spec.rb +0 -11
@@ -70,22 +70,17 @@ module ProxyFetcher
|
|
70
70
|
def fetch
|
71
71
|
response = process_http_request
|
72
72
|
response.body.to_s
|
73
|
-
rescue StandardError =>
|
74
|
-
ProxyFetcher.logger.warn("Failed to process request to #{url} (#{
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
def fetch_with_headers
|
79
|
-
process_http_request
|
80
|
-
rescue StandardError => error
|
81
|
-
ProxyFetcher.logger.warn("Failed to process request to #{url} (#{error.message})")
|
82
|
-
HTTP::Response.new(version: '1.1', status: 500, body: '')
|
73
|
+
rescue StandardError => e
|
74
|
+
ProxyFetcher.config.logger.warn("Failed to process request to #{url} (#{e.message})")
|
75
|
+
""
|
83
76
|
end
|
84
77
|
|
85
78
|
protected
|
86
79
|
|
87
80
|
def process_http_request(http_method: method, http_params: params)
|
88
|
-
|
81
|
+
unless HTTP::Request::METHODS.include?(http_method)
|
82
|
+
raise ArgumentError, "'#{http_method}' is a wrong HTTP method name!"
|
83
|
+
end
|
89
84
|
|
90
85
|
http.public_send(
|
91
86
|
http_method.to_sym, url,
|
@@ -101,7 +96,7 @@ module ProxyFetcher
|
|
101
96
|
#
|
102
97
|
def default_headers
|
103
98
|
{
|
104
|
-
|
99
|
+
"User-Agent" => ProxyFetcher.config.user_agent
|
105
100
|
}
|
106
101
|
end
|
107
102
|
end
|
@@ -34,7 +34,9 @@ module ProxyFetcher
|
|
34
34
|
proxy = target_proxies_lock.synchronize { target_proxies.shift }
|
35
35
|
break unless proxy
|
36
36
|
|
37
|
-
|
37
|
+
if proxy.connectable?
|
38
|
+
connectable_proxies_lock.synchronize { connectable_proxies << proxy }
|
39
|
+
end
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
@@ -6,31 +6,43 @@ module ProxyFetcher
|
|
6
6
|
# URL to check if proxy can be used (aka connectable?).
|
7
7
|
class ProxyValidator
|
8
8
|
# Default URL that will be used to check if proxy can be used.
|
9
|
-
URL_TO_CHECK =
|
9
|
+
URL_TO_CHECK = "https://google.com"
|
10
10
|
|
11
11
|
# Short variant to validate proxy.
|
12
12
|
#
|
13
|
-
# @param
|
14
|
-
# @param
|
13
|
+
# @param address [String] proxy address or IP
|
14
|
+
# @param port [String, Integer] proxy port
|
15
15
|
#
|
16
16
|
# @return [Boolean]
|
17
17
|
# true if connection to the server using proxy established, otherwise false
|
18
18
|
#
|
19
|
-
def self.connectable?(
|
20
|
-
new(
|
19
|
+
def self.connectable?(address, port)
|
20
|
+
new(address, port).connectable?
|
21
21
|
end
|
22
22
|
|
23
23
|
# Initialize new ProxyValidator instance
|
24
24
|
#
|
25
|
-
# @param
|
26
|
-
# @param
|
25
|
+
# @param address [String] Proxy address or IP
|
26
|
+
# @param port [String, Integer] Proxy port
|
27
|
+
# @param options [Hash] proxy options
|
28
|
+
# @option username [String] Proxy authentication username
|
29
|
+
# @option password [String] Proxy authentication password
|
30
|
+
# @option headers [Hash] Proxy headers
|
27
31
|
#
|
28
32
|
# @return [ProxyValidator]
|
29
33
|
#
|
30
|
-
def initialize(
|
34
|
+
def initialize(address, port, options: {})
|
31
35
|
timeout = ProxyFetcher.config.proxy_validation_timeout
|
36
|
+
proxy = [address, port.to_i]
|
32
37
|
|
33
|
-
|
38
|
+
if options[:username] && options[:password]
|
39
|
+
proxy << options[:username]
|
40
|
+
proxy << options[:password]
|
41
|
+
end
|
42
|
+
|
43
|
+
proxy << options[:headers].to_h if options[:headers]
|
44
|
+
|
45
|
+
@http = HTTP.follow.via(*proxy).timeout(connect: timeout, read: timeout)
|
34
46
|
end
|
35
47
|
|
36
48
|
# Checks if proxy is connectable (can be used to connect
|
@@ -13,11 +13,11 @@ module ProxyFetcher
|
|
13
13
|
# Major version number
|
14
14
|
MAJOR = 0
|
15
15
|
# Minor version number
|
16
|
-
MINOR =
|
16
|
+
MINOR = 15
|
17
17
|
# Smallest version number
|
18
|
-
TINY =
|
18
|
+
TINY = 0
|
19
19
|
|
20
20
|
# Full version number
|
21
|
-
STRING = [MAJOR, MINOR, TINY].compact.join(
|
21
|
+
STRING = [MAJOR, MINOR, TINY].compact.join(".")
|
22
22
|
end
|
23
23
|
end
|
data/proxy_fetcher.gemspec
CHANGED
@@ -1,25 +1,30 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "lib"))
|
4
|
+
|
5
|
+
require "proxy_fetcher/version"
|
4
6
|
|
5
7
|
Gem::Specification.new do |gem|
|
6
|
-
gem.name =
|
8
|
+
gem.name = "proxy_fetcher"
|
7
9
|
gem.version = ProxyFetcher.gem_version
|
8
|
-
gem.summary =
|
9
|
-
gem.description =
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
gem.
|
10
|
+
gem.summary = "Ruby gem for dealing with proxy lists from different providers"
|
11
|
+
gem.description = <<-TEXT.strip.gsub(/[\s\n]+/, " ")
|
12
|
+
This gem can help your Ruby application to make HTTP(S) requests
|
13
|
+
using proxies by fetching and validating proxy lists from
|
14
|
+
the different providers.
|
15
|
+
TEXT
|
16
|
+
gem.authors = ["Nikita Bulai"]
|
17
|
+
gem.email = "bulajnikita@gmail.com"
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.bindir = "bin"
|
15
20
|
gem.files = `git ls-files`.split($RS) - %w[README.md .travis.yml .rubocop.yml]
|
16
21
|
gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
17
|
-
gem.homepage =
|
18
|
-
gem.license =
|
19
|
-
gem.required_ruby_version =
|
22
|
+
gem.homepage = "http://github.com/nbulaj/proxy_fetcher"
|
23
|
+
gem.license = "MIT"
|
24
|
+
gem.required_ruby_version = ">= 2.3.0"
|
20
25
|
|
21
|
-
gem.add_runtime_dependency
|
26
|
+
gem.add_runtime_dependency "http", ">= 3", "< 5"
|
22
27
|
|
23
|
-
gem.add_development_dependency
|
24
|
-
gem.add_development_dependency
|
28
|
+
gem.add_development_dependency "rake", ">= 12.0"
|
29
|
+
gem.add_development_dependency "rspec", "~> 3.9"
|
25
30
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
139.162.59.9:3128
|
2
|
+
176.62.187.158:56351
|
3
|
+
144.217.22.142:8080
|
4
|
+
176.55.108.21:3128
|
5
|
+
157.225.214.251:3128
|
6
|
+
202.51.49.52:48298
|
7
|
+
104.244.75.26:8080
|
8
|
+
163.172.28.20:80
|
9
|
+
187.56.191.12:3128
|
10
|
+
129.194.12.26:80
|
11
|
+
178.128.39.39:8080
|
12
|
+
181.30.28.15:8080
|
13
|
+
51.181.96.185:8080
|
14
|
+
148.134.10.13
|
@@ -1,19 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "spec_helper"
|
4
|
+
require "json"
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require "evil-proxy"
|
7
|
+
require "evil-proxy/async"
|
8
8
|
|
9
|
-
|
9
|
+
describe ProxyFetcher::Client do
|
10
10
|
before :all do
|
11
11
|
ProxyFetcher.configure do |config|
|
12
12
|
config.provider = :xroxy
|
13
13
|
config.client_timeout = 5
|
14
|
+
config.logger = ProxyFetcher::NullLogger.new
|
14
15
|
end
|
15
16
|
|
16
|
-
|
17
|
+
quiet = ENV.key?("LOG_MITM") ? ENV["LOG_MITM"] == "false" : true
|
18
|
+
|
19
|
+
@server = EvilProxy::MITMProxyServer.new Port: 3128, Quiet: quiet
|
17
20
|
@server.start
|
18
21
|
end
|
19
22
|
|
@@ -21,121 +24,133 @@ xdescribe ProxyFetcher::Client do
|
|
21
24
|
@server.shutdown
|
22
25
|
end
|
23
26
|
|
27
|
+
let(:local_proxy) { ProxyFetcher::Proxy.new(addr: "127.0.0.1", port: 3128, type: "HTTP, HTTPS") }
|
28
|
+
|
24
29
|
# Use local proxy server in order to avoid side effects, non-working proxies, etc
|
25
30
|
before :each do
|
26
|
-
|
27
|
-
ProxyFetcher::
|
28
|
-
allow_any_instance_of(ProxyFetcher::Providers::Base).to receive(:fetch_proxies!).and_return([proxy])
|
31
|
+
ProxyFetcher::Client::ProxiesRegistry.manager.instance_variable_set(:'@proxies', [local_proxy])
|
32
|
+
allow_any_instance_of(ProxyFetcher::Providers::Base).to receive(:fetch_proxies).and_return([local_proxy])
|
29
33
|
end
|
30
34
|
|
31
|
-
context
|
32
|
-
it
|
33
|
-
content = ProxyFetcher::Client.get(
|
35
|
+
context "GET request with the valid proxy" do
|
36
|
+
it "successfully returns page content for HTTP" do
|
37
|
+
content = ProxyFetcher::Client.get("http://httpbin.org/get")
|
34
38
|
|
35
39
|
expect(content).not_to be_empty
|
36
40
|
end
|
37
41
|
|
38
|
-
|
39
|
-
|
42
|
+
# TODO: oh this SSL / MITM proxies ....
|
43
|
+
xit "successfully returns page content for HTTPS" do
|
44
|
+
content = ProxyFetcher::Client.get("https://httpbin.org/get")
|
40
45
|
|
41
46
|
expect(content).not_to be_empty
|
42
47
|
end
|
43
48
|
|
44
|
-
it
|
45
|
-
|
46
|
-
|
47
|
-
proxy = manager.get! until proxy
|
48
|
-
content = ProxyFetcher::Client.get('http://httpbin.org', options: { proxy: proxy })
|
49
|
+
it "successfully returns page content using custom proxy" do
|
50
|
+
content = ProxyFetcher::Client.get("http://httpbin.org/get", options: { proxy: local_proxy })
|
49
51
|
|
50
52
|
expect(content).not_to be_empty
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
54
|
-
context
|
55
|
-
it
|
56
|
+
context "POST request with the valid proxy" do
|
57
|
+
it "successfully returns page content for HTTP" do
|
56
58
|
headers = {
|
57
|
-
|
59
|
+
"X-Proxy-Fetcher-Version" => ProxyFetcher::VERSION::STRING
|
58
60
|
}
|
59
|
-
|
61
|
+
|
62
|
+
content = ProxyFetcher::Client.post(
|
63
|
+
"http://httpbin.org/post",
|
64
|
+
{ param: "value" },
|
65
|
+
headers: headers
|
66
|
+
)
|
60
67
|
|
61
68
|
expect(content).not_to be_empty
|
62
69
|
|
63
70
|
json = JSON.parse(content)
|
64
71
|
|
65
|
-
expect(json[
|
66
|
-
expect(json[
|
72
|
+
expect(json["headers"]["X-Proxy-Fetcher-Version"]).to eq(ProxyFetcher::VERSION::STRING)
|
73
|
+
expect(json["headers"]["User-Agent"]).to eq(ProxyFetcher.config.user_agent)
|
67
74
|
end
|
68
75
|
end
|
69
76
|
|
70
|
-
|
71
|
-
|
72
|
-
|
77
|
+
# TODO: EvilProxy incompatible with latest Ruby/Webrick
|
78
|
+
# @see https://github.com/bbtfr/evil-proxy/issues/10
|
79
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.6")
|
80
|
+
context "PUT request with the valid proxy" do
|
81
|
+
it "successfully returns page content for HTTP" do
|
82
|
+
content = ProxyFetcher::Client.put("http://httpbin.org/put", "param=PutValue")
|
73
83
|
|
74
|
-
|
84
|
+
expect(content).not_to be_empty
|
75
85
|
|
76
|
-
|
86
|
+
json = JSON.parse(content)
|
77
87
|
|
78
|
-
|
88
|
+
expect(json["form"]["param"]).to eq("PutValue")
|
89
|
+
end
|
79
90
|
end
|
80
|
-
end
|
81
91
|
|
82
|
-
|
83
|
-
|
84
|
-
|
92
|
+
context "PATCH request with the valid proxy" do
|
93
|
+
it "successfully returns page content for HTTP" do
|
94
|
+
content = ProxyFetcher::Client.patch("http://httpbin.org/patch", param: "value")
|
85
95
|
|
86
|
-
|
96
|
+
expect(content).not_to be_empty
|
87
97
|
|
88
|
-
|
98
|
+
json = JSON.parse(content)
|
89
99
|
|
90
|
-
|
100
|
+
expect(json["form"]["param"]).to eq("value")
|
101
|
+
end
|
91
102
|
end
|
92
103
|
end
|
93
104
|
|
94
|
-
context
|
95
|
-
it
|
96
|
-
content = ProxyFetcher::Client.delete(
|
105
|
+
context "DELETE request with the valid proxy" do
|
106
|
+
it "successfully returns page content for HTTP" do
|
107
|
+
content = ProxyFetcher::Client.delete("http://httpbin.org/delete")
|
97
108
|
|
98
109
|
expect(content).not_to be_empty
|
99
110
|
end
|
100
111
|
end
|
101
112
|
|
102
|
-
context
|
103
|
-
it
|
104
|
-
content = ProxyFetcher::Client.head(
|
113
|
+
context "HEAD request with the valid proxy" do
|
114
|
+
it "successfully works" do
|
115
|
+
content = ProxyFetcher::Client.head("http://httpbin.org")
|
105
116
|
|
106
117
|
expect(content).to be_empty
|
107
118
|
end
|
108
119
|
end
|
109
120
|
|
110
|
-
context
|
111
|
-
it
|
121
|
+
context "retries" do
|
122
|
+
it "raises an error when reaches max retries limit" do
|
112
123
|
allow(ProxyFetcher::Client::Request).to receive(:execute).and_raise(StandardError)
|
113
124
|
|
114
|
-
expect { ProxyFetcher::Client.get(
|
125
|
+
expect { ProxyFetcher::Client.get("http://httpbin.org", options: { max_retries: 10 }) }
|
126
|
+
.to raise_error(ProxyFetcher::Exceptions::MaximumRetriesReached)
|
115
127
|
end
|
116
128
|
|
117
|
-
|
129
|
+
xit "raises an error when http request returns an error" do
|
118
130
|
allow_any_instance_of(HTTP::Client).to receive(:get).and_return(StandardError.new)
|
119
131
|
|
120
|
-
expect { ProxyFetcher::Client.get(
|
132
|
+
expect { ProxyFetcher::Client.get("http://httpbin.org") }
|
133
|
+
.to raise_error(ProxyFetcher::Exceptions::MaximumRetriesReached)
|
121
134
|
end
|
122
135
|
|
123
|
-
it
|
124
|
-
ProxyFetcher::
|
136
|
+
it "refreshes proxy lists if no proxy found" do
|
137
|
+
allow(ProxyFetcher::Manager.new).to receive(:proxies).and_return([])
|
125
138
|
|
126
|
-
expect { ProxyFetcher::Client.get(
|
139
|
+
expect { ProxyFetcher::Client.get("http://httpbin.org") }
|
140
|
+
.not_to raise_error
|
127
141
|
end
|
128
142
|
end
|
129
143
|
|
130
|
-
|
131
|
-
it
|
132
|
-
content = ProxyFetcher::Client.get(
|
144
|
+
xcontext "redirects" do
|
145
|
+
it "follows redirect when present" do
|
146
|
+
content = ProxyFetcher::Client.get("http://httpbin.org/absolute-redirect/2")
|
133
147
|
|
134
148
|
expect(content).not_to be_empty
|
135
149
|
end
|
136
150
|
|
137
|
-
it
|
138
|
-
expect { ProxyFetcher::Client.get(
|
151
|
+
it "raises an error when reaches max redirects limit" do
|
152
|
+
expect { ProxyFetcher::Client.get("http://httpbin.org/absolute-redirect/11") }
|
153
|
+
.to raise_error(ProxyFetcher::Exceptions::MaximumRedirectsReached)
|
139
154
|
end
|
140
155
|
end
|
141
156
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe ProxyFetcher::Configuration do
|
6
6
|
before { ProxyFetcher.config.reset! }
|
7
7
|
after { ProxyFetcher.config.reset! }
|
8
8
|
|
9
|
-
context
|
10
|
-
it
|
9
|
+
context "custom HTTP client" do
|
10
|
+
it "successfully setups if class has all the required methods" do
|
11
11
|
class MyHTTPClient
|
12
12
|
def self.fetch(url)
|
13
13
|
url
|
@@ -17,7 +17,7 @@ describe ProxyFetcher::Configuration do
|
|
17
17
|
expect { ProxyFetcher.config.http_client = MyHTTPClient }.not_to raise_error
|
18
18
|
end
|
19
19
|
|
20
|
-
it
|
20
|
+
it "failed on setup if required methods are missing" do
|
21
21
|
MyWrongHTTPClient = Class.new
|
22
22
|
|
23
23
|
expect { ProxyFetcher.config.http_client = MyWrongHTTPClient }
|
@@ -25,8 +25,8 @@ describe ProxyFetcher::Configuration do
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
context
|
29
|
-
it
|
28
|
+
context "custom proxy validator" do
|
29
|
+
it "successfully setups if class has all the required methods" do
|
30
30
|
class MyProxyValidator
|
31
31
|
def self.connectable?(*)
|
32
32
|
true
|
@@ -36,7 +36,7 @@ describe ProxyFetcher::Configuration do
|
|
36
36
|
expect { ProxyFetcher.config.proxy_validator = MyProxyValidator }.not_to raise_error
|
37
37
|
end
|
38
38
|
|
39
|
-
it
|
39
|
+
it "failed on setup if required methods are missing" do
|
40
40
|
MyWrongProxyValidator = Class.new
|
41
41
|
|
42
42
|
expect { ProxyFetcher.config.proxy_validator = MyWrongProxyValidator }
|
@@ -44,8 +44,8 @@ describe ProxyFetcher::Configuration do
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
context
|
48
|
-
it
|
47
|
+
context "custom provider" do
|
48
|
+
it "fails on registration if provider class already registered" do
|
49
49
|
expect { ProxyFetcher::Configuration.register_provider(:xroxy, Class.new) }
|
50
50
|
.to raise_error(ProxyFetcher::Exceptions::RegisteredProvider)
|
51
51
|
end
|
@@ -58,13 +58,13 @@ describe ProxyFetcher::Configuration do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
context
|
61
|
+
context "custom HTML parsing adapter" do
|
62
62
|
it "fails if adapter can't be installed" do
|
63
63
|
old_adapter = ProxyFetcher.config.adapter.dup
|
64
64
|
|
65
65
|
class CustomAdapter < ProxyFetcher::Document::AbstractAdapter
|
66
66
|
def self.install_requirements!
|
67
|
-
require
|
67
|
+
require "not_existing_gem"
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|