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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d35ff970865a64a0f6a4c564134ac30a060dfc3
4
- data.tar.gz: 34525a50cdf84967b1549158746de39544bc08ba
3
+ metadata.gz: 65597a503b7fc561c9dae5377f36dd3860581a92
4
+ data.tar.gz: 44f24659044b6122d43476be9f41c3be1f8633b1
5
5
  SHA512:
6
- metadata.gz: de0f69c219747e9daae75bb9ce7db7118e7b02989d9bb365aa2e9e88db339229a80012e1a5119c8e08fcb4de31bfd1ca39cd978599744dbeb41219cce8389cec
7
- data.tar.gz: bcd0193c557dee8c3906b869c5e64c536b45aa8fde4de65e4a154ec4822bef3ff4b7d022dd2923dc5200713e75277d763e8615043c37c56dc6480dc97d109b9b
6
+ metadata.gz: 06b4ec0986dc6cd27575d65f73a29d00c2166b0e4b8c15e4b15d345a90ea382f4b6710d8cc67ff476debee80867e0489181bf65bb9f22e4b2ae2eb6eff958425
7
+ data.tar.gz: a14622a437b34deee71d3a6c0daf42f466d35a980531993d505a5c72c736c7a640da2ff9992d46063b5674334bf28e3d5422a9ce1e800b1533d863be05b99e97
data/.travis.yml CHANGED
@@ -1,6 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
- - 2.0.0
5
- before_install:
6
- - export NOKOGIRI_USE_SYSTEM_LIBRARIES=true
3
+ - 1.9
4
+ - 2.0
5
+ - 2.1
6
+ env:
7
+ global:
8
+ - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
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.png?branch=master)](https://travis-ci.org/gjtorikian/html-proofer) [![Gem Version](https://badge.fury.io/rb/html-proofer.png)](http://badge.fury.io/rb/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. Jawesome!
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
- | `as_link_array` | Assumes that you've passed in just an array of links to check. | `false` |
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 = > true, :ssl_verifyhost => 2 })
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 an array of links to check.'
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
- options[:as_link_array] = opts["as-links"] unless opts["as-links"].nil?
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 options[:as_link_array]
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.2.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 "html-pipeline", "~> 1.8"
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
- require File.dirname(__FILE__) + '/proofer/checkable'
5
- require File.dirname(__FILE__) + '/proofer/checks'
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
- :as_link_array => false
38
+ :only_4xx => false,
39
+ :directory_index_file => "index.html"
40
+ }
41
+
42
+ @typhoeus_opts = {
43
+ :followlocation => true
25
44
  }
26
- @options = @proofer_opts.merge({:followlocation => true}).merge(opts)
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 @options[:as_link_array]
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.sort.each do |issue|
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, @options.merge({:method => method}))
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
- failed_test_msg = "External link #{href} failed: got a time out"
118
- failed_test_msg.insert(0, "#{filenames.join(' ').blue}: ") unless filenames.nil?
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
- failed_test_msg = "External link #{href} failed: #{response_code} #{response.return_message}"
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("#{@src}/**/*#{@options[:ext]}")
163
+ Dir.glob File.join(@src, "**", "*#{@options[:ext]}")
164
+ elsif File.extname(@src) == @options[:ext]
165
+ [@src]
143
166
  else
144
- File.extname(@src) == @options[:ext] ? [@src] : []
167
+ []
145
168
  end
146
169
  end
147
170
 
148
171
  def self.create_nokogiri(path)
149
- path << "/index.html" if File.directory? path # support for Jekyll-style links
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 colorize(color, string)
165
- if $stdout.isatty && $stderr.isatty
166
- Colored.colorize(string, :foreground => color)
167
- else
168
- string
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
@@ -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 << "#{@path.blue}: #{desc}"
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
- begin
36
- URI.parse url
37
- rescue
38
- false
39
- end
35
+ !parts.nil?
40
36
  end
41
37
 
42
38
  def parts
43
- URI.parse url
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
- uri = URI.parse url
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
- uri = URI.parse url
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[0] == "#"
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 /index.html support, with support for trailing slashes
111
- file = File.join path, "index.html" if File.directory? File.expand_path file, @check.src
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
@@ -2,12 +2,13 @@ module HTML
2
2
  class Proofer
3
3
  class Checks
4
4
  [
5
- "/check",
6
- "/checks/images",
7
- "/checks/links",
8
- "/checks/scripts",
9
- "/checks/favicon"
10
- ].each { |r| require File.dirname(__FILE__) + r }
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.css("link").each do |favicon|
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 !@options[:followlocation] and !link.remote? and link.unslashed_directory?
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 "passes for broken favicon with data-proofer-ignore" do
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,9 @@
1
+ <html>
2
+ <head>
3
+ <link
4
+ rel="stylesheet"
5
+ href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic|Noto+Serif:400,400italic,700,700italic|Droid+Sans+Mono:400">
6
+ </head>
7
+ <body>
8
+ </body>
9
+ </html>
@@ -0,0 +1,2 @@
1
+ <?php
2
+ x = 42;
@@ -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
- options = { :as_link_array => true}
177
- output = capture_stderr { HTML::Proofer.new(["www.github.com", "foofoofoo.biz"], options).run }
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
@@ -12,6 +12,9 @@ RSpec.configure do |config|
12
12
 
13
13
  # Use the specified formatter
14
14
  config.formatter = :documentation # :progress, :html, :textmate
15
+
16
+ # Run in a random order
17
+ config.order = :random
15
18
  end
16
19
 
17
20
  def capture_stderr(&block)
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.2.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-08 00:00:00.000000000 Z
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: html-pipeline
84
+ name: redcarpet
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '1.8'
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: '1.8'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: escape_utils
98
+ name: rspec
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '1.0'
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: '1.0'
110
+ version: 2.13.0
111
111
  - !ruby/object:Gem::Dependency
112
- name: rspec
112
+ name: rake
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: 2.13.0
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: 2.13.0
124
+ version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: rake
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