site-inspector 3.0.0 → 3.1.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: b994e74251bb7b1be968d5bbad80273ee3ffea24
4
- data.tar.gz: e104a5856e1710233df4da02b234935e56910f3b
3
+ metadata.gz: 56a9e64300435fa494e8ae17ca710b46238bcffd
4
+ data.tar.gz: 1e552e430d8f1fea10eba7d873e1ae17aab00415
5
5
  SHA512:
6
- metadata.gz: c68e92c9e4c7b82aa7f19fb56f625f0656104b026ef81ede02b8f9dff90b430fc1af16062bb0fa8d337ad53f410ee563c127de9c594a3b47ce4a93723b668b90
7
- data.tar.gz: 2e07f88d11a2c116289bfeb3e9050ad59b7314523aedeb45cf7d4b4042912c31e2ac4e80828ed27a272cec8952726ed02735c2af4022821255d3685c38478c61
6
+ metadata.gz: 96eaaa8846783ef2b9dfe5b76e84ebd3c160139c425c69edc25761828690b2d508770aa842e234cbb63e9f6ecaa8bb7ffc7b2121a9449d934928938a9a9ec637
7
+ data.tar.gz: b3b4d86a6b6ead26b17eb380b27a5da37afd645c582b94b53860eb1948e28c8cf6baec1c088ace2a53ebdb4e755a316bb635236b9b46c36cb60f1012581c5500
@@ -24,7 +24,10 @@ class SiteInspector
24
24
  def pa11y?
25
25
  !!(Cliver.detect('pa11y'))
26
26
  end
27
- alias_method :enabled?, :pa11y?
27
+
28
+ def enabled?
29
+ @@enabled && pa11y?
30
+ end
28
31
  end
29
32
 
30
33
  def level
@@ -33,12 +33,21 @@ class SiteInspector
33
33
  self.class.name
34
34
  end
35
35
 
36
- def self.name
37
- self.to_s.split('::').last.downcase.to_sym
38
- end
36
+ class << self
37
+
38
+ @@enabled = true
39
+
40
+ def name
41
+ self.to_s.split('::').last.downcase.to_sym
42
+ end
43
+
44
+ def enabled?
45
+ !!(@@enabled)
46
+ end
39
47
 
40
- def self.enabled?
41
- true
48
+ def enabled=(value)
49
+ @@enabled = !!(value)
50
+ end
42
51
  end
43
52
  end
44
53
  end
@@ -6,6 +6,12 @@ class SiteInspector
6
6
  endpoint.up? && endpoint.request(path: path, followlocation: true).success?
7
7
  end
8
8
 
9
+ # The default Check#response method is from a HEAD request
10
+ # The content check has a special response which includes the body from a GET request
11
+ def response
12
+ @response ||= endpoint.request(:method => :get)
13
+ end
14
+
9
15
  def document
10
16
  require 'nokogiri'
11
17
  @doc ||= Nokogiri::HTML response.body if response
@@ -1,6 +1,7 @@
1
1
  class SiteInspector
2
2
  class Endpoint
3
3
  class Dns < Check
4
+ class LocalhostError < StandardError; end
4
5
 
5
6
  def self.resolver
6
7
  require "dnsruby"
@@ -55,6 +56,10 @@ class SiteInspector
55
56
  end
56
57
  end
57
58
 
59
+ def localhost?
60
+ ip == '127.0.0.1'
61
+ end
62
+
58
63
  def ip
59
64
  require 'resolv'
60
65
  @ip ||= Resolv.getaddress host
@@ -80,6 +85,7 @@ class SiteInspector
80
85
  end
81
86
 
82
87
  def to_h
88
+ return { :error => LocalhostError } if localhost?
83
89
  {
84
90
  :dnssec => dnssec?,
85
91
  :ipv6 => ipv6?,
@@ -21,6 +21,7 @@ class SiteInspector
21
21
  return cms unless cms.nil?
22
22
  return :expression_engine if endpoint.cookies.any? { |c| c.keys.first =~ /^exp_/ }
23
23
  return :php if endpoint.cookies["PHPSESSID"]
24
+ return :coldfusion if endpoint.cookies["CFID"] && endpoint.cookies["CFTOKEN"]
24
25
  return :cowboy if endpoint.headers.server.to_s.downcase == "cowboy"
25
26
  nil
26
27
  end
@@ -14,16 +14,19 @@ class SiteInspector
14
14
 
15
15
  def endpoints
16
16
  @endpoints ||= [
17
- Endpoint.new("https://#{host}"),
18
- Endpoint.new("https://www.#{host}"),
19
- Endpoint.new("http://#{host}"),
20
- Endpoint.new("http://www.#{host}")
17
+ Endpoint.new("https://#{host}", :domain => self),
18
+ Endpoint.new("https://www.#{host}", :domain => self),
19
+ Endpoint.new("http://#{host}", :domain => self),
20
+ Endpoint.new("http://www.#{host}", :domain => self)
21
21
  ]
22
22
  end
23
23
 
24
24
  def canonical_endpoint
25
- @canonical_endpoint ||= endpoints.find do |e|
26
- e.https? == canonically_https? && e.www? == canonically_www?
25
+ @canonical_endpoint ||= begin
26
+ prefetch
27
+ endpoints.find do |e|
28
+ e.https? == canonically_https? && e.www? == canonically_www?
29
+ end
27
30
  end
28
31
  end
29
32
 
@@ -10,15 +10,21 @@ class SiteInspector
10
10
  # Because each of the four endpoints could potentially respond differently
11
11
  # We must evaluate all four to make certain determination
12
12
  class Endpoint
13
- attr_accessor :host, :uri
13
+ attr_accessor :host, :uri, :domain
14
14
 
15
15
  # Initatiate a new Endpoint object
16
16
  #
17
17
  # endpoint - (string) the endpoint to query (e.g., `https://example.com`)
18
- def initialize(host)
18
+ # options - A hash of options
19
+ # domain - the parent domain object, if passed, facilitates caching of redirects
20
+ def initialize(host, options={})
19
21
  @uri = Addressable::URI.parse(host.downcase)
22
+ # The root URL always has an implict path of "/", even if not requested
23
+ # Make it explicit to facilitate caching and prevent a potential redirect
24
+ @uri.path = "/"
20
25
  @host = uri.host.sub(/^www\./, "")
21
26
  @checks = {}
27
+ @domain = options[:domain]
22
28
  end
23
29
 
24
30
  def www?
@@ -92,7 +98,7 @@ class SiteInspector
92
98
  return if redirect.host == host && redirect.scheme == scheme
93
99
 
94
100
  # Init a new endpoint representing the redirect
95
- Endpoint.new(redirect.to_s)
101
+ find_or_create_by_uri(redirect.to_s)
96
102
  end
97
103
  end
98
104
 
@@ -104,6 +110,11 @@ class SiteInspector
104
110
  # What's the effective URL of a request to this domain?
105
111
  def resolves_to
106
112
  return self unless redirect?
113
+
114
+ # If the redirect doesn't return a 30x response code, return the redirected endpoint
115
+ # Otherwise, we'll need to go down the rabbit hole and see how deep it goes
116
+ return redirect unless redirect.redirect?
117
+
107
118
  @resolves_to ||= begin
108
119
  response = request(:followlocation => true)
109
120
 
@@ -118,7 +129,7 @@ class SiteInspector
118
129
  url = response.effective_url
119
130
  end
120
131
 
121
- Endpoint.new(url)
132
+ find_or_create_by_uri(url)
122
133
  end
123
134
  end
124
135
 
@@ -161,7 +172,7 @@ class SiteInspector
161
172
  checks = SiteInspector::Endpoint.checks.select { |c| options.keys.include?(c.name) }
162
173
  checks = SiteInspector::Endpoint.checks if checks.empty?
163
174
 
164
- checks.each do |check|
175
+ Parallel.each(checks, :in_threads => 4) do |check|
165
176
  hash[check.name] = self.send(check.name).to_h
166
177
  end
167
178
 
@@ -193,5 +204,16 @@ class SiteInspector
193
204
  def hydra
194
205
  SiteInspector.hydra
195
206
  end
207
+
208
+ # In the event that a redirect is to one of the domain's four endpoints,
209
+ # Try to return the existing endpoint, rather than create a new one
210
+ def find_or_create_by_uri(uri)
211
+ uri = Addressable::URI.parse(uri.downcase)
212
+ if domain && cached_endpoint = domain.endpoints.find { |e| e.uri.to_s == uri.to_s }
213
+ cached_endpoint
214
+ else
215
+ Endpoint.new(uri.to_s)
216
+ end
217
+ end
196
218
  end
197
219
  end
@@ -1,3 +1,3 @@
1
1
  class SiteInspector
2
- VERSION = "3.0.0"
2
+ VERSION = "3.1.0"
3
3
  end
@@ -2,6 +2,7 @@ require 'open-uri'
2
2
  require 'addressable/uri'
3
3
  require 'public_suffix'
4
4
  require 'typhoeus'
5
+ require 'parallel'
5
6
  require 'cliver'
6
7
  require 'cgi'
7
8
 
@@ -49,17 +50,25 @@ class SiteInspector
49
50
  :followlocation => false,
50
51
  :timeout => SiteInspector.timeout,
51
52
  :accept_encoding => "gzip",
53
+ :method => :head,
52
54
  :headers => {
53
55
  "User-Agent" => "Mozilla/5.0 (compatible; SiteInspector/#{SiteInspector::VERSION}; +https://github.com/benbalter/site-inspector)"
54
56
  }
55
57
  }
56
58
  end
57
59
 
60
+ # Returns a thread-safe, memoized hydra instance
58
61
  def hydra
59
- @hydra ||= Typhoeus::Hydra.new(max_concurrency: 4)
62
+ Typhoeus::Hydra.hydra
60
63
  end
61
64
  end
62
65
  end
63
66
 
67
+ if ENV["DEBUG"]
68
+ Ethon.logger = Logger.new(STDOUT);
69
+ Ethon.logger.level = Logger::DEBUG
70
+ Typhoeus::Config.verbose = true
71
+ end
72
+
64
73
  Typhoeus::Config.memoize = true
65
74
  Typhoeus::Config.cache = SiteInspector.cache
data/script/console CHANGED
@@ -1 +1,3 @@
1
- bundle exec pry -r ./lib/site-inspector.rb
1
+ #! /bin/sh
2
+
3
+ DEBUG=1 bundle exec pry -r './lib/site-inspector'
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
26
26
  s.add_dependency("mercenary", "~> 0.3")
27
27
  s.add_dependency("colorator", "~> 0.1")
28
28
  s.add_dependency("cliver", "~> 0.3")
29
+ s.add_dependency("parallel", "~> 1.6")
29
30
  s.add_development_dependency("pry", "~> 0.10")
30
31
  s.add_development_dependency( "rake", "~> 10.4" )
31
32
  s.add_development_dependency( "rspec", "~> 3.2")
@@ -44,7 +44,7 @@ describe SiteInspector::Endpoint::Accessibility do
44
44
  context "with pa11y installed" do
45
45
 
46
46
  before do
47
- stub_request(:get, "http://example.com/").to_return(:status => 200 )
47
+ stub_request(:head, "http://example.com/").to_return(:status => 200 )
48
48
  end
49
49
 
50
50
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe SiteInspector::Endpoint::Check do
4
4
 
5
5
  subject do
6
- stub_request(:get, "http://example.com/").to_return(:status => 200)
6
+ stub_request(:head, "http://example.com/").to_return(:status => 200)
7
7
  endpoint = SiteInspector::Endpoint.new("http://example.com")
8
8
  SiteInspector::Endpoint::Check.new(endpoint)
9
9
  end
@@ -32,7 +32,10 @@ describe SiteInspector::Endpoint::Check do
32
32
  expect(SiteInspector::Endpoint::Check.name).to eql(:check)
33
33
  end
34
34
 
35
- it "enables the check" do
35
+ it "enables and disables the check" do
36
36
  expect(SiteInspector::Endpoint::Check.enabled?).to eql(true)
37
+ SiteInspector::Endpoint::Check.enabled = false
38
+ expect(SiteInspector::Endpoint::Check.enabled?).to eql(false)
39
+ SiteInspector::Endpoint::Check.enabled = true
37
40
  end
38
41
  end
@@ -14,6 +14,8 @@ describe SiteInspector::Endpoint::Content do
14
14
 
15
15
  stub_request(:get, "http://example.com/").
16
16
  to_return(:status => 200, :body => body )
17
+ stub_request(:head, "http://example.com/").
18
+ to_return(:status => 200 )
17
19
  endpoint = SiteInspector::Endpoint.new("http://example.com")
18
20
  SiteInspector::Endpoint::Content.new(endpoint)
19
21
  end
@@ -32,62 +34,62 @@ describe SiteInspector::Endpoint::Content do
32
34
  end
33
35
 
34
36
  it "knows when robots.txt exists" do
35
- stub_request(:get, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
37
+ stub_request(:head, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
36
38
 
37
- stub_request(:get, "http://example.com/robots.txt").
39
+ stub_request(:head, "http://example.com/robots.txt").
38
40
  to_return(:status => 200)
39
41
  expect(subject.robots_txt?).to eql(true)
40
42
  end
41
43
 
42
44
  it "knows when robots.txt doesn't exist" do
43
- stub_request(:get, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
45
+ stub_request(:head, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
44
46
 
45
- stub_request(:get, "http://example.com/robots.txt").
47
+ stub_request(:head, "http://example.com/robots.txt").
46
48
  to_return(:status => 404)
47
49
  expect(subject.robots_txt?).to eql(false)
48
50
  end
49
51
 
50
52
  it "knows when sitemap.xml exists" do
51
- stub_request(:get, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
53
+ stub_request(:head, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
52
54
 
53
- stub_request(:get, "http://example.com/sitemap.xml").
55
+ stub_request(:head, "http://example.com/sitemap.xml").
54
56
  to_return(:status => 200)
55
57
  expect(subject.sitemap_xml?).to eql(true)
56
58
  end
57
59
 
58
60
  it "knows when sitemap.xml exists" do
59
- stub_request(:get, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
61
+ stub_request(:head, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
60
62
 
61
- stub_request(:get, "http://example.com/sitemap.xml").
63
+ stub_request(:head, "http://example.com/sitemap.xml").
62
64
  to_return(:status => 404)
63
65
  expect(subject.sitemap_xml?).to eql(false)
64
66
  end
65
67
 
66
68
  it "knows when humans.txt exists" do
67
- stub_request(:get, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
69
+ stub_request(:head, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
68
70
 
69
- stub_request(:get, "http://example.com/humans.txt").
71
+ stub_request(:head, "http://example.com/humans.txt").
70
72
  to_return(:status => 200)
71
73
  expect(subject.humans_txt?).to eql(true)
72
74
  end
73
75
 
74
76
  it "knows when humans.txt doesn't exist" do
75
- stub_request(:get, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
77
+ stub_request(:head, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 404)
76
78
 
77
- stub_request(:get, "http://example.com/humans.txt").
79
+ stub_request(:head, "http://example.com/humans.txt").
78
80
  to_return(:status => 200)
79
81
  expect(subject.humans_txt?).to eql(true)
80
82
  end
81
83
 
82
84
  context "404s" do
83
85
  it "knows when an endpoint returns a proper 404" do
84
- stub_request(:get, /http\:\/\/example.com\/.*/).
86
+ stub_request(:head, /http\:\/\/example.com\/.*/).
85
87
  to_return(:status => 404)
86
88
  expect(subject.proper_404s?).to eql(true)
87
89
  end
88
90
 
89
91
  it "knows when an endpoint doesn't return a proper 404" do
90
- stub_request(:get, /http\:\/\/example.com\/[a-z0-9]{32}/i).
92
+ stub_request(:head, /http\:\/\/example.com\/[a-z0-9]{32}/i).
91
93
  to_return(:status => 200)
92
94
  expect(subject.proper_404s?).to eql(false)
93
95
  end
@@ -99,8 +101,8 @@ describe SiteInspector::Endpoint::Content do
99
101
  end
100
102
 
101
103
  it "doesn't say something exists when there are no 404s" do
102
- stub_request(:get, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 200)
103
- stub_request(:get, "http://example.com/humans.txt").to_return(:status => 200)
104
+ stub_request(:head, /http\:\/\/example.com\/[a-z0-9]{32}/i).to_return(:status => 200)
105
+ stub_request(:head, "http://example.com/humans.txt").to_return(:status => 200)
104
106
  expect(subject.humans_txt?).to eql(nil)
105
107
  end
106
108
  end
@@ -4,7 +4,7 @@ describe SiteInspector::Endpoint::Cookies do
4
4
 
5
5
  context "without cookies" do
6
6
  subject do
7
- stub_request(:get, "http://example.com/").
7
+ stub_request(:head, "http://example.com/").
8
8
  to_return(:status => 200, :body => "" )
9
9
  endpoint = SiteInspector::Endpoint.new("http://example.com")
10
10
  SiteInspector::Endpoint::Cookies.new(endpoint)
@@ -33,7 +33,7 @@ describe SiteInspector::Endpoint::Cookies do
33
33
  )
34
34
  ].map { |c| c.to_s }
35
35
 
36
- stub_request(:get, "http://example.com/").
36
+ stub_request(:head, "http://example.com/").
37
37
  to_return(:status => 200, :body => "", :headers => { "set-cookie" => cookies })
38
38
  endpoint = SiteInspector::Endpoint.new("http://example.com")
39
39
  SiteInspector::Endpoint::Cookies.new(endpoint)
@@ -59,7 +59,7 @@ describe SiteInspector::Endpoint::Cookies do
59
59
  "foo=bar; domain=example.com; path=/; secure; HttpOnly",
60
60
  "foo2=bar2; domain=example.com; path=/"
61
61
  ]
62
- stub_request(:get, "http://example.com/").
62
+ stub_request(:head, "http://example.com/").
63
63
  to_return(:status => 200, :body => "", :headers => { "set-cookie" => cookies })
64
64
  endpoint = SiteInspector::Endpoint.new("http://example.com")
65
65
  SiteInspector::Endpoint::Cookies.new(endpoint)
@@ -4,7 +4,7 @@ require 'dnsruby'
4
4
  describe SiteInspector::Endpoint::Dns do
5
5
 
6
6
  subject do
7
- stub_request(:get, "http://github.com/").to_return(:status => 200)
7
+ stub_request(:head, "http://github.com/").to_return(:status => 200)
8
8
  endpoint = SiteInspector::Endpoint.new("http://github.com")
9
9
  SiteInspector::Endpoint::Dns.new(endpoint)
10
10
  end
@@ -81,6 +81,10 @@ describe SiteInspector::Endpoint::Dns do
81
81
  expect(subject.ipv6?).to eql(true)
82
82
  end
83
83
 
84
+ it "knows it's not a localhost address" do
85
+ expect(subject.localhost?).to eql(false)
86
+ end
87
+
84
88
  context "hostname detection" do
85
89
  it "lists cnames" do
86
90
  records = []
@@ -164,4 +168,20 @@ describe SiteInspector::Endpoint::Dns do
164
168
  end
165
169
  end
166
170
  end
171
+
172
+ context "localhost" do
173
+
174
+ before do
175
+ allow(subject).to receive(:ip) { "127.0.0.1" }
176
+ end
177
+
178
+ it "knows it's a localhost address" do
179
+ expect(subject.localhost?).to eql(true)
180
+ end
181
+
182
+ it "returns a LocalhostError" do
183
+ expect(subject.to_h).to eql({:error => SiteInspector::Endpoint::Dns::LocalhostError})
184
+ end
185
+
186
+ end
167
187
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe SiteInspector::Endpoint::Headers do
4
4
 
5
5
  subject do
6
- stub_request(:get, "http://example.com/").
6
+ stub_request(:head, "http://example.com/").
7
7
  to_return(:status => 200, :headers => { :foo => "bar" } )
8
8
  endpoint = SiteInspector::Endpoint.new("http://example.com")
9
9
  SiteInspector::Endpoint::Headers.new(endpoint)
@@ -4,7 +4,7 @@ describe SiteInspector::Endpoint::Hsts do
4
4
 
5
5
  subject do
6
6
  headers = { "strict-transport-security" => "max-age=31536000; includeSubDomains;" }
7
- stub_request(:get, "http://example.com/").
7
+ stub_request(:head, "http://example.com/").
8
8
  to_return(:status => 200, :headers => headers )
9
9
  endpoint = SiteInspector::Endpoint.new("http://example.com")
10
10
  SiteInspector::Endpoint::Hsts.new(endpoint)
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe SiteInspector::Endpoint::Https do
4
4
 
5
5
  subject do
6
- stub_request(:get, "https://example.com/").
6
+ stub_request(:head, "https://example.com/").
7
7
  to_return(:status => 200 )
8
8
  endpoint = SiteInspector::Endpoint.new("https://example.com")
9
9
  allow(endpoint.response).to receive(:return_code) { :ok }
@@ -23,7 +23,10 @@ describe SiteInspector::Endpoint::Sniffer do
23
23
  ].map { |c| c.to_s }
24
24
 
25
25
  stub_request(:get, "http://example.com/").
26
- to_return(:status => 200, :body => "", :headers => { "set-cookie" => cookies } )
26
+ to_return(:status => 200, :body => "" )
27
+
28
+ stub_request(:head, "http://example.com/").
29
+ to_return(:status => 200, :headers => { "set-cookie" => cookies } )
27
30
  end
28
31
 
29
32
  context "stubbed body" do
@@ -50,6 +53,9 @@ describe SiteInspector::Endpoint::Sniffer do
50
53
 
51
54
  stub_request(:get, "http://example.com/").
52
55
  to_return(:status => 200, :body => body )
56
+
57
+ stub_request(:head, "http://example.com/").
58
+ to_return(:status => 200)
53
59
  endpoint = SiteInspector::Endpoint.new("http://example.com")
54
60
  SiteInspector::Endpoint::Sniffer.new(endpoint)
55
61
  end
@@ -105,10 +111,39 @@ describe SiteInspector::Endpoint::Sniffer do
105
111
 
106
112
  it "detects cowboy" do
107
113
  stub_request(:get, "http://example.com/").
108
- to_return(:status => 200, :body => "", :headers => { "server" => "Cowboy" } )
114
+ to_return(:status => 200, :body => "" )
115
+
116
+ stub_request(:head, "http://example.com/").
117
+ to_return(:status => 200, :headers => { "server" => "Cowboy" } )
109
118
 
110
119
  expect(subject.framework).to eql(:cowboy)
111
120
  expect(subject.open_source?).to eql(true)
112
121
  end
122
+
123
+ it "detects ColdFusion" do
124
+ cookies = [
125
+ CGI::Cookie::new(
126
+ "name" => "CFID",
127
+ "value" => "1234",
128
+ "domain" => "example.com",
129
+ "path" => "/"
130
+ ),
131
+ CGI::Cookie::new(
132
+ "name" => "CFTOKEN",
133
+ "value" => "5678",
134
+ "domain" => "example.com",
135
+ "path" => "/"
136
+ )
137
+ ].map { |c| c.to_s }
138
+
139
+ stub_request(:get, "http://example.com/").
140
+ to_return(:status => 200, :body => "" )
141
+
142
+ stub_request(:head, "http://example.com/").
143
+ to_return(:status => 200, :headers => { "set-cookie" => cookies } )
144
+
145
+ expect(subject.framework).to eql(:coldfusion)
146
+ expect(subject.open_source?).to eql(false)
147
+ end
113
148
  end
114
149
  end
@@ -45,19 +45,19 @@ describe SiteInspector::Domain do
45
45
  it "generates the endpoints" do
46
46
  endpoints = subject.endpoints
47
47
  expect(endpoints.count).to eql(4)
48
- expect(endpoints[0].to_s).to eql("https://example.com")
49
- expect(endpoints[1].to_s).to eql("https://www.example.com")
50
- expect(endpoints[2].to_s).to eql("http://example.com")
51
- expect(endpoints[3].to_s).to eql("http://www.example.com")
48
+ expect(endpoints[0].to_s).to eql("https://example.com/")
49
+ expect(endpoints[1].to_s).to eql("https://www.example.com/")
50
+ expect(endpoints[2].to_s).to eql("http://example.com/")
51
+ expect(endpoints[3].to_s).to eql("http://www.example.com/")
52
52
  end
53
53
  end
54
54
 
55
55
  it "knows the canonical domain" do
56
- stub_request(:get, "https://example.com/").to_return(:status => 500)
57
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
58
- stub_request(:get, "http://www.example.com/").to_return(:status => 200)
59
- stub_request(:get, "http://example.com/").to_return(:status => 200)
60
- expect(subject.canonical_endpoint.to_s).to eql("http://example.com")
56
+ stub_request(:head, "https://example.com/").to_return(:status => 500)
57
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
58
+ stub_request(:head, "http://www.example.com/").to_return(:status => 200)
59
+ stub_request(:head, "http://example.com/").to_return(:status => 200)
60
+ expect(subject.canonical_endpoint.to_s).to eql("http://example.com/")
61
61
  end
62
62
 
63
63
  it "knows if a domain is a government domain" do
@@ -75,7 +75,7 @@ describe SiteInspector::Domain do
75
75
  end
76
76
  end
77
77
 
78
- stub_request(:get, "http://www.example.com/").to_return(:status => 200)
78
+ stub_request(:head, "http://www.example.com/").to_return(:status => 200)
79
79
 
80
80
  expect(subject.up?).to eql(true)
81
81
  end
@@ -91,19 +91,19 @@ describe SiteInspector::Domain do
91
91
 
92
92
  context "up" do
93
93
  it "considers a domain up if at least one endpoint is up" do
94
- stub_request(:get, "https://example.com/").to_return(:status => 500)
95
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
96
- stub_request(:get, "http://example.com/").to_return(:status => 500)
97
- stub_request(:get, "http://www.example.com/").to_return(:status => 200)
94
+ stub_request(:head, "https://example.com/").to_return(:status => 500)
95
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
96
+ stub_request(:head, "http://example.com/").to_return(:status => 500)
97
+ stub_request(:head, "http://www.example.com/").to_return(:status => 200)
98
98
 
99
99
  expect(subject.up?).to eql(true)
100
100
  end
101
101
 
102
102
  it "doesn't consider a domain up if all endpoints are down" do
103
- stub_request(:get, "https://example.com/").to_return(:status => 500)
104
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
105
- stub_request(:get, "http://example.com/").to_return(:status => 500)
106
- stub_request(:get, "http://www.example.com/").to_return(:status => 500)
103
+ stub_request(:head, "https://example.com/").to_return(:status => 500)
104
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
105
+ stub_request(:head, "http://example.com/").to_return(:status => 500)
106
+ stub_request(:head, "http://www.example.com/").to_return(:status => 500)
107
107
 
108
108
  expect(subject.up?).to eql(false)
109
109
  end
@@ -111,19 +111,19 @@ describe SiteInspector::Domain do
111
111
 
112
112
  context "www" do
113
113
  it "considers a site www when at least one endpoint is www" do
114
- stub_request(:get, "https://example.com/").to_return(:status => 200)
115
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
116
- stub_request(:get, "http://example.com/").to_return(:status => 500)
117
- stub_request(:get, "http://www.example.com/").to_return(:status => 200)
114
+ stub_request(:head, "https://example.com/").to_return(:status => 200)
115
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
116
+ stub_request(:head, "http://example.com/").to_return(:status => 500)
117
+ stub_request(:head, "http://www.example.com/").to_return(:status => 200)
118
118
 
119
119
  expect(subject.www?).to eql(true)
120
120
  end
121
121
 
122
122
  it "doesn't consider a site www when no endpoint is www" do
123
- stub_request(:get, "https://example.com/").to_return(:status => 200)
124
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
125
- stub_request(:get, "http://example.com/").to_return(:status => 200)
126
- stub_request(:get, "http://www.example.com/").to_return(:status => 500)
123
+ stub_request(:head, "https://example.com/").to_return(:status => 200)
124
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
125
+ stub_request(:head, "http://example.com/").to_return(:status => 200)
126
+ stub_request(:head, "http://www.example.com/").to_return(:status => 500)
127
127
 
128
128
  expect(subject.www?).to eql(false)
129
129
  end
@@ -131,19 +131,19 @@ describe SiteInspector::Domain do
131
131
 
132
132
  context "root" do
133
133
  it "considers a domain root if you can connect without www" do
134
- stub_request(:get, "https://example.com/").to_return(:status => 200)
135
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
136
- stub_request(:get, "http://example.com/").to_return(:status => 500)
137
- stub_request(:get, "http://www.example.com/").to_return(:status => 500)
134
+ stub_request(:head, "https://example.com/").to_return(:status => 200)
135
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
136
+ stub_request(:head, "http://example.com/").to_return(:status => 500)
137
+ stub_request(:head, "http://www.example.com/").to_return(:status => 500)
138
138
 
139
139
  expect(subject.root?).to eql(true)
140
140
  end
141
141
 
142
142
  it "doesn't call a www-only domain root" do
143
- stub_request(:get, "https://example.com/").to_return(:status => 500)
144
- stub_request(:get, "https://www.example.com/").to_return(:status => 200)
145
- stub_request(:get, "http://example.com/").to_return(:status => 500)
146
- stub_request(:get, "http://www.example.com/").to_return(:status => 200)
143
+ stub_request(:head, "https://example.com/").to_return(:status => 500)
144
+ stub_request(:head, "https://www.example.com/").to_return(:status => 200)
145
+ stub_request(:head, "http://example.com/").to_return(:status => 500)
146
+ stub_request(:head, "http://www.example.com/").to_return(:status => 200)
147
147
 
148
148
  expect(subject.root?).to eql(false)
149
149
  end
@@ -151,38 +151,38 @@ describe SiteInspector::Domain do
151
151
 
152
152
  context "https" do
153
153
  it "knows when a domain supports https" do
154
- stub_request(:get, "https://example.com/").to_return(:status => 200)
155
- stub_request(:get, "https://www.example.com/").to_return(:status => 200)
156
- stub_request(:get, "http://example.com/").to_return(:status => 200)
157
- stub_request(:get, "http://www.example.com/").to_return(:status => 200)
154
+ stub_request(:head, "https://example.com/").to_return(:status => 200)
155
+ stub_request(:head, "https://www.example.com/").to_return(:status => 200)
156
+ stub_request(:head, "http://example.com/").to_return(:status => 200)
157
+ stub_request(:head, "http://www.example.com/").to_return(:status => 200)
158
158
  allow(subject.endpoints.first.https).to receive(:valid?) { true }
159
159
 
160
160
  expect(subject.https?).to eql(true)
161
161
  end
162
162
 
163
163
  it "knows when a domain doesn't support https" do
164
- stub_request(:get, "https://example.com/").to_return(:status => 500)
165
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
166
- stub_request(:get, "http://example.com/").to_return(:status => 200)
167
- stub_request(:get, "http://www.example.com/").to_return(:status => 200)
164
+ stub_request(:head, "https://example.com/").to_return(:status => 500)
165
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
166
+ stub_request(:head, "http://example.com/").to_return(:status => 200)
167
+ stub_request(:head, "http://www.example.com/").to_return(:status => 200)
168
168
 
169
169
  expect(subject.https?).to eql(false)
170
170
  end
171
171
 
172
172
  it "considers HTTPS inforced when no http endpoint responds" do
173
- stub_request(:get, "https://example.com/").to_return(:status => 200)
174
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
175
- stub_request(:get, "http://example.com/").to_return(:status => 500)
176
- stub_request(:get, "http://www.example.com/").to_return(:status => 500)
173
+ stub_request(:head, "https://example.com/").to_return(:status => 200)
174
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
175
+ stub_request(:head, "http://example.com/").to_return(:status => 500)
176
+ stub_request(:head, "http://www.example.com/").to_return(:status => 500)
177
177
 
178
178
  #expect(subject.enforces_https?).to eql(true)
179
179
  end
180
180
 
181
181
  it "doesn't consider HTTPS inforced when an http endpoint responds" do
182
- stub_request(:get, "https://example.com/").to_return(:status => 200)
183
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
184
- stub_request(:get, "http://example.com/").to_return(:status => 500)
185
- stub_request(:get, "http://www.example.com/").to_return(:status => 200)
182
+ stub_request(:head, "https://example.com/").to_return(:status => 200)
183
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
184
+ stub_request(:head, "http://example.com/").to_return(:status => 500)
185
+ stub_request(:head, "http://www.example.com/").to_return(:status => 200)
186
186
 
187
187
  expect(subject.enforces_https?).to eql(false)
188
188
  end
@@ -199,20 +199,20 @@ describe SiteInspector::Domain do
199
199
  context "canonical" do
200
200
  context "www" do
201
201
  it "detects a domain as canonically www when root is down" do
202
- stub_request(:get, "https://example.com/").to_return(:status => 500)
203
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
204
- stub_request(:get, "http://example.com/").to_return(:status => 500)
205
- stub_request(:get, "http://www.example.com/").to_return(:status => 200)
202
+ stub_request(:head, "https://example.com/").to_return(:status => 500)
203
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
204
+ stub_request(:head, "http://example.com/").to_return(:status => 500)
205
+ stub_request(:head, "http://www.example.com/").to_return(:status => 200)
206
206
 
207
207
  expect(subject.canonically_www?).to eql(true)
208
208
  end
209
209
 
210
210
  it "detects a domain as canonically www when root redirects" do
211
- stub_request(:get, "https://example.com/").to_return(:status => 500)
212
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
213
- stub_request(:get, "http://example.com/").
211
+ stub_request(:head, "https://example.com/").to_return(:status => 500)
212
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
213
+ stub_request(:head, "http://example.com/").
214
214
  to_return(:status => 301, :headers => { :location => "http://www.example.com" } )
215
- stub_request(:get, "http://www.example.com/").to_return(:status => 200)
215
+ stub_request(:head, "http://www.example.com/").to_return(:status => 200)
216
216
 
217
217
  expect(subject.canonically_www?).to eql(true)
218
218
  end
@@ -220,21 +220,21 @@ describe SiteInspector::Domain do
220
220
 
221
221
  context "https" do
222
222
  it "detects a domain as canonically https when http is down" do
223
- stub_request(:get, "https://example.com/").to_return(:status => 200)
224
- stub_request(:get, "https://www.example.com/").to_return(:status => 200)
225
- stub_request(:get, "http://example.com/").to_return(:status => 500)
226
- stub_request(:get, "http://www.example.com/").to_return(:status => 500)
223
+ stub_request(:head, "https://example.com/").to_return(:status => 200)
224
+ stub_request(:head, "https://www.example.com/").to_return(:status => 200)
225
+ stub_request(:head, "http://example.com/").to_return(:status => 500)
226
+ stub_request(:head, "http://www.example.com/").to_return(:status => 500)
227
227
  allow(subject.endpoints.first.https).to receive(:valid?) { true }
228
228
 
229
229
  expect(subject.canonically_https?).to eql(true)
230
230
  end
231
231
 
232
232
  it "detects a domain as canonically https when http redirect" do
233
- stub_request(:get, "https://example.com/").to_return(:status => 200)
234
- stub_request(:get, "https://www.example.com/").to_return(:status => 200)
235
- stub_request(:get, "http://example.com/").
233
+ stub_request(:head, "https://example.com/").to_return(:status => 200)
234
+ stub_request(:head, "https://www.example.com/").to_return(:status => 200)
235
+ stub_request(:head, "http://example.com/").
236
236
  to_return(:status => 301, :headers => { :location => "https://example.com" } )
237
- stub_request(:get, "http://www.example.com/").to_return(:status => 500)
237
+ stub_request(:head, "http://www.example.com/").to_return(:status => 500)
238
238
  allow(subject.endpoints.first.https).to receive(:valid?) { true }
239
239
 
240
240
  expect(subject.canonically_https?).to eql(true)
@@ -244,11 +244,12 @@ describe SiteInspector::Domain do
244
244
 
245
245
  context "redirects" do
246
246
  it "knows when a domain redirects" do
247
- stub_request(:get, "https://example.com/").to_return(:status => 500)
248
- stub_request(:get, "https://www.example.com/").to_return(:status => 500)
249
- stub_request(:get, "http://example.com/").
247
+ stub_request(:head, "https://example.com/").to_return(:status => 500)
248
+ stub_request(:head, "https://www.example.com/").to_return(:status => 500)
249
+ stub_request(:head, "http://example.com/").
250
250
  to_return(:status => 301, :headers => { :location => "http://foo.example.com" } )
251
- stub_request(:get, "http://www.example.com/").to_return(:status => 500)
251
+ stub_request(:head, "http://www.example.com/").to_return(:status => 500)
252
+ stub_request(:head, "http://foo.example.com/").to_return(:status => 200)
252
253
 
253
254
  expect(subject.redirect?).to eql(true)
254
255
  end
@@ -15,7 +15,7 @@ describe SiteInspector::Endpoint do
15
15
  end
16
16
 
17
17
  it "returns the uri" do
18
- expect(subject.uri.to_s).to eql("http://example.com")
18
+ expect(subject.uri.to_s).to eql("http://example.com/")
19
19
  end
20
20
 
21
21
  it "knows if an endpoint is www" do
@@ -28,10 +28,10 @@ describe SiteInspector::Endpoint do
28
28
  end
29
29
 
30
30
  it "knows if an endpoint is http" do
31
- stub_request(:get, "http://example.com/").
31
+ stub_request(:head, "http://example.com/").
32
32
  to_return(:status => 200, :body => "content")
33
33
 
34
- stub_request(:get, "https://example.com/").
34
+ stub_request(:head, "https://example.com/").
35
35
  to_return(:status => 500, :body => "content")
36
36
 
37
37
  expect(subject.https?).to eql(false)
@@ -39,10 +39,10 @@ describe SiteInspector::Endpoint do
39
39
  end
40
40
 
41
41
  it "knows if an endpoint is https" do
42
- stub_request(:get, "http://example.com/").
42
+ stub_request(:head, "http://example.com/").
43
43
  to_return(:status => 200, :body => "content")
44
44
 
45
- stub_request(:get, "https://example.com/").
45
+ stub_request(:head, "https://example.com/").
46
46
  to_return(:status => 200, :body => "content")
47
47
 
48
48
  endpoint = SiteInspector::Endpoint.new("https://example.com")
@@ -60,7 +60,7 @@ describe SiteInspector::Endpoint do
60
60
  context "requests" do
61
61
 
62
62
  it "requests a URL" do
63
- stub = stub_request(:get, "http://example.com/").
63
+ stub = stub_request(:head, "http://example.com/").
64
64
  to_return(:status => 200, :body => "content")
65
65
 
66
66
  expect(subject.request.body).to eql("content")
@@ -68,7 +68,7 @@ describe SiteInspector::Endpoint do
68
68
  end
69
69
 
70
70
  it "requests a requested path" do
71
- stub = stub_request(:get, "http://example.com/foo").
71
+ stub = stub_request(:head, "http://example.com/foo").
72
72
  to_return(:status => 200, :body => "content")
73
73
 
74
74
  expect(subject.request(:path => "foo").body).to eql("content")
@@ -76,7 +76,7 @@ describe SiteInspector::Endpoint do
76
76
  end
77
77
 
78
78
  it "requests with typhoeus options" do
79
- stub_request(:get, "http://example.com/").
79
+ stub_request(:head, "http://example.com/").
80
80
  to_return(:status => 301, :headers => { :location => "http://example.com/foo" } )
81
81
 
82
82
  response = subject.request(:followlocation => true)
@@ -84,7 +84,7 @@ describe SiteInspector::Endpoint do
84
84
  end
85
85
 
86
86
  it "returns the response" do
87
- stub = stub_request(:get, "http://example.com/").
87
+ stub = stub_request(:head, "http://example.com/").
88
88
  to_return(:status => 200, :body => "content")
89
89
 
90
90
  expect(subject.response.body).to eql("content")
@@ -93,7 +93,7 @@ describe SiteInspector::Endpoint do
93
93
  end
94
94
 
95
95
  it "knows if there's a response" do
96
- stub_request(:get, "http://example.com/").
96
+ stub_request(:head, "http://example.com/").
97
97
  to_return(:status => 200, :body => "content")
98
98
 
99
99
  expect(subject.responds?).to eql(true)
@@ -108,7 +108,7 @@ describe SiteInspector::Endpoint do
108
108
  end
109
109
 
110
110
  it "knows the response code" do
111
- stub_request(:get, "http://example.com/").
111
+ stub_request(:head, "http://example.com/").
112
112
  to_return(:status => 200)
113
113
 
114
114
  expect(subject.response_code).to eql("200")
@@ -120,7 +120,7 @@ describe SiteInspector::Endpoint do
120
120
  end
121
121
 
122
122
  it "considers a 200 response code to be live and a response" do
123
- stub_request(:get, "http://example.com/").
123
+ stub_request(:head, "http://example.com/").
124
124
  to_return(:status => 200)
125
125
 
126
126
  expect(subject.up?).to eql(true)
@@ -128,7 +128,7 @@ describe SiteInspector::Endpoint do
128
128
  end
129
129
 
130
130
  it "considers a 301 response code to be live and a response" do
131
- stub_request(:get, "http://example.com/").
131
+ stub_request(:head, "http://example.com/").
132
132
  to_return(:status => 301)
133
133
 
134
134
  expect(subject.up?).to eql(true)
@@ -136,7 +136,7 @@ describe SiteInspector::Endpoint do
136
136
  end
137
137
 
138
138
  it "considers a 404 response code to be down but a response" do
139
- stub_request(:get, "http://example.com/").
139
+ stub_request(:head, "http://example.com/").
140
140
  to_return(:status => 404)
141
141
 
142
142
  expect(subject.up?).to eql(false)
@@ -144,7 +144,7 @@ describe SiteInspector::Endpoint do
144
144
  end
145
145
 
146
146
  it "considers a 500 response code to be down but a response" do
147
- stub_request(:get, "http://example.com/").
147
+ stub_request(:head, "http://example.com/").
148
148
  to_return(:status => 500)
149
149
 
150
150
  expect(subject.up?).to eql(false)
@@ -168,59 +168,65 @@ describe SiteInspector::Endpoint do
168
168
 
169
169
  context "redirects" do
170
170
  it "knows when there's a redirect" do
171
- stub_request(:get, "http://example.com/").
171
+ stub_request(:head, "http://example.com/").
172
172
  to_return(:status => 301, :headers => { :location => "http://www.example.com" } )
173
173
 
174
174
  expect(subject.redirect?).to eql(true)
175
175
  end
176
176
 
177
177
  it "returns the redirect" do
178
- stub_request(:get, "http://example.com/").
178
+ stub_request(:head, "http://example.com/").
179
179
  to_return(:status => 301, :headers => { :location => "http://www.example.com" } )
180
180
 
181
- stub_request(:get, "http://www.example.com/").
181
+ stub_request(:head, "http://www.example.com/").
182
182
  to_return(:status => 200)
183
183
 
184
- expect(subject.redirect.uri.to_s).to eql("http://www.example.com")
184
+ expect(subject.redirect.uri.to_s).to eql("http://www.example.com/")
185
185
  end
186
186
 
187
187
  it "handles relative redirects" do
188
- stub_request(:get, "http://example.com/").
188
+ stub_request(:head, "http://example.com/").
189
189
  to_return(:status => 301, :headers => { :location => "/foo" } )
190
190
 
191
191
  expect(subject.redirect?).to eql(false)
192
192
  end
193
193
 
194
194
  it "handles relative redirects without a leading slash" do
195
- stub_request(:get, "http://example.com/").
195
+ stub_request(:head, "http://example.com/").
196
196
  to_return(:status => 301, :headers => { :location => "foo" } )
197
197
 
198
198
  expect(subject.redirect?).to eql(false)
199
199
  end
200
200
 
201
201
  it "knows what it resolves to" do
202
- stub_request(:get, "http://example.com/").
202
+ stub_request(:head, "http://example.com/").
203
203
  to_return(:status => 301, :headers => { :location => "http://www.example.com" } )
204
204
 
205
- stub_request(:get, "http://www.example.com/").
205
+ stub_request(:head, "http://www.example.com/").
206
206
  to_return(:status => 200)
207
207
 
208
208
  expect(subject.redirect?).to eql(true)
209
- expect(subject.resolves_to.uri.to_s).to eql("http://www.example.com")
209
+ expect(subject.resolves_to.uri.to_s).to eql("http://www.example.com/")
210
210
  end
211
211
 
212
212
  it "detects external redirects" do
213
- stub_request(:get, "http://example.com/").
213
+ stub_request(:head, "http://example.com/").
214
214
  to_return(:status => 301, :headers => { :location => "http://www.example.gov" } )
215
215
 
216
+ stub_request(:head, "http://www.example.gov").
217
+ to_return(:status => 200)
218
+
216
219
  expect(subject.redirect?).to eql(true)
217
220
  expect(subject.external_redirect?).to eql(true)
218
221
  end
219
222
 
220
223
  it "knows internal redirects are not external redirects" do
221
- stub_request(:get, "http://example.com/").
224
+ stub_request(:head, "http://example.com/").
222
225
  to_return(:status => 301, :headers => { :location => "https://example.com" } )
223
226
 
227
+ stub_request(:head, "https://example.com/").
228
+ to_return(:status => 200)
229
+
224
230
  expect(subject.external_redirect?).to eql(false)
225
231
  end
226
232
  end
@@ -233,7 +239,7 @@ describe SiteInspector::Endpoint do
233
239
  SiteInspector::Endpoint.checks.each do |check|
234
240
  it "responds to the #{check} check" do
235
241
 
236
- stub_request(:get, "http://example.com/").
242
+ stub_request(:head, "http://example.com/").
237
243
  to_return(:status => 200)
238
244
 
239
245
  expect(subject.send(check.name)).to_not be_nil
@@ -36,6 +36,7 @@ describe SiteInspector do
36
36
  expected = {
37
37
  :accept_encoding => "gzip",
38
38
  :followlocation => false,
39
+ :method => :head,
39
40
  :timeout => 10,
40
41
  :headers => {
41
42
  "User-Agent" => "Mozilla/5.0 (compatible; SiteInspector/#{SiteInspector::VERSION}; +https://github.com/benbalter/site-inspector)"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: site-inspector
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Balter
@@ -150,6 +150,20 @@ dependencies:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0.3'
153
+ - !ruby/object:Gem::Dependency
154
+ name: parallel
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '1.6'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '1.6'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: pry
155
169
  requirement: !ruby/object:Gem::Requirement