html-proofer 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c5f9520152e65b775e134ac987d42fdeb69a4448
4
- data.tar.gz: 6fb435127a7de49da70d5b9284d95bbb736bc19b
3
+ metadata.gz: 96ef995058e63021380229872126e11c18216d4a
4
+ data.tar.gz: 97f17a39a973e7819f52cbb0611f9f64f0152f94
5
5
  SHA512:
6
- metadata.gz: d2e355f14b84c62685a44b01e93109f7d4c6ddad4884c952f4c734c8a473ee22f94a258b09601bac4a648d9d3fa61f0f949d800208296755e5d63be5a4ca6f67
7
- data.tar.gz: 9e768b2b3920f5bf61fe1bcd257e890315cbe110c08afec49ba0a8e637341eef5c88f546adeeefcfa079a779b06b09f087ec18b00ed1c21f3f06ec038dd5c4c6
6
+ metadata.gz: 459bf3c2a753d660993f17ba982367a2ae395a04d3866bacb590f687c82b5929138fa596282d2ecac95f7644128777fceaa2fbeb2967737beb3d02cdd9d37c5d
7
+ data.tar.gz: 953d20ddcd61d8af3bec8eb7b9ffc2c8f532a16f9241960ee7040255b87079a4c8b72ba0210c411fbd4597833bf8f94d0d3f65c57870f88471d29bbf3c284838
data/Gemfile.lock CHANGED
@@ -1,11 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- html-proofer (0.2.3)
4
+ html-proofer (0.3.0)
5
5
  colored (~> 1.2)
6
6
  mercenary (~> 0.2.0)
7
7
  nokogiri (~> 1.6.0)
8
- typhoeus (~> 0.6.3)
8
+ typhoeus (~> 0.6.7)
9
9
 
10
10
  GEM
11
11
  remote: http://rubygems.org/
@@ -20,7 +20,7 @@ GEM
20
20
  colored (1.2)
21
21
  diff-lcs (1.2.4)
22
22
  escape_utils (0.3.2)
23
- ethon (0.6.1)
23
+ ethon (0.6.2)
24
24
  ffi (>= 1.3.0)
25
25
  mime-types (~> 1.18)
26
26
  ffi (1.9.3)
@@ -56,8 +56,8 @@ GEM
56
56
  nokogiri (>= 1.4.4)
57
57
  thread_safe (0.1.3)
58
58
  atomic
59
- typhoeus (0.6.6)
60
- ethon (~> 0.6.1)
59
+ typhoeus (0.6.7)
60
+ ethon (~> 0.6.2)
61
61
  tzinfo (0.3.38)
62
62
 
63
63
  PLATFORMS
data/README.md CHANGED
@@ -69,7 +69,9 @@ Note: since `swap` is a bit special, you'll pass in a pair of `RegEx:String` val
69
69
 
70
70
  ## Usage with Jekyll
71
71
 
72
- Want to use HTML Proofer with your Jekyll site? Awesome. Simply add `gem 'html-proofer'` to your `Gemfile` as described above, and add the following to your `Rakefile`, using `rake test` to execute:
72
+ Want to use HTML Proofer with your Jekyll site? Awesome. Simply add `gem 'html-proofer'`
73
+ to your `Gemfile` as described above, and add the following to your `Rakefile`,
74
+ using `rake test` to execute:
73
75
 
74
76
  ```ruby
75
77
  require 'html/proofer'
@@ -94,12 +96,23 @@ htmlproof ./_site
94
96
  * Whether your internal links are not broken; this includes hash references (`#linkToMe`)
95
97
  * Whether external links are working
96
98
 
97
- ## Configuration
99
+ ## Configuration
98
100
 
99
101
  The `HTML::Proofer` constructor takes an optional hash of additional options:
100
102
 
101
103
  * `:ext`: the extension (including the `.`) of your HTML files (default: `.html`)
102
104
  * `:href_swap`: a hash containing key-value pairs of `RegExp => String`. It transforms links that match `RegExp` into `String` via `gsub`.
103
- * `:href_ignore`: an array of Strings containing `href`s that are safe to ignore (default: `mailto`)
105
+ * `:href_ignore`: an array of Strings containing `href`s that are safe to ignore (by default, `mailto` is always ignored)
106
+ * `:disable_external`: if `true`, does not run the external link checker, which can take a lot of time (default: `false`)
104
107
 
105
- To any `<a>` or `<img>` tag, you may add the `data-proofer-ignore` attribute to ignore the link.
108
+ You can also pass in any of Typhoeus' options for the external link check. For example:
109
+
110
+ ``` ruby
111
+ HTML::Proofer.new("out/", {:ext => ".htm", :verbose = > true, :ssl_verifyhost => 2 })
112
+ ```
113
+
114
+ This sets `HTML::Proofer`'s' extensions to use _.htm_, and gives Typhoeus a configurtion for it to be verbose, and use specific SSL settings. Check [the Typhoeus documentation](https://github.com/typhoeus/typhoeus#other-curl-options) for more information on what options it can receive.
115
+
116
+ ## Ignoring links
117
+
118
+ To any `<a>` or `<img>` tag, you may add the `data-proofer-ignore` attribute to ignore the link.
data/html-proofer.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |gem|
18
18
  gem.add_dependency "mercenary", "~> 0.2.0"
19
19
  gem.add_dependency "nokogiri", "~> 1.6.0"
20
20
  gem.add_dependency "colored", "~> 1.2"
21
- gem.add_dependency "typhoeus", "~> 0.6.3"
21
+ gem.add_dependency "typhoeus", "~> 0.6.7"
22
22
 
23
23
  gem.add_development_dependency "html-pipeline", "~> 0.0.12"
24
24
  gem.add_development_dependency "rspec", "~> 2.13.0"
data/lib/html/proofer.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'nokogiri'
2
+
2
3
  require File.dirname(__FILE__) + '/proofer/checkable'
3
4
  require File.dirname(__FILE__) + '/proofer/checks'
4
5
 
@@ -6,44 +7,109 @@ module HTML
6
7
  class Proofer
7
8
  def initialize(src, opts={})
8
9
  @srcDir = src
9
- @options = {:ext => ".html"}.merge(opts)
10
+
11
+ @proofer_opts = {:ext => ".html", :href_swap => [], :href_ignore => [], :disable_external => false }
12
+ @options = @proofer_opts.merge({:followlocation => true}).merge(opts)
13
+
14
+ @failed_tests = []
10
15
  end
11
16
 
12
17
  def run
13
18
  total_files = 0
14
- failed_tests = []
19
+ external_urls = {}
15
20
 
16
- puts "Running #{get_checks} checks on #{@srcDir}... \n\n"
21
+ puts "Running #{get_checks} checks on #{@srcDir} on *#{@options[:ext]}... \n\n"
17
22
 
18
- Dir.glob("#{@srcDir}/**/*#{@options[:ext]}") do |path|
23
+ files.each do |path|
19
24
  total_files += 1
20
25
  html = HTML::Proofer.create_nokogiri(path)
21
26
 
22
27
  get_checks.each do |klass|
23
28
  check = klass.new(@srcDir, path, html, @options)
24
29
  check.run
25
- check.hydra.run
26
- failed_tests.concat(check.issues) if check.issues.length > 0
30
+ external_urls.merge!(check.external_urls)
31
+ @failed_tests.concat(check.issues) if check.issues.length > 0
27
32
  end
28
33
  end
29
34
 
35
+ # the hypothesis is that Proofer runs way faster if we pull out
36
+ # all the external URLs and run the checks at the end. Otherwise, we're halting
37
+ # the consuming process for every file. In addition, sorting the list lets
38
+ # libcurl keep connections to hosts alive. Finally, we'll make a HEAD request,
39
+ # rather than GETing all the contents
40
+ external_urls = Hash[external_urls.sort]
41
+
42
+ unless @options[:disable_external]
43
+ puts "Checking #{external_urls.length} external links... \n\n"
44
+
45
+ # Typhoeus won't let you pass any non-Typhoeus option
46
+ @proofer_opts.each_key do |opt|
47
+ @options.delete opt
48
+ end
49
+
50
+ external_urls.each_pair do |href, filenames|
51
+ request = Typhoeus::Request.new(href, @options.merge({:method => :head}))
52
+ request.on_complete { |response| response_handler(response, filenames) }
53
+ hydra.queue request
54
+ end
55
+ hydra.run
56
+ end
57
+
30
58
  puts "Ran on #{total_files} files!"
31
59
 
32
- if failed_tests.empty?
60
+ if @failed_tests.empty?
33
61
  puts "HTML-Proofer finished successfully.".green
34
- exit 0
35
62
  else
36
- failed_tests.each do |issue|
63
+ @failed_tests.each do |issue|
37
64
  $stderr.puts issue + "\n\n"
38
65
  end
39
66
 
40
- raise "HTML-Proofer found #{failed_tests.length} failures!"
67
+ raise "HTML-Proofer found #{@failed_tests.length} failures!"
68
+ end
69
+ end
70
+
71
+ def response_handler(response, filenames)
72
+ href = response.options[:effective_url]
73
+ method = response.request.options[:method]
74
+ response_code = response.code
75
+
76
+ if response_code.between?(200, 299)
77
+ # continue with no op
78
+ elsif response.timed_out?
79
+ @failed_tests << "#{filenames.join(' ').blue}: External link #{href} failed: got a time out"
80
+ # hey here's a funny bug: sometimes HEAD requests return a 404, even on legitimate pages! The
81
+ # bug seems to affect curl; try `curl -I -X HEAD https://help.github.com/changing-author-info`
82
+ # so in these cases, try a regular `GET`. if it fails, it fails.
83
+ elsif response_code == 404 && method == :head
84
+ next_response = Typhoeus.get(href, @options)
85
+ response_handler(next_response, filenames)
86
+ elsif (response_code == 420 || response_code == 503) && method == :head
87
+ # 420s usually come from rate limiting; let's ignore the query and try just the path with a GET
88
+ uri = URI(href)
89
+ next_response = Typhoeus.get(uri.scheme + "://" + uri.host + uri.path, @options)
90
+ response_handler(next_response, filenames)
91
+ else
92
+ # Received a non-successful http response.
93
+ @failed_tests << "#{filenames.join(' ').blue}: External link #{href} failed: #{response_code} #{response.return_message}"
94
+ end
95
+ end
96
+
97
+ def hydra
98
+ @hydra ||= Typhoeus::Hydra.new
99
+ end
100
+
101
+ def files
102
+ if File.directory? @srcDir
103
+ Dir.glob("#{@srcDir}/**/*#{@options[:ext]}")
104
+ else
105
+ File.extname(@srcDir) == @options[:ext] ? [@srcDir] : []
41
106
  end
42
107
  end
43
108
 
44
109
  def self.create_nokogiri(path)
45
110
  path << "/index.html" if File.directory? path # support for Jekyll-style links
46
- Nokogiri::HTML(File.read(path))
111
+ content = File.open(path, "rb") {|f| f.read }
112
+ Nokogiri::HTML(content)
47
113
  end
48
114
 
49
115
  def get_checks
@@ -10,7 +10,7 @@ class HTML::Proofer::Checks
10
10
 
11
11
  class Check
12
12
 
13
- attr_reader :issues, :hydra, :src, :path, :options, :additional_href_ignores
13
+ attr_reader :issues, :src, :path, :options, :external_urls, :additional_href_ignores
14
14
 
15
15
  def initialize(src, path, html, opts={})
16
16
  @src = src
@@ -18,10 +18,8 @@ class HTML::Proofer::Checks
18
18
  @html = html
19
19
  @options = opts
20
20
  @issues = []
21
- @checked_urls = {}
22
-
23
- @hydra = Typhoeus::Hydra.hydra
24
- @additional_href_ignores = @options[:href_ignore] || []
21
+ @additional_href_ignores = @options[:href_ignore]
22
+ @external_urls = {}
25
23
  end
26
24
 
27
25
  def run
@@ -36,44 +34,12 @@ class HTML::Proofer::Checks
36
34
  Dir[@site.config[:output_dir] + '/**/*'].select{ |f| File.file?(f) }
37
35
  end
38
36
 
39
- def validate_url(href, issue_text)
40
- return @checked_urls[href] if @checked_urls.has_key? href
41
- request = Typhoeus::Request.new(href, {:followlocation => true})
42
- request.on_complete do |response|
43
- if response.success?
44
- @checked_urls[href] = true
45
- elsif response.timed_out?
46
- self.add_issue(issue_text + " got a time out")
47
- elsif response.code == 0
48
- # Could not get an http response, something's wrong.
49
- self.add_issue(issue_text + ". #{response.return_message}!")
50
- else
51
- response_code = response.code.to_s
52
- if %w(420 503).include?(response_code)
53
- # 420s usually come from rate limiting; let's ignore the query and try just the path
54
- uri = URI(href)
55
- response = Typhoeus.get(uri.scheme + "://" + uri.host + uri.path, {:followlocation => true})
56
- self.add_issue("#{issue_text} Originally, this was a #{response_code}. Now, the HTTP request failed again: #{response.code.to_s}") unless response.success?
57
- else
58
- # Received a non-successful http response.
59
- self.add_issue("#{issue_text} HTTP request failed: #{response_code}")
60
- end
61
- end
62
-
63
- @checked_urls[href] = false unless response.success?
64
- end
65
- hydra.queue(request)
66
- end
67
-
68
- def request_url(url)
69
- path = (url.path.nil? || url.path.empty? ? '/' : url.path)
70
- req = Net::HTTP::Head.new(path)
71
- http = Net::HTTP.new(url.host, url.port)
72
- if url.instance_of? URI::HTTPS
73
- http.use_ssl = true
74
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
37
+ def add_to_external_urls(href)
38
+ if @external_urls[href]
39
+ @external_urls[href] << @path
40
+ else
41
+ @external_urls[href] = [@path]
75
42
  end
76
- res = http.request(req)
77
43
  end
78
44
 
79
45
  def self.subclasses
@@ -1,7 +1,6 @@
1
1
  module HTML
2
2
  class Proofer
3
3
  class Checkable
4
-
5
4
  def initialize(obj, check)
6
5
  @src = obj['src']
7
6
  @href = obj['href']
@@ -56,7 +55,7 @@ module HTML
56
55
 
57
56
  def ignore?
58
57
  uri = URI.parse url
59
- @data_ignore_proofer || %w( mailto ).include?(uri.scheme) || @check.additional_href_ignores.include?(href)
58
+ @data_ignore_proofer || %w( mailto ).include?(uri.scheme) || @check.additional_href_ignores.include?(url)
60
59
  rescue URI::BadURIError
61
60
  false
62
61
  rescue URI::InvalidURIError
@@ -76,11 +75,13 @@ module HTML
76
75
  def file_path
77
76
  return if path.nil?
78
77
 
79
- if path =~ /^\// #path relative to root
80
- base = @check.src
81
- elsif File.exist? File.expand_path path, @check.src #relative links, path is a file
78
+ if path =~ /^\// # path relative to root
79
+ base = File.directory?(@check.src) ? @check.src : File.dirname(@check.src)
80
+ elsif File.exist?(File.expand_path path, @check.src) # relative links, path is a file
81
+ base = File.dirname @check.path
82
+ elsif File.exist?(File.join(File.dirname(@check.path), path)) # relative links in nested dir, path is a file
82
83
  base = File.dirname @check.path
83
- else #relative link, path is a directory
84
+ else # relative link, path is a directory
84
85
  base = @check.path
85
86
  end
86
87
 
@@ -102,7 +103,6 @@ module HTML
102
103
  path = file_path || @check.path
103
104
  File.expand_path path, Dir.pwd
104
105
  end
105
-
106
106
  end
107
107
  end
108
108
  end
@@ -24,24 +24,27 @@ end
24
24
 
25
25
  class Images < ::HTML::Proofer::Checks::Check
26
26
  def run
27
- @html.css('img').each do |img|
27
+ @html.css('img').each do |i|
28
+ img = Image.new i, self
28
29
 
29
- img = Image.new img, self
30
-
31
- # screenshot filenames, return because invalid URL
30
+ # screenshot filenames should return because of terrible names
32
31
  return self.add_issue "image has a terrible filename (#{img.src})" if img.terrible_filename?
33
32
 
34
33
  # does the image exist?
35
34
  if img.missing_src?
36
35
  self.add_issue "image has no src attribute"
37
36
  elsif img.remote?
38
- validate_url img.src, "external image #{img.src} does not exist"
37
+ return if img.ignore?
38
+ add_to_external_urls img.src
39
39
  else
40
+ return if img.ignore?
40
41
  self.add_issue("internal image #{img.src} does not exist") unless img.exists?
41
42
  end
42
43
 
43
44
  # check alt tag
44
45
  self.add_issue "image #{img.src} does not have an alt attribute" unless img.valid_alt_tag?
45
46
  end
47
+
48
+ return external_urls
46
49
  end
47
50
  end
@@ -15,9 +15,8 @@ end
15
15
  class Links < ::HTML::Proofer::Checks::Check
16
16
 
17
17
  def run
18
- @html.css('a').each do |link|
19
-
20
- link = Link.new link, self
18
+ @html.css('a').each do |l|
19
+ link = Link.new l, self
21
20
  return if link.ignore?
22
21
 
23
22
  # is there even a href?
@@ -28,7 +27,7 @@ class Links < ::HTML::Proofer::Checks::Check
28
27
 
29
28
  # does the file even exist?
30
29
  if link.remote?
31
- validate_url link.href, "externally linking to #{link.href}, which does not exist"
30
+ add_to_external_urls link.href
32
31
  else
33
32
  self.add_issue "internally linking to #{link.href}, which does not exist" unless link.exists?
34
33
  end
@@ -36,7 +35,7 @@ class Links < ::HTML::Proofer::Checks::Check
36
35
  # verify the target hash
37
36
  if link.hash
38
37
  if link.remote?
39
- #not yet checked
38
+ add_to_external_urls link.href
40
39
  elsif link.internal?
41
40
  self.add_issue "linking to internal hash ##{link.hash} that does not exist" unless hash_check @html, link.hash
42
41
  elsif link.external?
@@ -49,6 +48,8 @@ class Links < ::HTML::Proofer::Checks::Check
49
48
  end
50
49
  end
51
50
  end
51
+
52
+ return external_urls
52
53
  end
53
54
 
54
55
  def hash_check(html, href_hash)
@@ -1,5 +1,5 @@
1
1
  module HTML
2
2
  class Proofer
3
- VERSION = "0.3.0"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
@@ -0,0 +1,2 @@
1
+
2
+ <ing alt="sure thing" src="assets/barrel.png">Folder relative to self</a>
@@ -2,8 +2,9 @@
2
2
 
3
3
  <body>
4
4
 
5
- <p>Blah blah blah. <a href="http://www.capify.org/">This is a redirect.</a>. </p>
5
+ <p>Blah blah blah. <a href="http://github.github.com/github-flavored-markdown/">This is a redirect.</a>. </p>
6
6
 
7
+ <p>Blah blah blah. <a href="https://help.github.com/changing-author-info/">This is another redirect.</a>. </p>
7
8
  </body>
8
9
 
9
- </html>
10
+ </html>
@@ -2,3 +2,5 @@
2
2
  <a href="index.html">Relative to self</a>
3
3
  <a href="folder/">Folder relative to self</a>
4
4
  <a href="index.html#anchor">Anchor relative to self</a>
5
+
6
+ <img alt="sure thing" src="gpl.png"/>Relative to self
@@ -0,0 +1,5 @@
1
+ <img src="assets/pro-git.jpg" alt="Pro Git">
2
+
3
+ <img src="assets/getting-good-with-git.jpg" alt="Getting Good with Git">
4
+
5
+ <img src="assets/version-control-with-git.jpg" alt="Version Control with Git, 2nd Edition">
@@ -0,0 +1,2 @@
1
+
2
+ <img alt="sure thing" src="/gpl.png"/>Relative to root
@@ -3,59 +3,59 @@ require "spec_helper"
3
3
  describe "Image tests" do
4
4
  it "passes for existing external images" do
5
5
  externalImageFilepath = "#{FIXTURES_DIR}/existingImageExternal.html"
6
- @imageCheck = Images.new("#{FIXTURES_DIR}", externalImageFilepath, HTML::Proofer.create_nokogiri(externalImageFilepath))
7
- @imageCheck.run
8
- @imageCheck.issues[0].should eq(nil)
6
+ output = capture_stderr { HTML::Proofer.new(externalImageFilepath).run }
7
+ output.should == ""
9
8
  end
10
9
 
11
10
  it "fails for image without alt attribute" do
12
11
  missingAltFilepath = "#{FIXTURES_DIR}/missingImageAlt.html"
13
- @imageCheck = Images.new("#{FIXTURES_DIR}", missingAltFilepath, HTML::Proofer.create_nokogiri(missingAltFilepath))
14
- @imageCheck.run
15
- @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/missingImageAlt.html".blue + ": image ./gpl.png does not have an alt attribute")
12
+ output = capture_stderr { HTML::Proofer.new(missingAltFilepath).run }
13
+ output.should match /gpl.png does not have an alt attribute/
16
14
  end
17
15
 
18
16
  it "fails for image with an empty alt attribute" do
19
17
  missingAltFilepath = "#{FIXTURES_DIR}/missingImageAltText.html"
20
- @imageCheck = Images.new("#{FIXTURES_DIR}", missingAltFilepath, HTML::Proofer.create_nokogiri(missingAltFilepath))
21
- @imageCheck.run
22
- @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/missingImageAltText.html".blue + ": image ./gpl.png does not have an alt attribute")
18
+ output = capture_stderr { HTML::Proofer.new(missingAltFilepath).run }
19
+ output.should match /gpl.png does not have an alt attribute/
23
20
  end
24
21
 
25
22
  it "fails for missing external images" do
26
23
  externalImageFilepath = "#{FIXTURES_DIR}/missingImageExternal.html"
27
- @imageCheck = Images.new("#{FIXTURES_DIR}", externalImageFilepath, HTML::Proofer.create_nokogiri(externalImageFilepath))
28
- @imageCheck.run
29
- @imageCheck.hydra.run
30
- @imageCheck.issues[0].sub!(/ #<Typhoeus::Response:[\w]+>/, "")
31
- @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/missingImageExternal.html".blue + ": external image http://www.whatthehell does not exist. Couldn't resolve host name!")
24
+ output = capture_stderr { HTML::Proofer.new(externalImageFilepath).run }
25
+ output.should match /External link http:\/\/www.whatthehell\/? failed: 0 Couldn't resolve host/
32
26
  end
33
27
 
34
28
  it "fails for missing internal images" do
35
29
  internalImageFilepath = "#{FIXTURES_DIR}/missingImageInternal.html"
36
- @imageCheck = Images.new("#{FIXTURES_DIR}", internalImageFilepath, HTML::Proofer.create_nokogiri(internalImageFilepath))
37
- @imageCheck.run
38
- @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/missingImageInternal.html".blue + ": internal image ./doesnotexist.png does not exist")
30
+ output = capture_stderr { HTML::Proofer.new(internalImageFilepath).run }
31
+ output.should match /doesnotexist.png does not exist/
39
32
  end
40
33
 
41
34
  it "fails for image with no src" do
42
35
  imageSrcFilepath = "#{FIXTURES_DIR}/missingImageSrc.html"
43
- @imageCheck = Images.new("#{FIXTURES_DIR}", imageSrcFilepath, HTML::Proofer.create_nokogiri(imageSrcFilepath))
44
- @imageCheck.run
45
- @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/missingImageSrc.html".blue + ": image has no src attribute")
36
+ output = capture_stderr { HTML::Proofer.new(imageSrcFilepath).run }
37
+ output.should match /image has no src attribute/
46
38
  end
47
39
 
48
40
  it "fails for image with default mac filename" do
49
41
  terribleImageName = "#{FIXTURES_DIR}/terribleImageName.html"
50
- @imageCheck = Images.new("#{FIXTURES_DIR}", terribleImageName, HTML::Proofer.create_nokogiri(terribleImageName))
51
- @imageCheck.run
52
- @imageCheck.issues[0].should eq("spec/html/proofer/fixtures/terribleImageName.html".blue + ": image has a terrible filename (./Screen Shot 2012-08-09 at 7.51.18 AM.png)")
42
+ output = capture_stderr { HTML::Proofer.new(terribleImageName).run }
43
+ output.should match /image has a terrible filename/
53
44
  end
54
45
 
55
46
  it 'ignores images marked as ignore data-proofer-ignore' do
56
47
  ignorableImages = "#{FIXTURES_DIR}/ignorableImages.html"
57
- @linkCheck = Links.new("#{FIXTURES_DIR}", ignorableImages, HTML::Proofer.create_nokogiri(ignorableImages))
58
- @linkCheck.run
59
- @linkCheck.issues[0].should eq(nil)
48
+ output = capture_stderr { HTML::Proofer.new(ignorableImages).run }
49
+ output.should == ""
50
+ end
51
+
52
+ it 'properly checks relative images' do
53
+ relativeImages = "#{FIXTURES_DIR}/rootRelativeImages.html"
54
+ output = capture_stderr { HTML::Proofer.new(relativeImages).run }
55
+ output.should == ""
56
+
57
+ relativeImages = "#{FIXTURES_DIR}/resources/books/nestedRelativeImages.html"
58
+ output = capture_stderr { HTML::Proofer.new(relativeImages).run }
59
+ output.should == ""
60
60
  end
61
61
  end
@@ -4,94 +4,79 @@ describe "Links tests" do
4
4
 
5
5
  it "fails for broken external hash (even if the file exists)" do
6
6
  brokenHashExternalFilepath = "#{FIXTURES_DIR}/brokenHashExternal.html"
7
- @linkCheck = Links.new("#{FIXTURES_DIR}", brokenHashExternalFilepath, HTML::Proofer.create_nokogiri(brokenHashExternalFilepath))
8
- @linkCheck.run
9
- @linkCheck.issues[1].should eq("spec/html/proofer/fixtures/brokenHashExternal.html".blue + ": linking to ./missingImageAlt.html#asdfasfdkafl, but asdfasfdkafl does not exist")
7
+ output = capture_stderr { HTML::Proofer.new(brokenHashExternalFilepath).run }
8
+ output.should match /linking to .\/missingImageAlt.html#asdfasfdkafl, but asdfasfdkafl does not exist/
10
9
  end
11
10
 
12
11
  it "fails for broken internal hash" do
13
12
  brokenHashInternalFilepath = "#{FIXTURES_DIR}/brokenHashInternal.html"
14
- @linkCheck = Links.new("#{FIXTURES_DIR}", brokenHashInternalFilepath, HTML::Proofer.create_nokogiri(brokenHashInternalFilepath))
15
- @linkCheck.run
16
- @linkCheck.issues[0].should eq("spec/html/proofer/fixtures/brokenHashInternal.html".blue + ": linking to internal hash #noHash that does not exist")
13
+ output = capture_stderr { HTML::Proofer.new(brokenHashInternalFilepath).run }
14
+ output.should match /linking to internal hash #noHash that does not exist/
17
15
  end
18
16
 
19
17
  it "fails for broken external links" do
20
18
  brokenLinkExternalFilepath = "#{FIXTURES_DIR}/brokenLinkExternal.html"
21
- @linkCheck = Links.new("#{FIXTURES_DIR}", brokenLinkExternalFilepath, HTML::Proofer.create_nokogiri(brokenLinkExternalFilepath))
22
- @linkCheck.run
23
- @linkCheck.hydra.run
24
- @linkCheck.issues[0].sub!(/ #<Typhoeus::Response:[\w]+>/, "")
25
- @linkCheck.issues[0].should eq("spec/html/proofer/fixtures/brokenLinkExternal.html".blue + ": externally linking to http://www.asdo3IRJ395295jsingrkrg4.com, which does not exist. Couldn't resolve host name!")
19
+ output = capture_stderr { HTML::Proofer.new(brokenLinkExternalFilepath).run }
20
+ output.should match /External link http:\/\/www.asdo3IRJ395295jsingrkrg4.com\/? failed: 0 Couldn't resolve host name/
26
21
  end
27
22
 
28
23
  it "fails for broken internal links" do
29
24
  brokenLinkInternalFilepath = "#{FIXTURES_DIR}/brokenLinkInternal.html"
30
- @linkCheck = Links.new("#{FIXTURES_DIR}", brokenLinkInternalFilepath, HTML::Proofer.create_nokogiri(brokenLinkInternalFilepath))
31
- @linkCheck.run
32
- @linkCheck.issues[0].should eq("spec/html/proofer/fixtures/brokenLinkInternal.html".blue + ": internally linking to ./notreal.html, which does not exist")
25
+ output = capture_stderr { HTML::Proofer.new(brokenLinkInternalFilepath).run }
26
+ output.should match /internally linking to .\/notreal.html, which does not exist/
33
27
  end
34
28
 
35
29
  it "fails for link with no href" do
36
30
  missingLinkHrefFilepath = "#{FIXTURES_DIR}/missingLinkHref.html"
37
- @linkCheck = Links.new("#{FIXTURES_DIR}", missingLinkHrefFilepath, HTML::Proofer.create_nokogiri(missingLinkHrefFilepath))
38
- @linkCheck.run
39
- @linkCheck.issues[0].should eq("spec/html/proofer/fixtures/missingLinkHref.html".blue + ": link has no href attribute")
31
+ output = capture_stderr { HTML::Proofer.new(missingLinkHrefFilepath).run }
32
+ output.should match /link has no href attribute/
40
33
  end
41
34
 
42
35
  it "should follow redirects" do
43
36
  linkWithRedirectFilepath = "#{FIXTURES_DIR}/linkWithRedirect.html"
44
- @linkCheck = Links.new("#{FIXTURES_DIR}", linkWithRedirectFilepath, HTML::Proofer.create_nokogiri(linkWithRedirectFilepath))
45
- @linkCheck.run
46
- @linkCheck.issues[0].should eq(nil)
37
+ output = capture_stderr { HTML::Proofer.new(linkWithRedirectFilepath).run }
38
+ output.should == ""
47
39
  end
48
40
 
49
41
  it "should understand https" do
50
42
  linkWithHttpsFilepath = "#{FIXTURES_DIR}/linkWithHttps.html"
51
- @linkCheck = Links.new("#{FIXTURES_DIR}", linkWithHttpsFilepath, HTML::Proofer.create_nokogiri(linkWithHttpsFilepath))
52
- @linkCheck.run
53
- @linkCheck.issues[0].should eq(nil)
43
+ output = capture_stderr { HTML::Proofer.new(linkWithHttpsFilepath).run }
44
+ output.should == ""
54
45
  end
55
46
 
56
47
  it "fails for broken hash links with status code numbers" do
57
48
  brokenLinkWithNumberFilepath = "#{FIXTURES_DIR}/brokenLinkWithNumber.html"
58
- @linkCheck = Links.new("#{FIXTURES_DIR}", brokenLinkWithNumberFilepath, HTML::Proofer.create_nokogiri(brokenLinkWithNumberFilepath))
59
- @linkCheck.run
60
- @linkCheck.issues[0].should eq("\e[34mspec/html/proofer/fixtures/brokenLinkWithNumber.html\e[0m: linking to internal hash #25-method-not-allowed that does not exist")
49
+ output = capture_stderr { HTML::Proofer.new(brokenLinkWithNumberFilepath).run }
50
+ output.should match /linking to internal hash #25-method-not-allowed that does not exist/
61
51
  end
62
52
 
63
53
  it 'properly resolves implicit /index.html in link paths' do
64
54
  linkToFolder = "#{FIXTURES_DIR}/linkToFolder.html"
65
- @linkCheck = Links.new("#{FIXTURES_DIR}", linkToFolder, HTML::Proofer.create_nokogiri(linkToFolder))
66
- @linkCheck.run
67
- @linkCheck.issues[0].should eq(nil)
55
+ output = capture_stderr { HTML::Proofer.new(linkToFolder).run }
56
+ output.should == ""
68
57
  end
69
58
 
70
59
  it 'properly checks links to root' do
71
60
  rootLink = "#{FIXTURES_DIR}/rootLink.html"
72
- @linkCheck = Links.new("#{FIXTURES_DIR}", rootLink, HTML::Proofer.create_nokogiri(rootLink))
73
- @linkCheck.run
74
- @linkCheck.issues[0].should eq(nil)
61
+ output = capture_stderr { HTML::Proofer.new(rootLink).run }
62
+ output.should == ""
75
63
  end
76
64
 
77
65
  it 'properly checks relative links' do
78
66
  relativeLinks = "#{FIXTURES_DIR}/relativeLinks.html"
79
- @linkCheck = Links.new("#{FIXTURES_DIR}", relativeLinks, HTML::Proofer.create_nokogiri(relativeLinks))
80
- @linkCheck.run
81
- @linkCheck.issues[0].should eq(nil)
67
+ output = capture_stderr { HTML::Proofer.new(relativeLinks).run }
68
+ output.should == ""
82
69
  end
83
70
 
84
71
  it 'ignores links marked as ignore data-proofer-ignore' do
85
72
  ignorableLinks = "#{FIXTURES_DIR}/ignorableLinks.html"
86
- @linkCheck = Links.new("#{FIXTURES_DIR}", ignorableLinks, HTML::Proofer.create_nokogiri(ignorableLinks))
87
- @linkCheck.run
88
- @linkCheck.issues[0].should eq(nil)
73
+ output = capture_stderr { HTML::Proofer.new(ignorableLinks).run }
74
+ output.should == ""
89
75
  end
90
76
 
91
77
  it 'translates links via href_swap' do
92
78
  translatedLink = "#{FIXTURES_DIR}/linkTranslatedViaHrefSwap.html"
93
- @linkCheck = Links.new("#{FIXTURES_DIR}", translatedLink, HTML::Proofer.create_nokogiri(translatedLink), {:href_swap => { /\A\/articles\/([\w-]+)/ => "\\1.html" }})
94
- @linkCheck.run
95
- @linkCheck.issues[0].should eq(nil)
79
+ output = capture_stderr { HTML::Proofer.new(translatedLink, {:href_swap => { /\A\/articles\/([\w-]+)/ => "\\1.html" }}).run }
80
+ output.should == ""
96
81
  end
97
82
  end
data/spec/spec_helper.rb CHANGED
@@ -14,4 +14,19 @@ RSpec.configure do |config|
14
14
 
15
15
  # Use the specified formatter
16
16
  config.formatter = :documentation # :progress, :html, :textmate
17
- end
17
+ end
18
+
19
+ def capture_stderr(&block)
20
+ original_stderr = $stderr
21
+ original_stdout = $stdout
22
+ $stderr = fake_err = StringIO.new
23
+ $stdout = fake_out = StringIO.new
24
+ begin
25
+ yield
26
+ rescue RuntimeError
27
+ ensure
28
+ $stderr = original_stderr
29
+ # $stdout = original_stdout
30
+ end
31
+ fake_err.string
32
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html-proofer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen Torikian
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-05 00:00:00.000000000 Z
11
+ date: 2013-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mercenary
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 0.6.3
61
+ version: 0.6.7
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ~>
67
67
  - !ruby/object:Gem::Version
68
- version: 0.6.3
68
+ version: 0.6.7
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: html-pipeline
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -140,7 +140,9 @@ files:
140
140
  - spec/html/proofer/fixtures/brokenLinkWithNumber.html
141
141
  - spec/html/proofer/fixtures/existingImageExternal.html
142
142
  - spec/html/proofer/fixtures/folder/anchorLink.html
143
+ - spec/html/proofer/fixtures/folder/assets/barrel.png
143
144
  - spec/html/proofer/fixtures/folder/index.html
145
+ - spec/html/proofer/fixtures/folder/relativeImage.html
144
146
  - spec/html/proofer/fixtures/gpl.png
145
147
  - spec/html/proofer/fixtures/ignorableImages.html
146
148
  - spec/html/proofer/fixtures/ignorableLinks.html
@@ -157,7 +159,12 @@ files:
157
159
  - spec/html/proofer/fixtures/missingLinkHref.html
158
160
  - spec/html/proofer/fixtures/notarealhash.html
159
161
  - spec/html/proofer/fixtures/relativeLinks.html
162
+ - spec/html/proofer/fixtures/resources/books/assets/getting-good-with-git.jpg
163
+ - spec/html/proofer/fixtures/resources/books/assets/pro-git.jpg
164
+ - spec/html/proofer/fixtures/resources/books/assets/version-control-with-git.jpg
165
+ - spec/html/proofer/fixtures/resources/books/nestedRelativeImages.html
160
166
  - spec/html/proofer/fixtures/rootLink.html
167
+ - spec/html/proofer/fixtures/rootRelativeImages.html
161
168
  - spec/html/proofer/fixtures/terribleImageName.html
162
169
  - spec/html/proofer/images_spec.rb
163
170
  - spec/html/proofer/links_spec.rb
@@ -199,7 +206,9 @@ test_files:
199
206
  - spec/html/proofer/fixtures/brokenLinkWithNumber.html
200
207
  - spec/html/proofer/fixtures/existingImageExternal.html
201
208
  - spec/html/proofer/fixtures/folder/anchorLink.html
209
+ - spec/html/proofer/fixtures/folder/assets/barrel.png
202
210
  - spec/html/proofer/fixtures/folder/index.html
211
+ - spec/html/proofer/fixtures/folder/relativeImage.html
203
212
  - spec/html/proofer/fixtures/gpl.png
204
213
  - spec/html/proofer/fixtures/ignorableImages.html
205
214
  - spec/html/proofer/fixtures/ignorableLinks.html
@@ -216,7 +225,12 @@ test_files:
216
225
  - spec/html/proofer/fixtures/missingLinkHref.html
217
226
  - spec/html/proofer/fixtures/notarealhash.html
218
227
  - spec/html/proofer/fixtures/relativeLinks.html
228
+ - spec/html/proofer/fixtures/resources/books/assets/getting-good-with-git.jpg
229
+ - spec/html/proofer/fixtures/resources/books/assets/pro-git.jpg
230
+ - spec/html/proofer/fixtures/resources/books/assets/version-control-with-git.jpg
231
+ - spec/html/proofer/fixtures/resources/books/nestedRelativeImages.html
219
232
  - spec/html/proofer/fixtures/rootLink.html
233
+ - spec/html/proofer/fixtures/rootRelativeImages.html
220
234
  - spec/html/proofer/fixtures/terribleImageName.html
221
235
  - spec/html/proofer/images_spec.rb
222
236
  - spec/html/proofer/links_spec.rb