html-proofer 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -4
- data/README.md +25 -4
- data/Rakefile +16 -1
- data/bin/htmlproof +6 -3
- data/html-proofer.gemspec +3 -3
- data/lib/html/proofer.rb +68 -37
- data/lib/html/proofer/check.rb +2 -3
- data/lib/html/proofer/checkable.rb +22 -24
- data/lib/html/proofer/checks.rb +7 -6
- data/lib/html/proofer/checks/favicon.rb +2 -1
- data/lib/html/proofer/checks/links.rb +1 -5
- data/lib/html/proofer/issue.rb +21 -0
- data/spec/html/proofer/favicon_spec.rb +2 -2
- data/spec/html/proofer/fixtures/links/broken_hash_with_query.html +9 -0
- data/spec/html/proofer/fixtures/links/escape_pipes.html +9 -0
- data/spec/html/proofer/fixtures/links/folder/index.php +2 -0
- data/spec/html/proofer/fixtures/links/link_pointing_to_directory.html +1 -0
- data/spec/html/proofer/links_spec.rb +29 -3
- data/spec/spec_helper.rb +3 -0
- metadata +25 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65597a503b7fc561c9dae5377f36dd3860581a92
|
4
|
+
data.tar.gz: 44f24659044b6122d43476be9f41c3be1f8633b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06b4ec0986dc6cd27575d65f73a29d00c2166b0e4b8c15e4b15d345a90ea382f4b6710d8cc67ff476debee80867e0489181bf65bb9f22e4b2ae2eb6eff958425
|
7
|
+
data.tar.gz: a14622a437b34deee71d3a6c0daf42f466d35a980531993d505a5c72c736c7a640da2ff9992d46063b5674334bf28e3d5422a9ce1e800b1533d863be05b99e97
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,7 @@ If you generate HTML files, _then this tool might be for you_.
|
|
4
4
|
|
5
5
|
`HTML::Proofer` is a set of tests to validate your HTML output. These tests check if your image references are legitimate, if they have alt tags, if your internal links are working, and so on. It's intended to be an all-in-one checker for your output.
|
6
6
|
|
7
|
-
[![Build Status](https://travis-ci.org/gjtorikian/html-proofer.
|
7
|
+
[![Build Status](https://travis-ci.org/gjtorikian/html-proofer.svg?branch=master)](https://travis-ci.org/gjtorikian/html-proofer) [![Gem Version](https://badge.fury.io/rb/html-proofer.svg)](http://badge.fury.io/rb/html-proofer)
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
@@ -58,7 +58,7 @@ HTML::Proofer.new("./out").run
|
|
58
58
|
|
59
59
|
### Using on the command-line
|
60
60
|
|
61
|
-
You'll get a new program called `htmlproof` with this gem.
|
61
|
+
You'll get a new program called `htmlproof` with this gem. Terrific!
|
62
62
|
|
63
63
|
Use it like you'd expect to:
|
64
64
|
|
@@ -90,6 +90,14 @@ Don't have or want a `Rakefile`? You _could_ also do something like the followin
|
|
90
90
|
htmlproof ./_site
|
91
91
|
```
|
92
92
|
|
93
|
+
### Real-life examples
|
94
|
+
|
95
|
+
Project | Repository
|
96
|
+
:--- | :---
|
97
|
+
[Raspberry Pi documentation](http://www.raspberrypi.org/documentation/) | [raspberrypi/documentation]( https://github.com/raspberrypi/documentation)
|
98
|
+
[Open Whisper Systems website](https://whispersystems.org/) | [WhisperSystems/whispersystems.org](https://github.com/WhisperSystems/whispersystems.org)
|
99
|
+
[Jekyll website](http://jekyllrb.com/) | [jekyll/jekyll](https://github.com/jekyll/jekyll)
|
100
|
+
|
93
101
|
## What's Tested?
|
94
102
|
|
95
103
|
### Images
|
@@ -124,20 +132,33 @@ The `HTML::Proofer` constructor takes an optional hash of additional options:
|
|
124
132
|
| `ext` | The extension of your HTML files including the dot. | `.html`
|
125
133
|
| `favicon` | Enables the favicon checker. | `false` |
|
126
134
|
| `followlocation` | Follows external redirections. Amends missing trailing slashes to internal directories. | `true` |
|
127
|
-
| `
|
135
|
+
| `directory_index_file` | Sets the file to look for when a link refers to a directory. | `index.html` |
|
128
136
|
| `href_ignore` | An array of Strings or RegExps containing `href`s that are safe to ignore. Certain URIs, like `mailto` and `tel`, are always ignored. | `[]` |
|
129
137
|
| `alt_ignore` | An array of Strings or RegExps containing `img`s whose missing `alt` tags are safe to ignore. | `[]` |
|
130
138
|
| `href_swap` | A hash containing key-value pairs of `RegExp => String`. It transforms links that match `RegExp` into `String` via `gsub`. | `{}` |
|
131
139
|
| `verbose` | If `true`, outputs extra information as the checking happens. Useful for debugging. | `false` |
|
140
|
+
| `only_4xx` | Only reports errors for links that fall within the 4xx status code range. | `false` |
|
132
141
|
|
133
142
|
You can also pass in any of Typhoeus' options for the external link check. For example:
|
134
143
|
|
135
144
|
``` ruby
|
136
|
-
HTML::Proofer.new("out/", {:ext => ".htm", :verbose
|
145
|
+
HTML::Proofer.new("out/", {:ext => ".htm", :verbose => true, :ssl_verifyhost => 2 })
|
137
146
|
```
|
138
147
|
|
139
148
|
This sets `HTML::Proofer`'s extensions to use _.htm_, and gives Typhoeus a configuration 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.
|
140
149
|
|
150
|
+
Instead of a directory as the first argument, you can also pass in an array of links:
|
151
|
+
|
152
|
+
``` ruby
|
153
|
+
HTML::Proofer.new(["http://github.com", "http://jekyllrb.com"])
|
154
|
+
```
|
155
|
+
|
156
|
+
This configures Proofer to just test those links to ensure they are valid. Note that for the command-line, you'll need to pass a special `--as-links` argument:
|
157
|
+
|
158
|
+
``` bash
|
159
|
+
bin/htmlproof www.google.com,www.github.com --as-links
|
160
|
+
```
|
161
|
+
|
141
162
|
## Ignoring content
|
142
163
|
|
143
164
|
Add the `data-proofer-ignore` attribute to any tag to ignore it from the checks.
|
data/Rakefile
CHANGED
@@ -5,4 +5,19 @@ require 'rspec/core/rake_task'
|
|
5
5
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec)
|
7
7
|
|
8
|
-
task :default => :spec
|
8
|
+
task :default => [:spec, :proof_readme]
|
9
|
+
|
10
|
+
task :proof_readme do
|
11
|
+
require 'html/proofer'
|
12
|
+
require 'redcarpet'
|
13
|
+
|
14
|
+
redcarpet = Redcarpet::Markdown.new Redcarpet::Render::HTML.new({}), {}
|
15
|
+
html = redcarpet.render File.open("README.md").read
|
16
|
+
|
17
|
+
mkdir_p "out"
|
18
|
+
File.open "out/README.html", File::CREAT|File::WRONLY do |file|
|
19
|
+
file.puts html
|
20
|
+
end
|
21
|
+
|
22
|
+
HTML::Proofer.new("./out").run
|
23
|
+
end
|
data/bin/htmlproof
CHANGED
@@ -16,12 +16,14 @@ Mercenary.program(:htmlproof) do |p|
|
|
16
16
|
|
17
17
|
p.option 'ext', '--ext EXT', 'The extension of your HTML files (default: `.html`)'
|
18
18
|
p.option 'favicon', '--favicon', 'Enables the favicon checker (default: `false`).'
|
19
|
-
p.option 'as-links', '--as-links', 'Assumes that `PATH` is
|
19
|
+
p.option 'as-links', '--as-links', 'Assumes that `PATH` is a comma-separated array of links to check.'
|
20
20
|
p.option 'swap', '--swap regex:string,[regex:string,...]', Array, 'Array containing key-value pairs of `RegExp:String`. It transforms links that match `RegExp` into `String`'
|
21
21
|
p.option 'href_ignore', '--href_ignore link1,[link2,...]', Array, 'Array of Strings containing `href`s that are safe to ignore. Certain URIs, like `mailto` and `tel`, are always ignored.'
|
22
22
|
p.option 'alt_ignore', '--alt_ignore image1,[image2,...]', Array, 'Array of Strings containing `img`s whose missing `alt` tags are safe to ignore'
|
23
23
|
p.option 'disable_external', '--disable_external', 'Disables the external link checker (default: `false`)'
|
24
|
+
p.option 'only-4xx', '--only-4xx', 'Only reports errors for links that fall within the 4x status code range.'
|
24
25
|
p.option 'verbose', '--verbose', 'Enables more verbose logging.'
|
26
|
+
p.option 'directory_index_file', '--directory_index_file', 'Sets the file to look for when a link refers to a directory.'
|
25
27
|
|
26
28
|
p.action do |args, opts|
|
27
29
|
args = ["."] if args.empty?
|
@@ -36,14 +38,15 @@ Mercenary.program(:htmlproof) do |p|
|
|
36
38
|
options[:href_swap][%r{#{pair[0]}}] = pair[1]
|
37
39
|
end
|
38
40
|
end
|
39
|
-
|
41
|
+
|
40
42
|
options[:href_ignore] = opts["href_ignore"] unless opts["href_ignore"].nil?
|
41
43
|
options[:alt_ignore] = opts["alt_ignore"] unless opts["alt_ignore"].nil?
|
42
44
|
options[:disable_external] = opts["disable_external"] unless opts["disable_external"].nil?
|
43
45
|
options[:favicon] = opts["favicon"] unless opts["favicon"].nil?
|
44
46
|
options[:verbose] = opts["verbose"] unless opts["verbose"].nil?
|
47
|
+
options[:directory_index_file] = opts["directory_index_file"] unless opts["directory_index_file"].nil?
|
45
48
|
|
46
|
-
path = path.delete(' ').split(",") if
|
49
|
+
path = path.delete(' ').split(",") if opts["as-links"]
|
47
50
|
|
48
51
|
HTML::Proofer.new(path, options).run
|
49
52
|
end
|
data/html-proofer.gemspec
CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.name = "html-proofer"
|
6
|
-
gem.version = "1.
|
6
|
+
gem.version = "1.3.0"
|
7
7
|
gem.authors = ["Garen Torikian"]
|
8
8
|
gem.email = ["gjtorikian@gmail.com"]
|
9
9
|
gem.description = %q{Test your rendered HTML files to make sure they're accurate.}
|
@@ -21,8 +21,8 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.add_dependency "typhoeus", "~> 0.6.7"
|
22
22
|
gem.add_dependency "yell", "~> 2.0"
|
23
23
|
|
24
|
-
gem.add_development_dependency "
|
25
|
-
gem.add_development_dependency "escape_utils", "~> 1.0" # Ruby 2.1 fix
|
24
|
+
gem.add_development_dependency "redcarpet"
|
26
25
|
gem.add_development_dependency "rspec", "~> 2.13.0"
|
27
26
|
gem.add_development_dependency "rake"
|
27
|
+
gem.add_development_dependency "awesome_print"
|
28
28
|
end
|
data/lib/html/proofer.rb
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
require 'nokogiri'
|
2
2
|
require 'yell'
|
3
3
|
|
4
|
-
|
5
|
-
require
|
4
|
+
begin
|
5
|
+
require "awesome_print"
|
6
|
+
rescue LoadError; end
|
7
|
+
|
8
|
+
[
|
9
|
+
'checkable',
|
10
|
+
'checks',
|
11
|
+
'issue'
|
12
|
+
].each { |r| require File.join(File.dirname(__FILE__), "proofer", r) }
|
6
13
|
|
7
14
|
module HTML
|
15
|
+
|
16
|
+
def self.colorize(color, string)
|
17
|
+
if $stdout.isatty && $stderr.isatty
|
18
|
+
Colored.colorize(string, :foreground => color)
|
19
|
+
else
|
20
|
+
string
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
8
24
|
class Proofer
|
9
25
|
include Yell::Loggable
|
10
26
|
|
11
|
-
attr_accessor :failed_tests
|
12
|
-
|
13
27
|
def initialize(src, opts={})
|
14
28
|
@src = src
|
15
29
|
|
@@ -21,9 +35,23 @@ module HTML
|
|
21
35
|
:alt_ignore => [],
|
22
36
|
:disable_external => false,
|
23
37
|
:verbose => false,
|
24
|
-
:
|
38
|
+
:only_4xx => false,
|
39
|
+
:directory_index_file => "index.html"
|
40
|
+
}
|
41
|
+
|
42
|
+
@typhoeus_opts = {
|
43
|
+
:followlocation => true
|
25
44
|
}
|
26
|
-
|
45
|
+
|
46
|
+
# Typhoeus won't let you pass any non-Typhoeus option
|
47
|
+
opts.keys.each do |key|
|
48
|
+
unless @typhoeus_opts[key].nil?
|
49
|
+
@typhoeus_opts[key] = opts[key]
|
50
|
+
@proofer_opts[key] = opts[key]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
@options = @proofer_opts.merge(@typhoeus_opts).merge(opts)
|
27
55
|
|
28
56
|
@failed_tests = []
|
29
57
|
|
@@ -34,18 +62,18 @@ module HTML
|
|
34
62
|
end
|
35
63
|
|
36
64
|
def run
|
37
|
-
unless @
|
65
|
+
unless @src.is_a? Array
|
38
66
|
total_files = 0
|
39
67
|
external_urls = {}
|
40
68
|
|
41
|
-
logger.info colorize :white, "Running #{get_checks} checks on #{@src} on *#{@options[:ext]}... \n\n"
|
69
|
+
logger.info HTML::colorize :white, "Running #{get_checks} checks on #{@src} on *#{@options[:ext]}... \n\n"
|
42
70
|
|
43
71
|
files.each do |path|
|
44
72
|
total_files += 1
|
45
73
|
html = HTML::Proofer.create_nokogiri(path)
|
46
74
|
|
47
75
|
get_checks.each do |klass|
|
48
|
-
logger.debug colorize :blue, "Checking #{klass.to_s.downcase} on #{path} ..."
|
76
|
+
logger.debug HTML::colorize :blue, "Checking #{klass.to_s.downcase} on #{path} ..."
|
49
77
|
check = Object.const_get(klass).new(@src, path, html, @options)
|
50
78
|
check.run
|
51
79
|
external_urls.merge!(check.external_urls)
|
@@ -55,20 +83,20 @@ module HTML
|
|
55
83
|
|
56
84
|
external_link_checker(external_urls) unless @options[:disable_external]
|
57
85
|
|
58
|
-
logger.info colorize :green, "Ran on #{total_files} files!\n\n"
|
86
|
+
logger.info HTML::colorize :green, "Ran on #{total_files} files!\n\n"
|
59
87
|
else
|
60
88
|
external_urls = Hash[*@src.map{ |s| [s, nil] }.flatten]
|
61
89
|
external_link_checker(external_urls) unless @options[:disable_external]
|
62
90
|
end
|
63
91
|
|
64
92
|
if @failed_tests.empty?
|
65
|
-
logger.info colorize :green, "HTML-Proofer finished successfully."
|
93
|
+
logger.info HTML::colorize :green, "HTML-Proofer finished successfully."
|
66
94
|
else
|
67
|
-
@failed_tests.
|
68
|
-
logger.error colorize :red, issue.to_s
|
95
|
+
@failed_tests.sort_by(&:path).each do |issue|
|
96
|
+
logger.error HTML::colorize :red, issue.to_s
|
69
97
|
end
|
70
98
|
|
71
|
-
raise colorize :red, "HTML-Proofer found #{@failed_tests.length} failures!"
|
99
|
+
raise HTML::colorize :red, "HTML-Proofer found #{@failed_tests.length} failures!"
|
72
100
|
end
|
73
101
|
end
|
74
102
|
|
@@ -80,24 +108,19 @@ module HTML
|
|
80
108
|
def external_link_checker(external_urls)
|
81
109
|
external_urls = Hash[external_urls.sort]
|
82
110
|
|
83
|
-
logger.info colorize :yellow, "Checking #{external_urls.length} external links..."
|
84
|
-
|
85
|
-
# Typhoeus won't let you pass any non-Typhoeus option
|
86
|
-
@proofer_opts.each_key do |opt|
|
87
|
-
@options.delete opt
|
88
|
-
end
|
111
|
+
logger.info HTML::colorize :yellow, "Checking #{external_urls.length} external links..."
|
89
112
|
|
90
113
|
Ethon.logger = logger # log from Typhoeus/Ethon
|
91
114
|
|
92
115
|
external_urls.each_pair do |href, filenames|
|
93
116
|
queue_request(:head, href, filenames)
|
94
117
|
end
|
95
|
-
logger.debug colorize :yellow, "Running requests for all #{hydra.queued_requests.size} external URLs..."
|
118
|
+
logger.debug HTML::colorize :yellow, "Running requests for all #{hydra.queued_requests.size} external URLs..."
|
96
119
|
hydra.run
|
97
120
|
end
|
98
121
|
|
99
122
|
def queue_request(method, href, filenames)
|
100
|
-
request = Typhoeus::Request.new(href, @
|
123
|
+
request = Typhoeus::Request.new(href, @typhoeus_opts.merge({:method => method}))
|
101
124
|
request.on_complete { |response| response_handler(response, filenames) }
|
102
125
|
hydra.queue request
|
103
126
|
end
|
@@ -114,9 +137,8 @@ module HTML
|
|
114
137
|
if response_code.between?(200, 299)
|
115
138
|
# continue with no op
|
116
139
|
elsif response.timed_out?
|
117
|
-
|
118
|
-
|
119
|
-
@failed_tests << failed_test_msg
|
140
|
+
return if @options[:only_4xx]
|
141
|
+
add_failed_tests filenames, "External link #{href} failed: got a time out", response_code
|
120
142
|
elsif (response_code == 405 || response_code == 420 || response_code == 503) && method == :head
|
121
143
|
# 420s usually come from rate limiting; let's ignore the query and try just the path with a GET
|
122
144
|
uri = URI(href)
|
@@ -126,10 +148,9 @@ module HTML
|
|
126
148
|
elsif method == :head
|
127
149
|
queue_request(:get, href, filenames)
|
128
150
|
else
|
151
|
+
return if @options[:only_4xx] && !response_code.between?(400, 499)
|
129
152
|
# Received a non-successful http response.
|
130
|
-
|
131
|
-
failed_test_msg.insert(0, "#{filenames.join(' ').blue}: ") unless filenames.nil?
|
132
|
-
@failed_tests << failed_test_msg
|
153
|
+
add_failed_tests filenames, "External link #{href} failed: #{response_code} #{response.return_message}", response_code
|
133
154
|
end
|
134
155
|
end
|
135
156
|
|
@@ -139,15 +160,16 @@ module HTML
|
|
139
160
|
|
140
161
|
def files
|
141
162
|
if File.directory? @src
|
142
|
-
Dir.glob(
|
163
|
+
Dir.glob File.join(@src, "**", "*#{@options[:ext]}")
|
164
|
+
elsif File.extname(@src) == @options[:ext]
|
165
|
+
[@src]
|
143
166
|
else
|
144
|
-
|
167
|
+
[]
|
145
168
|
end
|
146
169
|
end
|
147
170
|
|
148
171
|
def self.create_nokogiri(path)
|
149
|
-
|
150
|
-
content = File.open(path, "rb") {|f| f.read }
|
172
|
+
content = File.open(path).read
|
151
173
|
Nokogiri::HTML(content)
|
152
174
|
end
|
153
175
|
|
@@ -161,12 +183,21 @@ module HTML
|
|
161
183
|
@options[:verbose] ? :debug : :info
|
162
184
|
end
|
163
185
|
|
164
|
-
def
|
165
|
-
if
|
166
|
-
|
167
|
-
|
168
|
-
|
186
|
+
def add_failed_tests(filenames, desc, status = nil)
|
187
|
+
if filenames.nil?
|
188
|
+
@failed_tests << Checks::Issue.new("", desc, status)
|
189
|
+
elsif
|
190
|
+
filenames.each { |f|
|
191
|
+
@failed_tests << Checks::Issue.new(f, desc, status)
|
192
|
+
}
|
169
193
|
end
|
170
194
|
end
|
195
|
+
|
196
|
+
def failed_tests
|
197
|
+
return [] if @failed_tests.empty?
|
198
|
+
result = []
|
199
|
+
@failed_tests.each { |f| result << f.to_s }
|
200
|
+
result
|
201
|
+
end
|
171
202
|
end
|
172
203
|
end
|
data/lib/html/proofer/check.rb
CHANGED
@@ -3,7 +3,6 @@ require 'net/http'
|
|
3
3
|
require 'net/https'
|
4
4
|
require 'timeout'
|
5
5
|
require 'uri'
|
6
|
-
require 'colored'
|
7
6
|
require 'typhoeus'
|
8
7
|
|
9
8
|
class HTML::Proofer::Checks
|
@@ -27,8 +26,8 @@ class HTML::Proofer::Checks
|
|
27
26
|
raise NotImplementedError.new("HTML::Proofer::Check subclasses must implement #run")
|
28
27
|
end
|
29
28
|
|
30
|
-
def add_issue(desc)
|
31
|
-
@issues <<
|
29
|
+
def add_issue(desc, status = nil)
|
30
|
+
@issues << Issue.new(@path, desc, status)
|
32
31
|
end
|
33
32
|
|
34
33
|
def output_filenames
|
@@ -32,33 +32,30 @@ module HTML
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def valid?
|
35
|
-
|
36
|
-
URI.parse url
|
37
|
-
rescue
|
38
|
-
false
|
39
|
-
end
|
35
|
+
!parts.nil?
|
40
36
|
end
|
41
37
|
|
42
38
|
def parts
|
43
|
-
|
39
|
+
URI::Parser.new(:ESCAPED => '\%|\|').parse url
|
40
|
+
rescue URI::Error
|
41
|
+
nil
|
44
42
|
end
|
45
43
|
|
46
44
|
def path
|
47
|
-
parts.path
|
45
|
+
parts.path if !parts.nil?
|
48
46
|
end
|
49
47
|
|
50
48
|
def hash
|
51
|
-
parts.fragment
|
49
|
+
parts.fragment if !parts.nil?
|
50
|
+
end
|
51
|
+
|
52
|
+
def scheme
|
53
|
+
parts.scheme if !parts.nil?
|
52
54
|
end
|
53
55
|
|
54
56
|
# path is to an external server
|
55
57
|
def remote?
|
56
|
-
|
57
|
-
%w( http https ).include?(uri.scheme)
|
58
|
-
rescue URI::BadURIError
|
59
|
-
false
|
60
|
-
rescue URI::InvalidURIError
|
61
|
-
false
|
58
|
+
%w( http https ).include? scheme
|
62
59
|
end
|
63
60
|
|
64
61
|
def ignore?
|
@@ -74,12 +71,7 @@ module HTML
|
|
74
71
|
return true if ignores_pattern_check(@check.additional_alt_ignores)
|
75
72
|
end
|
76
73
|
|
77
|
-
|
78
|
-
%w( mailto tel ).include?(uri.scheme)
|
79
|
-
rescue URI::BadURIError
|
80
|
-
false
|
81
|
-
rescue URI::InvalidURIError
|
82
|
-
false
|
74
|
+
%w( mailto tel ).include? scheme
|
83
75
|
end
|
84
76
|
|
85
77
|
# path is external to the file
|
@@ -87,9 +79,9 @@ module HTML
|
|
87
79
|
!internal?
|
88
80
|
end
|
89
81
|
|
90
|
-
# path is an anchor
|
82
|
+
# path is an anchor or a query
|
91
83
|
def internal?
|
92
|
-
url
|
84
|
+
url.start_with? "#", "?"
|
93
85
|
end
|
94
86
|
|
95
87
|
def file_path
|
@@ -107,8 +99,10 @@ module HTML
|
|
107
99
|
|
108
100
|
file = File.join base, path
|
109
101
|
|
110
|
-
# implicit
|
111
|
-
|
102
|
+
# implicit index support
|
103
|
+
if File.directory? file and !unslashed_directory? file
|
104
|
+
file = File.join file, @check.options[:directory_index_file]
|
105
|
+
end
|
112
106
|
|
113
107
|
file
|
114
108
|
end
|
@@ -135,6 +129,10 @@ module HTML
|
|
135
129
|
|
136
130
|
false
|
137
131
|
end
|
132
|
+
|
133
|
+
def unslashed_directory? file
|
134
|
+
File.directory? file and !file.end_with? File::SEPARATOR and !@check.options[:followlocation]
|
135
|
+
end
|
138
136
|
end
|
139
137
|
end
|
140
138
|
end
|
data/lib/html/proofer/checks.rb
CHANGED
@@ -2,12 +2,13 @@ module HTML
|
|
2
2
|
class Proofer
|
3
3
|
class Checks
|
4
4
|
[
|
5
|
-
"
|
6
|
-
"
|
7
|
-
"
|
8
|
-
"
|
9
|
-
"
|
10
|
-
|
5
|
+
"issue",
|
6
|
+
"check",
|
7
|
+
"checks/images",
|
8
|
+
"checks/links",
|
9
|
+
"checks/scripts",
|
10
|
+
"checks/favicon"
|
11
|
+
].each { |r| require File.join(File.dirname(__FILE__), r) }
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|
@@ -11,8 +11,9 @@ class Favicons < ::HTML::Proofer::Checks::Check
|
|
11
11
|
def run
|
12
12
|
return unless @options[:favicon]
|
13
13
|
|
14
|
-
@html.
|
14
|
+
@html.xpath("//link[not(ancestor::pre or ancestor::code)]").each do |favicon|
|
15
15
|
favicon = Favicon.new favicon, "favicon", self
|
16
|
+
next if favicon.ignore?
|
16
17
|
return if favicon.rel.split(" ").last.eql? "icon"
|
17
18
|
end
|
18
19
|
|
@@ -10,10 +10,6 @@ class Link < ::HTML::Proofer::Checkable
|
|
10
10
|
href.nil? and @name.nil? and @id.nil?
|
11
11
|
end
|
12
12
|
|
13
|
-
def unslashed_directory?
|
14
|
-
File.directory? absolute_path and !absolute_path.end_with? File::SEPARATOR
|
15
|
-
end
|
16
|
-
|
17
13
|
end
|
18
14
|
|
19
15
|
class Links < ::HTML::Proofer::Checks::Check
|
@@ -45,7 +41,7 @@ class Links < ::HTML::Proofer::Checks::Check
|
|
45
41
|
end
|
46
42
|
|
47
43
|
# has the local directory a trailing slash?
|
48
|
-
if
|
44
|
+
if link.unslashed_directory? link.absolute_path
|
49
45
|
self.add_issue("internally linking to a directory #{link.absolute_path} without trailing slash")
|
50
46
|
next
|
51
47
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'colored'
|
3
|
+
|
4
|
+
class HTML::Proofer::Checks
|
5
|
+
|
6
|
+
class Issue
|
7
|
+
|
8
|
+
attr_reader :path, :desc, :status
|
9
|
+
|
10
|
+
def initialize(path, desc, status = nil)
|
11
|
+
@path = path
|
12
|
+
@desc = desc
|
13
|
+
@status = status
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"#{HTML::colorize(:blue, @path)}: #{desc}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -37,10 +37,10 @@ describe "Favicons test" do
|
|
37
37
|
output.should == ""
|
38
38
|
end
|
39
39
|
|
40
|
-
it "
|
40
|
+
it "fails for broken favicon with data-proofer-ignore" do
|
41
41
|
broken_but_ignored = "#{FIXTURES_DIR}/favicon/favicon_broken_but_ignored.html"
|
42
42
|
output = capture_stderr { HTML::Proofer.new(broken_but_ignored, {:favicon => true}).run }
|
43
|
-
output.should
|
43
|
+
output.should match /no favicon specified/
|
44
44
|
end
|
45
45
|
|
46
46
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<html>
|
2
|
+
|
3
|
+
<body>
|
4
|
+
|
5
|
+
<p><a href="?txthl=avian%20influenza+world+cook+flu-like%20symptoms+Don't%20Forget...+causes%20sickness%20in%20birds,%20it%20can%20also%20infect%20people.#example">Highlight example text that meets the search criteria</a></p>
|
6
|
+
|
7
|
+
</body>
|
8
|
+
|
9
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
<a href="folder/">Directory</a>
|
@@ -45,6 +45,14 @@ describe "Links test" do
|
|
45
45
|
output.should match /External link https:\/\/help.github.com\/changing-author-info\/ failed: 301 No error/
|
46
46
|
end
|
47
47
|
|
48
|
+
it "does not fail on redirects we're not following" do
|
49
|
+
# this test should emit a 301--see above--but we're intentionally supressing it
|
50
|
+
options = { :only_4xx => true, :followlocation => false }
|
51
|
+
linkWithRedirectFilepath = "#{FIXTURES_DIR}/links/linkWithRedirect.html"
|
52
|
+
output = capture_stderr { HTML::Proofer.new(linkWithRedirectFilepath, options).run }
|
53
|
+
output.should == ""
|
54
|
+
end
|
55
|
+
|
48
56
|
it "should understand https" do
|
49
57
|
linkWithHttpsFilepath = "#{FIXTURES_DIR}/links/linkWithHttps.html"
|
50
58
|
output = capture_stderr { HTML::Proofer.new(linkWithHttpsFilepath).run }
|
@@ -173,9 +181,8 @@ describe "Links test" do
|
|
173
181
|
end
|
174
182
|
|
175
183
|
it "works for array of links" do
|
176
|
-
|
177
|
-
output
|
178
|
-
output.should match /foofoo.biz\/? failed: 0 Couldn't resolve host name/
|
184
|
+
output = capture_stderr { HTML::Proofer.new(["www.github.com", "foofoofoo.biz"]).run }
|
185
|
+
output.should match /foofoofoo.biz\/? failed: 0 Couldn't resolve host name/
|
179
186
|
end
|
180
187
|
|
181
188
|
it "works for broken anchors within pre" do
|
@@ -189,4 +196,23 @@ describe "Links test" do
|
|
189
196
|
output = capture_stderr { HTML::Proofer.new(link_pre).run }
|
190
197
|
output.should == ""
|
191
198
|
end
|
199
|
+
|
200
|
+
it "works for pipes in the URL" do
|
201
|
+
escape_pipes = "#{FIXTURES_DIR}/links/escape_pipes.html"
|
202
|
+
output = capture_stderr { HTML::Proofer.new(escape_pipes).run }
|
203
|
+
output.should == ""
|
204
|
+
end
|
205
|
+
|
206
|
+
it "fails for broken hash with query" do
|
207
|
+
broken_hash = "#{FIXTURES_DIR}/links/broken_hash_with_query.html"
|
208
|
+
output = capture_stderr { HTML::Proofer.new(broken_hash).run }
|
209
|
+
output.should match /linking to internal hash #example that does not exist/
|
210
|
+
end
|
211
|
+
|
212
|
+
it "works for directory index file" do
|
213
|
+
options = { :directory_index => "index.php" }
|
214
|
+
link_pointing_to_directory = "#{FIXTURES_DIR}/links/link_pointing_to_directory.html"
|
215
|
+
output = capture_stderr { HTML::Proofer.new(link_pointing_to_directory, options).run }
|
216
|
+
output.should == ""
|
217
|
+
end
|
192
218
|
end
|
data/spec/spec_helper.rb
CHANGED
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: 1.
|
4
|
+
version: 1.3.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: 2014-08-
|
11
|
+
date: 2014-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mercenary
|
@@ -81,49 +81,49 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '2.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: redcarpet
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: rspec
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: 2.13.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
110
|
+
version: 2.13.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: rake
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - "
|
115
|
+
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
117
|
+
version: '0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- - "
|
122
|
+
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
124
|
+
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: awesome_print
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
@@ -160,6 +160,7 @@ files:
|
|
160
160
|
- lib/html/proofer/checks/images.rb
|
161
161
|
- lib/html/proofer/checks/links.rb
|
162
162
|
- lib/html/proofer/checks/scripts.rb
|
163
|
+
- lib/html/proofer/issue.rb
|
163
164
|
- spec/html/proofer/favicon_spec.rb
|
164
165
|
- spec/html/proofer/fixtures/favicon/favicon_absent.html
|
165
166
|
- spec/html/proofer/fixtures/favicon/favicon_absent_apple.html
|
@@ -192,10 +193,13 @@ files:
|
|
192
193
|
- spec/html/proofer/fixtures/links/brokenLinkExternal.html
|
193
194
|
- spec/html/proofer/fixtures/links/brokenLinkInternal.html
|
194
195
|
- spec/html/proofer/fixtures/links/brokenLinkWithNumber.html
|
196
|
+
- spec/html/proofer/fixtures/links/broken_hash_with_query.html
|
195
197
|
- spec/html/proofer/fixtures/links/checkSSLLinks.html
|
198
|
+
- spec/html/proofer/fixtures/links/escape_pipes.html
|
196
199
|
- spec/html/proofer/fixtures/links/folder/anchorLink.html
|
197
200
|
- spec/html/proofer/fixtures/links/folder/assets/barrel.png
|
198
201
|
- spec/html/proofer/fixtures/links/folder/index.html
|
202
|
+
- spec/html/proofer/fixtures/links/folder/index.php
|
199
203
|
- spec/html/proofer/fixtures/links/folder/relativeImage.html
|
200
204
|
- spec/html/proofer/fixtures/links/gpl.png
|
201
205
|
- spec/html/proofer/fixtures/links/head_link_href.html
|
@@ -212,6 +216,7 @@ files:
|
|
212
216
|
- spec/html/proofer/fixtures/links/link_directory_without_slash.html
|
213
217
|
- spec/html/proofer/fixtures/links/link_missing_protocol_invalid.html
|
214
218
|
- spec/html/proofer/fixtures/links/link_missing_protocol_valid.html
|
219
|
+
- spec/html/proofer/fixtures/links/link_pointing_to_directory.html
|
215
220
|
- spec/html/proofer/fixtures/links/links_in_pre.html
|
216
221
|
- spec/html/proofer/fixtures/links/mailto_link.html
|
217
222
|
- spec/html/proofer/fixtures/links/missingLinkHref.html
|
@@ -297,10 +302,13 @@ test_files:
|
|
297
302
|
- spec/html/proofer/fixtures/links/brokenLinkExternal.html
|
298
303
|
- spec/html/proofer/fixtures/links/brokenLinkInternal.html
|
299
304
|
- spec/html/proofer/fixtures/links/brokenLinkWithNumber.html
|
305
|
+
- spec/html/proofer/fixtures/links/broken_hash_with_query.html
|
300
306
|
- spec/html/proofer/fixtures/links/checkSSLLinks.html
|
307
|
+
- spec/html/proofer/fixtures/links/escape_pipes.html
|
301
308
|
- spec/html/proofer/fixtures/links/folder/anchorLink.html
|
302
309
|
- spec/html/proofer/fixtures/links/folder/assets/barrel.png
|
303
310
|
- spec/html/proofer/fixtures/links/folder/index.html
|
311
|
+
- spec/html/proofer/fixtures/links/folder/index.php
|
304
312
|
- spec/html/proofer/fixtures/links/folder/relativeImage.html
|
305
313
|
- spec/html/proofer/fixtures/links/gpl.png
|
306
314
|
- spec/html/proofer/fixtures/links/head_link_href.html
|
@@ -317,6 +325,7 @@ test_files:
|
|
317
325
|
- spec/html/proofer/fixtures/links/link_directory_without_slash.html
|
318
326
|
- spec/html/proofer/fixtures/links/link_missing_protocol_invalid.html
|
319
327
|
- spec/html/proofer/fixtures/links/link_missing_protocol_valid.html
|
328
|
+
- spec/html/proofer/fixtures/links/link_pointing_to_directory.html
|
320
329
|
- spec/html/proofer/fixtures/links/links_in_pre.html
|
321
330
|
- spec/html/proofer/fixtures/links/mailto_link.html
|
322
331
|
- spec/html/proofer/fixtures/links/missingLinkHref.html
|