ndd-url_checker 0.1.1 → 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 +4 -4
- data/CHANGELOG.md +9 -2
- data/Guardfile +1 -1
- data/README.md +63 -3
- data/VERSION +1 -1
- data/lib/ndd/url_checker/abstract_url_checker.rb +5 -14
- data/lib/ndd/url_checker/blocking_url_checker.rb +18 -37
- data/lib/ndd/url_checker/forked_url_checker.rb +25 -29
- data/lib/ndd/url_checker/parallel_url_checker.rb +12 -11
- data/lib/ndd/url_checker/reporting_url_checker.html.erb +97 -0
- data/lib/ndd/url_checker/reporting_url_checker.rb +83 -0
- data/lib/ndd/url_checker/status.rb +20 -20
- data/lib/ndd/url_checker/threaded_url_checker.rb +10 -8
- data/ndd-url_checker.gemspec +123 -0
- data/spec/ndd/url_checker/abstract_url_checker_spec.rb +0 -6
- data/spec/ndd/url_checker/reporting_url_checker/multiple_urls.html +111 -0
- data/spec/ndd/url_checker/reporting_url_checker/single_url.html +97 -0
- data/spec/ndd/url_checker/reporting_url_checker_spec.rb +70 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/multiple_url_checker_spec.rb +3 -11
- data/spec/support/single_url_checker_spec.rb +0 -36
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99d36713ad66fe4e91a94f8244232de75f4c9e2c
|
4
|
+
data.tar.gz: 49b3313cc7ef54b102f1af8a2e921f9b96e5c70e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb756c557e6c76cb1f5ba947b383e3b3a5baec440f7b4ae1763251744fb925050a5724588d779ea51f1901948abf2777c77bd5f86c57734117a533794144a7b6
|
7
|
+
data.tar.gz: 3d1aa11d6dec0ea8159bb643b6cebe52f33d84b979e0f2bd858356085a616e5c170af888e72cb8f5872a0617421c0e34541b5ace207e12eaf7ff537a6d3e1727
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
|
-
#
|
1
|
+
# NDD URL Checker changelog
|
2
|
+
|
3
|
+
## Version 0.2.0
|
4
|
+
|
5
|
+
- Switched to named parameters
|
6
|
+
- Fixed documentation
|
7
|
+
- Removed the `UrlChecker#validate` method.
|
8
|
+
- Changed the type of the return value of `UrlChecker#check`.
|
2
9
|
|
3
10
|
## Version 0.1.0
|
4
11
|
|
5
|
-
|
12
|
+
- initial commit
|
data/Guardfile
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
# ----------------------------------------------------------------------------------------------------------------------
|
3
2
|
# bundler
|
4
3
|
# ----------------------------------------------------------------------------------------------------------------------
|
@@ -31,6 +30,7 @@ guard :rspec, cmd: 'bundle exec rspec' do
|
|
31
30
|
|
32
31
|
# ----- lib directory
|
33
32
|
watch(%r{^lib/(.+)\.rb$}) { |m| %W(spec/#{m[1]}_spec.rb) }
|
33
|
+
watch(%r{^lib/(.+)\.(.+)\.erb$}) { |m| %W(spec/#{m[1]}_spec.rb) }
|
34
34
|
|
35
35
|
# ----- spec directory
|
36
36
|
watch(%r{^spec/.+_spec\.rb$})
|
data/README.md
CHANGED
@@ -5,13 +5,73 @@
|
|
5
5
|
[](https://codeclimate.com/github/ddidier/ndd-url_checker)
|
6
6
|
[](https://codeclimate.com/github/ddidier/ndd-url_checker)
|
7
7
|
|
8
|
-
URL validator.
|
8
|
+
An URL validator.
|
9
|
+
|
10
|
+
The API documentation can be find at [RubyDoc](http://www.rubydoc.info/github/ddidier/ndd-url_checker).
|
9
11
|
|
10
12
|
## Prerequisites
|
11
13
|
|
12
|
-
This gem
|
14
|
+
This gem requires Ruby 2.x and is tested with:
|
15
|
+
|
16
|
+
- Ruby 2.0.0
|
17
|
+
- Ruby 2.1.x
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
This gem provides several types of URL checker which may be composed using the [decorator pattern](http://en.wikipedia.org/wiki/Decorator_pattern). An URL checker exposes a [`#check(*urls)`](http://www.rubydoc.info/github/ddidier/ndd-url_checker/NDD/UrlChecker/AbstractUrlChecker#check-instance_method) method which has 2 variants:
|
22
|
+
|
23
|
+
- if a single URL is passed as an argument, it returns a single [`NDD::UrlChecker::Status`](http://www.rubydoc.info/github/ddidier/ndd-url_checker/NDD/UrlChecker/Status)
|
24
|
+
- if multiple URL are passed as arguments, it returns an array of [`NDD::UrlChecker::Status`](http://www.rubydoc.info/github/ddidier/ndd-url_checker/NDD/UrlChecker/Status)
|
25
|
+
|
26
|
+
A status has a code reflecting the result of the URL check. For the time being:
|
27
|
+
|
28
|
+
- valid codes are `direct` and `redirected`
|
29
|
+
- invalid codes are `failed`, `too_many_redirects` and `unknown_host`
|
30
|
+
|
31
|
+
### BlockingUrlChecker
|
32
|
+
|
33
|
+
[`NDD::UrlChecker::BlockingUrlChecker`](http://www.rubydoc.info/github/ddidier/ndd-url_checker/NDD/UrlChecker/BlockingUrlChecker) provides a serial URL checker using the standard [`Net:HTTP`](http://ruby-doc.org/stdlib-2.1.5/libdoc/net/http/rdoc/Net/HTTP.html) implementation.
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
checker = NDD::UrlChecker::BlockingUrlChecker.new
|
37
|
+
|
38
|
+
status = checker.check('http://www.invalid123456789.com/')
|
39
|
+
status.valid? # => false
|
40
|
+
status.code # => :unknown_host
|
41
|
+
|
42
|
+
status = checker.check('http://www.google.com/')
|
43
|
+
status.valid? # => true
|
44
|
+
status.code # => :direct
|
45
|
+
|
46
|
+
statuses = checker.check('http://www.invalid123456789.com/', 'http://www.google.com/')
|
47
|
+
statuses[0].uri # => 'http://www.invalid123456789.com/'
|
48
|
+
statuses[0].valid? # => false
|
49
|
+
statuses[0].code # => :unknown_host
|
50
|
+
statuses[1].uri # => 'http://www.google.com/'
|
51
|
+
statuses[1].valid? # => true
|
52
|
+
statuses[1].code # => :direct
|
53
|
+
```
|
54
|
+
|
55
|
+
### ParallelUrlChecker
|
56
|
+
|
57
|
+
But this will be very time consuming if there is a lot of URL to check. Meet [`NDD::UrlChecker::ParallelUrlChecker`](http://www.rubydoc.info/github/ddidier/ndd-url_checker/NDD/UrlChecker/ParallelUrlChecker) which enables a very significant processing boost. For the time being, only a forked implementation is provided but a threaded one is planed.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
checker = NDD::UrlChecker::ParallelUrlChecker.new(parallelism: 100)
|
61
|
+
checker.check('http://www.invalid123456789.com/')
|
62
|
+
checker.check('http://www.google.com/')
|
63
|
+
```
|
64
|
+
|
65
|
+
### ReportingUrlChecker
|
66
|
+
|
67
|
+
For a nice looking report, use [`NDD::UrlChecker::ReportingUrlChecker`](http://www.rubydoc.info/github/ddidier/ndd-url_checker/NDD/UrlChecker/ReportingUrlChecker) which enables reporting capabilities using ERB templates. Several built-in templates are provided: CSV (planed), HTML and JSON (planed).
|
13
68
|
|
14
|
-
|
69
|
+
```ruby
|
70
|
+
checker = NDD::UrlChecker:: ReportingUrlChecker.new(delegate_checker)
|
71
|
+
statuses = checker.check('http://www.invalid123456789.com/', 'http://www.google.com/')
|
72
|
+
report_as_text = checker.report(:html, '/some/report.html')
|
73
|
+
report_as_text = checker.report('/some/template.erb', '/some/report.html')
|
74
|
+
```
|
15
75
|
|
16
76
|
## Copyright
|
17
77
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -4,27 +4,18 @@ module NDD
|
|
4
4
|
module UrlChecker
|
5
5
|
|
6
6
|
# Abstract class, not very ruby-ish :)
|
7
|
+
# @abstract
|
7
8
|
# @author David DIDIER
|
8
9
|
class AbstractUrlChecker
|
9
10
|
|
10
|
-
# Checks that the given
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# @return [NDD::UrlChecker::Status|Hash<String => NDD::UrlChecker::Status>]
|
11
|
+
# Checks that the given URLs are valid.
|
12
|
+
# @param urls [String, Array<String>] the URLs to check
|
13
|
+
# @return [NDD::UrlChecker::Status, Array<NDD::UrlChecker::Status>] a single status for a single URL, an array
|
14
|
+
# of status for multiple parameters
|
15
15
|
def check(*urls)
|
16
16
|
raise 'NDD::UrlChecker::UrlChecker#check must be implemented'
|
17
17
|
end
|
18
18
|
|
19
|
-
# Validates that the given URL are valid.
|
20
|
-
# If there is only a single URL parameter, returns a boolean.
|
21
|
-
# If there is only multiple URL parameters, returns a Hash of boolean indexed by their URI.
|
22
|
-
# @param urls [String|Array<String>] the URLs to validate.
|
23
|
-
# @return [NDD::UrlChecker::Status|Hash<String => Boolean>]
|
24
|
-
def validate(*urls)
|
25
|
-
raise 'NDD::UrlChecker::UrlChecker#validate must be implemented'
|
26
|
-
end
|
27
|
-
|
28
19
|
end
|
29
20
|
end
|
30
21
|
end
|
@@ -7,47 +7,36 @@ require 'net/https'
|
|
7
7
|
module NDD
|
8
8
|
module UrlChecker
|
9
9
|
|
10
|
-
# An URL checker using the blocking Net::HTTP class.
|
10
|
+
# An URL checker using the blocking {Net::HTTP} class.
|
11
11
|
# @author David DIDIER
|
12
12
|
class BlockingUrlChecker < AbstractUrlChecker
|
13
13
|
|
14
14
|
# Create a new instance.
|
15
|
-
# @param [Fixnum]
|
16
|
-
# @param [Fixnum]
|
17
|
-
def initialize(maximum_redirects
|
15
|
+
# @param maximum_redirects [Fixnum] the maximum number of redirects to follow before failing.
|
16
|
+
# @param timeout [Fixnum] the number of seconds to wait before failing.
|
17
|
+
def initialize(maximum_redirects: 5, timeout: 5)
|
18
18
|
@logger = Logging.logger[self]
|
19
19
|
@maximum_redirects = maximum_redirects
|
20
20
|
@timeout = timeout
|
21
21
|
end
|
22
22
|
|
23
|
-
# Checks that the given
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# @return [NDD::UrlChecker::Status|Hash<String => NDD::UrlChecker::Status>]
|
23
|
+
# Checks that the given URLs are valid.
|
24
|
+
# @param urls [String, Array<String>] the URLs to check
|
25
|
+
# @return [NDD::UrlChecker::Status, Array<NDD::UrlChecker::Status>] a single status for a single URL, an array
|
26
|
+
# of status for multiple parameters
|
28
27
|
def check(*urls)
|
29
28
|
@logger.info "Checking #{urls.size} URL(s)"
|
30
|
-
return check_single(urls.first) if urls.size
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
# Validates that the given URL are valid.
|
35
|
-
# If there is only a single URL parameter, returns a boolean.
|
36
|
-
# If there is only multiple URL parameters, returns a Hash of boolean indexed by their URI.
|
37
|
-
# @param [String|Array<String>] urls
|
38
|
-
# @return [NDD::UrlChecker::Status|Hash<String => Boolean>]
|
39
|
-
def validate(*urls)
|
40
|
-
@logger.info "Validating #{urls.size} URL(s)"
|
41
|
-
return validate_single(urls.first) if urls.size == 1
|
42
|
-
Hash[urls.map { |url| [url, validate_single(url)] }]
|
29
|
+
return check_single(urls.first) if urls.size < 2
|
30
|
+
urls.map { |url| check_single(url) }
|
43
31
|
end
|
44
32
|
|
45
33
|
|
34
|
+
# -------------------------------------------------------------------------------------------------- private -----
|
46
35
|
private
|
47
36
|
|
48
37
|
# Checks that the given URL is valid.
|
49
|
-
#
|
50
|
-
#
|
38
|
+
# @param url [String] the URL to check
|
39
|
+
# @return [NDD::UrlChecker::Status]
|
51
40
|
def check_single(url)
|
52
41
|
begin
|
53
42
|
@logger.debug "Checking: #{url}"
|
@@ -63,18 +52,10 @@ module NDD
|
|
63
52
|
status
|
64
53
|
end
|
65
54
|
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
|
70
|
-
@logger.debug "Validating: #{url}"
|
71
|
-
check_single(url).valid?
|
72
|
-
end
|
73
|
-
|
74
|
-
# Checks that the given URL is valid.
|
75
|
-
# @param [URI::HTTP] uri the URI to check
|
76
|
-
# @param [NDD::UrlChecker::Status] status the current status of the stack
|
77
|
-
# @return [NDD::UrlChecker::Status]
|
55
|
+
# Checks that the given URI is valid.
|
56
|
+
# @param uri [URI::HTTP] the URI to check.
|
57
|
+
# @param status [NDD::UrlChecker::Status] the current status of the stack.
|
58
|
+
# @return [NDD::UrlChecker::Status]
|
78
59
|
def check_uri(uri, status)
|
79
60
|
if status.uris.size() > @maximum_redirects
|
80
61
|
return status.too_many_redirects
|
@@ -122,7 +103,7 @@ module NDD
|
|
122
103
|
end
|
123
104
|
end
|
124
105
|
|
125
|
-
#
|
106
|
+
# FIXME: platform dependent?
|
126
107
|
UNKNOWN_HOST_MESSAGE = 'getaddrinfo: Name or service not known'
|
127
108
|
|
128
109
|
def unknown_host?(error)
|
@@ -9,49 +9,43 @@ module NDD
|
|
9
9
|
|
10
10
|
# An URL checker using forks to parallelize processing. To be used with MRI.
|
11
11
|
# @author David DIDIER
|
12
|
+
# @attr_reader delegate [#check] the delegate URL checker.
|
13
|
+
# @attr_reader parallelism [Fixnum] the number of processes.
|
12
14
|
class ForkedUrlChecker < AbstractUrlChecker
|
13
15
|
|
14
16
|
attr_reader :delegate
|
15
17
|
attr_reader :parallelism
|
16
18
|
|
17
19
|
# Create a new instance.
|
18
|
-
# @param [AbstractUrlChecker]
|
19
|
-
# @param [Fixnum]
|
20
|
-
def initialize(delegate_checker
|
20
|
+
# @param delegate_checker [AbstractUrlChecker] defaults to {NDD::UrlChecker::BlockingUrlChecker}.
|
21
|
+
# @param parallelism [Fixnum] the number of processes.
|
22
|
+
def initialize(delegate_checker: nil, parallelism: 10)
|
21
23
|
@logger = Logging.logger[self]
|
22
24
|
@delegate = delegate_checker || BlockingUrlChecker.new
|
23
25
|
@parallelism = parallelism
|
24
26
|
end
|
25
27
|
|
28
|
+
# Checks that the given URLs are valid.
|
29
|
+
# @param urls [String, Array<String>] the URLs to check
|
30
|
+
# @return [NDD::UrlChecker::Status, Array<NDD::UrlChecker::Status>] a single status for a single URL, an array
|
31
|
+
# of status for multiple parameters
|
26
32
|
def check(*urls)
|
27
33
|
return delegate.check(*urls) if urls.size < 2
|
28
|
-
process(urls, :check)
|
29
|
-
end
|
30
|
-
|
31
|
-
def validate(*urls)
|
32
|
-
return delegate.validate(*urls) if urls.size < 2
|
33
|
-
process(urls, :validate)
|
34
|
-
end
|
35
|
-
|
36
34
|
|
37
|
-
private
|
38
|
-
|
39
|
-
def process(urls, method)
|
40
35
|
# for receiving results
|
41
36
|
result_pipe = Cod.pipe
|
42
37
|
# partition the URLs, but not too much :)
|
43
38
|
url_slices = partition(urls, [parallelism, urls.size].min)
|
44
39
|
# and distribute them among the workers
|
45
40
|
pids = url_slices.each_with_index.map do |url_slice, index|
|
46
|
-
fork { Worker.new(index, result_pipe, delegate).
|
41
|
+
fork { Worker.new(index, result_pipe, delegate).check(url_slice) }
|
47
42
|
end
|
48
43
|
|
49
44
|
# read back the results
|
50
|
-
results = urls.
|
45
|
+
results = urls.map do |_|
|
51
46
|
result = result_pipe.get
|
52
|
-
hash.merge!(result)
|
53
47
|
@logger.debug("Processed URLs #{hash.size}/#{urls.size}")
|
54
|
-
|
48
|
+
result
|
55
49
|
end
|
56
50
|
|
57
51
|
# kill all the workers
|
@@ -60,9 +54,15 @@ module NDD
|
|
60
54
|
results
|
61
55
|
end
|
62
56
|
|
63
|
-
|
64
|
-
#
|
65
|
-
|
57
|
+
|
58
|
+
# -------------------------------------------------------------------------------------------------- private -----
|
59
|
+
private
|
60
|
+
|
61
|
+
# Evenly distributes data into buckets.
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# partition([1, 2, 3], 2) #=> [[1, 3], [2]]
|
65
|
+
# partition([1, 2, 3, 4, 5, 6], 3) #=> [[1, 4], [2, 5], [3, 6]]
|
66
66
|
def partition(data, buckets)
|
67
67
|
Array.new.tap do |slices|
|
68
68
|
buckets.times.each { |_| slices << Array.new }
|
@@ -71,7 +71,9 @@ module NDD
|
|
71
71
|
end
|
72
72
|
|
73
73
|
|
74
|
+
# ---------------------------------------------------------------------------------------------------- class -----
|
74
75
|
# A simple worker class processing URL one by one.
|
76
|
+
# @private
|
75
77
|
class Worker
|
76
78
|
def initialize(id, result_pipe, url_checker)
|
77
79
|
@logger = Logging.logger[self]
|
@@ -83,18 +85,12 @@ module NDD
|
|
83
85
|
def check(urls)
|
84
86
|
@logger.debug("[worker #{@id}] Checking #{urls.size} URLs")
|
85
87
|
urls.each do |url|
|
86
|
-
@result_pipe.put(
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def validate(urls)
|
91
|
-
@logger.debug("[worker #{@id}] Validating #{urls.size} URLs")
|
92
|
-
urls.each do |url|
|
93
|
-
@result_pipe.put({url => @url_checker.validate(url)})
|
88
|
+
@result_pipe.put(@url_checker.check(url))
|
94
89
|
end
|
95
90
|
end
|
96
91
|
end
|
97
92
|
|
93
|
+
private_constant :Worker
|
98
94
|
end
|
99
95
|
end
|
100
96
|
end
|
@@ -7,39 +7,40 @@ require 'ndd/url_checker/threaded_url_checker'
|
|
7
7
|
module NDD
|
8
8
|
module UrlChecker
|
9
9
|
|
10
|
-
# Wraps an instance of ThreadedUrlChecker or ForkedUrlChecker
|
11
|
-
#
|
10
|
+
# Wraps an instance of {NDD::UrlChecker::ThreadedUrlChecker} or {NDD::UrlChecker::ForkedUrlChecker}
|
11
|
+
# depending of the underlying Ruby implementation.
|
12
12
|
# @author David DIDIER
|
13
|
+
# @attr_reader delegate [#check] the delegate URL checker.
|
13
14
|
class ParallelUrlChecker < AbstractUrlChecker
|
14
15
|
|
15
16
|
attr_reader :delegate
|
16
17
|
|
17
18
|
# Create a new instance.
|
18
|
-
# @param [AbstractUrlChecker]
|
19
|
-
# @param [Fixnum]
|
20
|
-
def initialize(delegate_checker
|
19
|
+
# @param delegate_checker [AbstractUrlChecker] defaults to {NDD::UrlChecker::BlockingUrlChecker}.
|
20
|
+
# @param parallelism [Fixnum] the number of threads or processes.
|
21
|
+
def initialize(delegate_checker: nil, parallelism: 10)
|
21
22
|
@logger = Logging.logger[self]
|
22
23
|
|
23
24
|
@logger.debug "Ruby engine is #{RUBY_ENGINE}"
|
24
25
|
if RUBY_ENGINE == 'jruby'
|
25
26
|
@logger.info 'Creating a threaded URL checker'
|
26
|
-
parallel_checker = ThreadedUrlChecker.new(delegate_checker, parallelism)
|
27
|
+
parallel_checker = ThreadedUrlChecker.new(delegate_checker: delegate_checker, parallelism: parallelism)
|
27
28
|
else
|
28
29
|
@logger.info 'Creating a forked URL checker'
|
29
|
-
parallel_checker = ForkedUrlChecker.new(delegate_checker, parallelism)
|
30
|
+
parallel_checker = ForkedUrlChecker.new(delegate_checker: delegate_checker, parallelism: parallelism)
|
30
31
|
end
|
31
32
|
|
32
33
|
@delegate = parallel_checker
|
33
34
|
end
|
34
35
|
|
36
|
+
# Checks that the given URLs are valid.
|
37
|
+
# @param urls [String, Array<String>] the URLs to check
|
38
|
+
# @return [NDD::UrlChecker::Status, Array<NDD::UrlChecker::Status>] a single status for a single URL, an array
|
39
|
+
# of status for multiple parameters
|
35
40
|
def check(*urls)
|
36
41
|
@delegate.check(*urls)
|
37
42
|
end
|
38
43
|
|
39
|
-
def validate(*urls)
|
40
|
-
@delegate.validate(*urls)
|
41
|
-
end
|
42
|
-
|
43
44
|
end
|
44
45
|
end
|
45
46
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
|
4
|
+
<head>
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
|
7
|
+
<style>
|
8
|
+
body {
|
9
|
+
padding: 1em;
|
10
|
+
}
|
11
|
+
</style>
|
12
|
+
|
13
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
14
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
|
15
|
+
<script language="JavaScript">
|
16
|
+
$(document).ready(function() {
|
17
|
+
$('input[type=radio][name=urlsFilter]').change(function() {
|
18
|
+
if (this.value == 'all') {
|
19
|
+
$('tr').show();
|
20
|
+
}
|
21
|
+
else if (this.value == 'invalid') {
|
22
|
+
$('tr').not('.danger').hide();
|
23
|
+
}
|
24
|
+
});
|
25
|
+
});
|
26
|
+
</script>
|
27
|
+
</head>
|
28
|
+
|
29
|
+
<body>
|
30
|
+
|
31
|
+
<h1>URL Checker Report</h1>
|
32
|
+
|
33
|
+
<table class="table table-condensed table-hover" style="width: auto">
|
34
|
+
<tbody>
|
35
|
+
<tr>
|
36
|
+
<td>User CPU time</td>
|
37
|
+
<td><%= benchmark.utime %> second(s)</td>
|
38
|
+
</tr>
|
39
|
+
<tr>
|
40
|
+
<td>System CPU time</td>
|
41
|
+
<td><%= benchmark.stime %> second(s)</td>
|
42
|
+
</tr>
|
43
|
+
<tr>
|
44
|
+
<td>Total time</td>
|
45
|
+
<td><%= benchmark.total %> second(s)</td>
|
46
|
+
</tr>
|
47
|
+
<tr>
|
48
|
+
<td>Elapsed real time</td>
|
49
|
+
<td><%= benchmark.real %> second(s)</td>
|
50
|
+
</tr>
|
51
|
+
<tr>
|
52
|
+
<td>Number of URLs</td>
|
53
|
+
<td><%= results.size %></td>
|
54
|
+
</tr>
|
55
|
+
<tr>
|
56
|
+
<td>Average time for 1 URL</td>
|
57
|
+
<td><%= benchmark.real/results.size %> second(s)</td>
|
58
|
+
</tr>
|
59
|
+
</tbody>
|
60
|
+
</table>
|
61
|
+
|
62
|
+
<div class="radio">
|
63
|
+
<label>
|
64
|
+
<input type="radio" name="urlsFilter" id="showAllUrls" value="all" checked="true" />
|
65
|
+
Show all URLs
|
66
|
+
</label>
|
67
|
+
</div>
|
68
|
+
<div class="radio">
|
69
|
+
<label>
|
70
|
+
<input type="radio" name="urlsFilter" id="showInvalidUrls" value="invalid" />
|
71
|
+
Show invalid URLs
|
72
|
+
</label>
|
73
|
+
</div>
|
74
|
+
|
75
|
+
<table class="table table-condensed table-hover" style="width: auto">
|
76
|
+
<thead>
|
77
|
+
<tr>
|
78
|
+
<th>#</th>
|
79
|
+
<th>URL</th>
|
80
|
+
<th>Result</th>
|
81
|
+
<th>Comment</th>
|
82
|
+
</tr>
|
83
|
+
</thead>
|
84
|
+
<tbody>
|
85
|
+
<% results.each_with_index do |status, index| %>
|
86
|
+
<tr class="<%= status.invalid? ? 'danger' : '' %>">
|
87
|
+
<td><%= index+1 %></td>
|
88
|
+
<td><a href="<%= status.uri %>" target="_blank"><%= status.uri %></a></td>
|
89
|
+
<td><%= status.class %></td>
|
90
|
+
<td><% if status.invalid? %><%= status.error %><% end %></td>
|
91
|
+
</tr>
|
92
|
+
<% end %>
|
93
|
+
</tbody>
|
94
|
+
</table>
|
95
|
+
|
96
|
+
</body>
|
97
|
+
</html>
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'erb'
|
3
|
+
require 'logging'
|
4
|
+
require 'ndd/url_checker'
|
5
|
+
require 'ostruct'
|
6
|
+
|
7
|
+
module NDD
|
8
|
+
module UrlChecker
|
9
|
+
|
10
|
+
# Wraps an instance of URL checker and provides reporting capabilities using ERB templates.
|
11
|
+
# @author David DIDIER
|
12
|
+
# @attr_reader delegate [#check] the delegate URL checker.
|
13
|
+
class ReportingUrlChecker < AbstractUrlChecker
|
14
|
+
|
15
|
+
attr_reader :delegate
|
16
|
+
|
17
|
+
# Create a new instance.
|
18
|
+
# @param delegate_checker [AbstractUrlChecker].
|
19
|
+
def initialize(delegate_checker)
|
20
|
+
@logger = Logging.logger[self]
|
21
|
+
@delegate = delegate_checker
|
22
|
+
end
|
23
|
+
|
24
|
+
def check(*urls)
|
25
|
+
results = nil
|
26
|
+
benchmark = Benchmark.measure { results = @delegate.check(*urls) }
|
27
|
+
@logger.debug "Checking #{urls.size} URL(s) benchmark: #{benchmark}"
|
28
|
+
|
29
|
+
if urls.size > 1
|
30
|
+
@context = OpenStruct.new(
|
31
|
+
{
|
32
|
+
benchmark: benchmark,
|
33
|
+
results: results.sort_by { |status| status.uri }
|
34
|
+
})
|
35
|
+
else
|
36
|
+
@context = OpenStruct.new(
|
37
|
+
{
|
38
|
+
benchmark: benchmark,
|
39
|
+
results: [results]
|
40
|
+
})
|
41
|
+
end
|
42
|
+
|
43
|
+
results
|
44
|
+
end
|
45
|
+
|
46
|
+
# Creates a report about the previous check using the specified template. The result may be written to a file.
|
47
|
+
# @param template [Symbol, String] a predefined template (:csv, :html, :json) or the path of a template file.
|
48
|
+
# @param output_path [String, nil] the path of the output file.
|
49
|
+
# @return [String] the report.
|
50
|
+
def report(template, output_path=nil)
|
51
|
+
template_path = template_path(template)
|
52
|
+
template_content = ERB.new(File.new(template_path).read)
|
53
|
+
report = template_content.result(@context.instance_eval { binding })
|
54
|
+
|
55
|
+
if output_path
|
56
|
+
@logger.info "Reporting to #{output_path}"
|
57
|
+
File.open(output_path, 'w') { |file| file.write(report) }
|
58
|
+
end
|
59
|
+
|
60
|
+
report
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# -------------------------------------------------------------------------------------------------- private -----
|
65
|
+
private
|
66
|
+
|
67
|
+
def template_path(symbol_or_path)
|
68
|
+
case symbol_or_path
|
69
|
+
when :csv then
|
70
|
+
# File.expand_path(File.join(File.dirname(__FILE__), 'reporting_url_checker.csv.erb'))
|
71
|
+
raise 'TODO'
|
72
|
+
when :html then
|
73
|
+
File.expand_path(File.join(File.dirname(__FILE__), 'reporting_url_checker.html.erb'))
|
74
|
+
when :json then
|
75
|
+
# File.expand_path(File.join(File.dirname(__FILE__), 'reporting_url_checker.json.erb'))
|
76
|
+
raise 'TODO'
|
77
|
+
else
|
78
|
+
symbol_or_path
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|