diff --git a/.rubocop.yml b/.rubocop.yml
index 366a760f..40b099bf 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -11,3 +11,6 @@ RequireParentheses:
Naming/FileName:
Enabled: false
+
+Style/Documentation:
+ Enabled: false
diff --git a/Rakefile b/Rakefile
index 24a27e60..87a1fa5a 100644
--- a/Rakefile
+++ b/Rakefile
@@ -11,7 +11,7 @@ require 'rubocop/rake_task'
RuboCop::RakeTask.new(:rubocop)
-task default: %i(spec proof_readme)
+task default: %i[spec proof_readme]
task :proof_readme do
require 'html-proofer'
diff --git a/bin/htmlproofer b/bin/htmlproofer
index eed31fbc..d22bd203 100755
--- a/bin/htmlproofer
+++ b/bin/htmlproofer
@@ -57,9 +57,7 @@ Mercenary.program(:htmlproofer) do |p|
# prepare everything to go to proofer
p.options.reject { |o| opts[o.config_key].nil? }.each do |option|
- if opts[option.config_key].is_a?(Array)
- opts[option.config_key] = opts[option.config_key].map { |i| HTMLProofer::Configuration.to_regex?(i) }
- end
+ opts[option.config_key] = opts[option.config_key].map { |i| HTMLProofer::Configuration.to_regex?(i) } if opts[option.config_key].is_a?(Array)
options[option.config_key.to_sym] = opts[option.config_key]
end
@@ -83,9 +81,7 @@ Mercenary.program(:htmlproofer) do |p|
options[:validation][:report_missing_names] = opts['report_missing_names'] unless opts['report_missing_names'].nil?
options[:validation][:report_invalid_tags] = opts['report_invalid_tags'] unless opts['report_invalid_tags'].nil?
- unless opts['typhoeus_config'].nil?
- options[:typhoeus] = HTMLProofer::Configuration.parse_json_option('typhoeus_config', opts['typhoeus_config'])
- end
+ options[:typhoeus] = HTMLProofer::Configuration.parse_json_option('typhoeus_config', opts['typhoeus_config']) unless opts['typhoeus_config'].nil?
unless opts['timeframe'].nil?
options[:cache] ||= {}
diff --git a/html-proofer.gemspec b/html-proofer.gemspec
index 313bc143..edf6ac10 100644
--- a/html-proofer.gemspec
+++ b/html-proofer.gemspec
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-$LOAD_PATH.push File.expand_path('../lib', __FILE__)
+$LOAD_PATH.push File.expand_path('lib', __dir__)
require 'html-proofer/version'
Gem::Specification.new do |gem|
@@ -12,30 +12,29 @@ Gem::Specification.new do |gem|
gem.summary = %(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 documentation output.)
gem.homepage = 'https://github.com/gjtorikian/html-proofer'
gem.license = 'MIT'
- gem.executables = ['htmlproofer']
all_files = `git ls-files -z`.split("\x0")
gem.files = all_files.grep(%r{^(bin|lib)/})
gem.executables = all_files.grep(%r{^bin/}) { |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(spec)/})
gem.require_paths = ['lib']
+ gem.add_dependency 'addressable', '~> 2.3'
gem.add_dependency 'mercenary', '~> 0.3'
gem.add_dependency 'nokogiri', '~> 1.10'
+ gem.add_dependency 'parallel', '~> 1.3'
gem.add_dependency 'rainbow', '~> 3.0'
gem.add_dependency 'typhoeus', '~> 1.3'
gem.add_dependency 'yell', '~> 2.0'
- gem.add_dependency 'parallel', '~> 1.3'
- gem.add_dependency 'addressable', '~> 2.3'
+ gem.add_development_dependency 'awesome_print'
+ gem.add_development_dependency 'codecov'
+ gem.add_development_dependency 'pry-byebug'
+ gem.add_development_dependency 'rake'
gem.add_development_dependency 'redcarpet'
+ gem.add_development_dependency 'rspec', '~> 3.1'
gem.add_development_dependency 'rubocop'
- gem.add_development_dependency 'rubocop-standard'
gem.add_development_dependency 'rubocop-performance'
- gem.add_development_dependency 'codecov'
- gem.add_development_dependency 'rspec', '~> 3.1'
- gem.add_development_dependency 'rake'
- gem.add_development_dependency 'pry-byebug'
- gem.add_development_dependency 'awesome_print'
- gem.add_development_dependency 'vcr', '~> 2.9'
+ gem.add_development_dependency 'rubocop-standard'
gem.add_development_dependency 'timecop', '~> 0.8'
+ gem.add_development_dependency 'vcr', '~> 2.9'
end
diff --git a/lib/html-proofer.rb b/lib/html-proofer.rb
index 384cbdf5..92ef0df0 100644
--- a/lib/html-proofer.rb
+++ b/lib/html-proofer.rb
@@ -17,38 +17,38 @@ def require_all(path)
begin
require 'awesome_print'
require 'pry-byebug'
-rescue LoadError; end
+rescue LoadError; end # rubocop:disable Lint/HandleExceptions
module HTMLProofer
- def check_file(file, options = {})
+ def self.check_file(file, options = {})
raise ArgumentError unless file.is_a?(String)
raise ArgumentError, "#{file} does not exist" unless File.exist?(file)
+
options[:type] = :file
HTMLProofer::Runner.new(file, options)
end
- module_function :check_file
- def check_directory(directory, options = {})
+ def self.check_directory(directory, options = {})
raise ArgumentError unless directory.is_a?(String)
raise ArgumentError, "#{directory} does not exist" unless Dir.exist?(directory)
+
options[:type] = :directory
HTMLProofer::Runner.new([directory], options)
end
- module_function :check_directory
- def check_directories(directories, options = {})
+ def self.check_directories(directories, options = {})
raise ArgumentError unless directories.is_a?(Array)
+
options[:type] = :directory
directories.each do |directory|
raise ArgumentError, "#{directory} does not exist" unless Dir.exist?(directory)
end
HTMLProofer::Runner.new(directories, options)
end
- module_function :check_directories
- def check_links(links, options = {})
+ def self.check_links(links, options = {})
raise ArgumentError unless links.is_a?(Array)
+
options[:type] = :links
HTMLProofer::Runner.new(links, options)
end
- module_function :check_links
end
diff --git a/lib/html-proofer/cache.rb b/lib/html-proofer/cache.rb
index 8836893a..1eaa2852 100644
--- a/lib/html-proofer/cache.rb
+++ b/lib/html-proofer/cache.rb
@@ -9,7 +9,7 @@ class Cache
include HTMLProofer::Utils
DEFAULT_STORAGE_DIR = File.join('tmp', '.htmlproofer')
- DEFAULT_CACHE_FILE_NAME = 'cache.log'.freeze
+ DEFAULT_CACHE_FILE_NAME = 'cache.log'
attr_reader :exists, :cache_log, :storage_dir, :cache_file
@@ -120,9 +120,8 @@ def retrieve_urls(external_urls)
@cache_log.each_pair do |url, cache|
if within_timeframe?(cache['time'])
next if cache['message'].empty? # these were successes to skip
- urls_to_check[url] = cache['filenames'] # these are failures to retry
else
- urls_to_check[url] = cache['filenames'] # pass or fail, recheck expired links
+ urls_to_check[url] = cache['filenames'] # recheck expired links
end
end
urls_to_check
@@ -142,23 +141,16 @@ def clean_url(url)
end
def setup_cache!(options)
- @storage_dir = if options[:storage_dir]
- options[:storage_dir]
- else
- DEFAULT_STORAGE_DIR
- end
+ @storage_dir = options[:storage_dir] || DEFAULT_STORAGE_DIR
FileUtils.mkdir_p(storage_dir) unless Dir.exist?(storage_dir)
- cache_file_name = if options[:cache_file]
- options[:cache_file]
- else
- DEFAULT_CACHE_FILE_NAME
- end
+ cache_file_name = options[:cache_file] || DEFAULT_CACHE_FILE_NAME
@cache_file = File.join(storage_dir, cache_file_name)
return unless File.exist?(cache_file)
+
contents = File.read(cache_file)
@cache_log = contents.empty? ? {} : JSON.parse(contents)
end
@@ -174,7 +166,7 @@ def time_ago(measurement, unit)
when :days
@cache_datetime - measurement
when :hours
- @cache_datetime - Rational(measurement/24.0)
+ @cache_datetime - Rational(measurement / 24.0)
end.to_time
end
end
diff --git a/lib/html-proofer/check.rb b/lib/html-proofer/check.rb
index 39e9b6a1..1104b6e4 100644
--- a/lib/html-proofer/check.rb
+++ b/lib/html-proofer/check.rb
@@ -29,6 +29,7 @@ def add_issue(desc, line: nil, status: -1, content: nil)
def add_to_external_urls(url)
return if @external_urls[url]
+
add_path_for_url(url)
end
@@ -45,6 +46,7 @@ def self.subchecks
ObjectSpace.each_object(Class) do |c|
next unless c.superclass == self
+
classes << c
end
diff --git a/lib/html-proofer/check/favicon.rb b/lib/html-proofer/check/favicon.rb
index 7c0231a4..e681a8a9 100644
--- a/lib/html-proofer/check/favicon.rb
+++ b/lib/html-proofer/check/favicon.rb
@@ -6,22 +6,24 @@ def run
@html.xpath('//link[not(ancestor::pre or ancestor::code)]').each do |node|
favicon = create_element(node)
next if favicon.ignore?
+
found = true if favicon.rel.split(' ').last.eql? 'icon'
break if found
end
return if found
- return if is_immediate_redirect?
+ return if immediate_redirect?
add_issue('no favicon specified')
end
private
- def is_immediate_redirect?
- # allow any instant-redirect meta tag
- @html.xpath("//meta[@http-equiv='refresh']").attribute('content').value.start_with? '0;' rescue false
+ # allow any instant-redirect meta tag
+ def immediate_redirect?
+ @html.xpath("//meta[@http-equiv='refresh']").attribute('content').value.start_with? '0;'
+ rescue StandardError
+ false
end
-
end
diff --git a/lib/html-proofer/check/html.rb b/lib/html-proofer/check/html.rb
index e47bd486..9580c44c 100644
--- a/lib/html-proofer/check/html.rb
+++ b/lib/html-proofer/check/html.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
class HtmlCheck < ::HTMLProofer::Check
- SCRIPT_EMBEDS_MSG = /Element script embeds close tag/
- INVALID_TAG_MSG = /Tag ([\w\-:]+) invalid/
- INVALID_PREFIX = /Namespace prefix/
- PARSE_ENTITY_REF = /htmlParseEntityRef: no name/
+ SCRIPT_EMBEDS_MSG = /Element script embeds close tag/.freeze
+ INVALID_TAG_MSG = /Tag ([\w\-:]+) invalid/.freeze
+ INVALID_PREFIX = /Namespace prefix/.freeze
+ PARSE_ENTITY_REF = /htmlParseEntityRef: no name/.freeze
def run
@html.errors.each do |error|
diff --git a/lib/html-proofer/check/images.rb b/lib/html-proofer/check/images.rb
index 648a1c95..92712ffd 100644
--- a/lib/html-proofer/check/images.rb
+++ b/lib/html-proofer/check/images.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class ImageCheck < ::HTMLProofer::Check
- SCREEN_SHOT_REGEX = /Screen(?: |%20)Shot(?: |%20)\d+-\d+-\d+(?: |%20)at(?: |%20)\d+.\d+.\d+/
+ SCREEN_SHOT_REGEX = /Screen(?: |%20)Shot(?: |%20)\d+-\d+-\d+(?: |%20)at(?: |%20)\d+.\d+.\d+/.freeze
def empty_alt_tag?
@img.alt.nil? || @img.alt.strip.empty?
@@ -38,13 +38,9 @@ def run
add_issue("internal image #{@img.url} does not exist", line: line, content: content)
end
- if empty_alt_tag? && !@img.ignore_empty_alt? && !@img.ignore_alt?
- add_issue("image #{@img.url} does not have an alt attribute", line: line, content: content)
- end
+ add_issue("image #{@img.url} does not have an alt attribute", line: line, content: content) if empty_alt_tag? && !@img.ignore_empty_alt? && !@img.ignore_alt?
- if @img.check_img_http? && @img.scheme == 'http'
- add_issue("image #{@img.url} uses the http scheme", line: line, content: content)
- end
+ add_issue("image #{@img.url} uses the http scheme", line: line, content: content) if @img.check_img_http? && @img.scheme == 'http'
end
external_urls
diff --git a/lib/html-proofer/check/links.rb b/lib/html-proofer/check/links.rb
index dc91af9a..58f332a3 100644
--- a/lib/html-proofer/check/links.rb
+++ b/lib/html-proofer/check/links.rb
@@ -35,6 +35,7 @@ def run
next if @link.allow_missing_href?
# HTML5 allows dropping the href: http://git.io/vBX0z
next if @html.internal_subset.name == 'html' && @html.internal_subset.external_id.nil?
+
add_issue('anchor has no href attribute', line: line, content: content)
next
end
@@ -47,9 +48,10 @@ def run
# we need to skip these for now; although the domain main be valid,
# curl/Typheous inaccurately return 404s for some links. cc https://git.io/vyCFx
next if @link.respond_to?(:rel) && @link.rel == 'dns-prefetch'
+
add_to_external_urls(@link.href)
next
- elsif !@link.internal? && !@link.exists?
+ elsif !@link.remote? && !@link.exists?
add_issue("internally linking to #{@link.href}, which does not exist", line: line, content: content)
end
@@ -74,6 +76,7 @@ def check_schemes(link, line, content)
handle_tel(link, line, content)
when 'http'
return unless @options[:enforce_https]
+
add_issue("#{link.href} is not an HTTPS link", line: line, content: content)
end
end
@@ -103,9 +106,7 @@ def external_link_check(link, line, content)
add_issue("trying to find hash of #{link.href}, but #{link.absolute_path} does not exist", line: line, content: content)
else
target_html = create_nokogiri link.absolute_path
- unless hash_check target_html, link.hash
- add_issue("linking to #{link.href}, but #{link.hash} does not exist", line: line, content: content)
- end
+ add_issue("linking to #{link.href}, but #{link.hash} does not exist", line: line, content: content) unless hash_check target_html, link.hash
end
end
@@ -135,6 +136,7 @@ def find_fragments(html, fragment_ids)
def check_sri(line, content)
return unless SRI_REL_TYPES.include?(@link.rel)
+
if !defined?(@link.integrity) && !defined?(@link.crossorigin)
add_issue("SRI and CORS not provided in: #{@link.src}", line: line, content: content)
elsif !defined?(@link.integrity)
diff --git a/lib/html-proofer/check/opengraph.rb b/lib/html-proofer/check/opengraph.rb
index 654d59bd..751ce460 100644
--- a/lib/html-proofer/check/opengraph.rb
+++ b/lib/html-proofer/check/opengraph.rb
@@ -1,4 +1,3 @@
-# encoding: utf-8
# frozen_string_literal: true
class OpenGraphElement < ::HTMLProofer::Element
diff --git a/lib/html-proofer/configuration.rb b/lib/html-proofer/configuration.rb
index 76e14a37..187d4bdb 100644
--- a/lib/html-proofer/configuration.rb
+++ b/lib/html-proofer/configuration.rb
@@ -65,19 +65,19 @@ def self.to_regex?(item)
end
def self.parse_json_option(option_name, config)
- raise ArgumentError.new('Must provide an option name in string format.') unless option_name.is_a?(String)
- raise ArgumentError.new('Must provide an option name in string format.') unless !option_name.strip.empty?
+ raise ArgumentError, 'Must provide an option name in string format.' unless option_name.is_a?(String)
+ raise ArgumentError, 'Must provide an option name in string format.' if option_name.strip.empty?
return {} if config.nil?
- raise ArgumentError.new('Must provide a JSON configuration in string format.') unless config.is_a?(String)
+ raise ArgumentError, 'Must provide a JSON configuration in string format.' unless config.is_a?(String)
return {} if config.strip.empty?
begin
JSON.parse(config)
- rescue
- raise ArgumentError.new("Option '" + option_name + "' did not contain valid JSON.")
+ rescue StandardError
+ raise ArgumentError, "Option '" + option_name + "' did not contain valid JSON."
end
end
end
diff --git a/lib/html-proofer/element.rb b/lib/html-proofer/element.rb
index d0f88b8d..d792206e 100644
--- a/lib/html-proofer/element.rb
+++ b/lib/html-proofer/element.rb
@@ -18,7 +18,7 @@ def initialize(obj, check)
instance_variable_set("@#{name}", value.value)
end
- @aria_hidden = (defined?(@aria_hidden) && @aria_hidden == 'true') ? true : false
+ @aria_hidden = defined?(@aria_hidden) && @aria_hidden == 'true' ? true : false
@data_proofer_ignore = defined?(@data_proofer_ignore)
@@ -56,9 +56,11 @@ def initialize(obj, check)
def url
return @url if defined?(@url)
+
@url = (@src || @srcset || @href || '').delete("\u200b").strip
@url = Addressable::URI.join(base.attr('href') || '', url).to_s if base
return @url if @check.options[:url_swap].empty?
+
@url = swap(@url, @check.options[:url_swap])
end
@@ -77,11 +79,11 @@ def path
end
def hash
- parts.fragment unless parts.nil?
+ parts&.fragment
end
def scheme
- parts.scheme unless parts.nil?
+ parts&.scheme
end
# path is to an external server
@@ -137,7 +139,7 @@ def external?
!internal?
end
- # path is an anchor or a query
+ # path is an anchor, a query or refers to root
def internal?
hash_link || param_link || slash_link
end
@@ -151,24 +153,22 @@ def param_link
end
def slash_link
- url.start_with?('|')
+ url.start_with?('/')
end
def file_path
- return if path.nil?
+ return if path.nil? || path.empty?
path_dot_ext = ''
- if @check.options[:assume_extension]
- path_dot_ext = path + @check.options[:extension]
- end
+ path_dot_ext = path + @check.options[:extension] if @check.options[:assume_extension]
if path =~ %r{^/} # path relative to root
if File.directory?(@check.src)
base = @check.src
else
root_dir = @check.options[:root_dir]
- base = root_dir ? root_dir : File.dirname(@check.src)
+ base = root_dir || File.dirname(@check.src)
end
elsif File.exist?(File.expand_path(path, @check.src)) || File.exist?(File.expand_path(path_dot_ext, @check.src)) # relative links, path is a file
base = File.dirname @check.path
@@ -179,7 +179,6 @@ def file_path
end
file = File.join base, path
-
if @check.options[:assume_extension] && File.file?("#{file}#{@check.options[:extension]}")
file = "#{file}#{@check.options[:extension]}"
elsif File.directory?(file) && !unslashed_directory?(file) # implicit index support
@@ -192,6 +191,7 @@ def file_path
# checks if a file exists relative to the current pwd
def exists?
return @checked_paths[absolute_path] if @checked_paths.key? absolute_path
+
@checked_paths[absolute_path] = File.exist? absolute_path
end
@@ -226,9 +226,9 @@ def base
def html
# If link is on the same page, then URL is on the current page so can use the same HTML as for current page
- if (hash_link || param_link) && internal?
+ if hash_link || param_link
@html
- elsif slash_link && internal?
+ elsif slash_link
# link on another page, e.g. /about#Team - need to get HTML from the other page
create_nokogiri(absolute_path)
end
diff --git a/lib/html-proofer/issue.rb b/lib/html-proofer/issue.rb
index 72dd2265..1bbc3eb6 100644
--- a/lib/html-proofer/issue.rb
+++ b/lib/html-proofer/issue.rb
@@ -56,9 +56,7 @@ def report(sorted_issues, first_report, second_report)
@logger.log :error, " * #{issue}"
else
msg = " * #{issue.send(second_report)}#{issue.line}"
- if !issue.content.nil? && !issue.content.empty?
- msg = "#{msg}\n #{issue.content}"
- end
+ msg = "#{msg}\n #{issue.content}" if !issue.content.nil? && !issue.content.empty?
@logger.log(:error, msg)
end
end
diff --git a/lib/html-proofer/middleware.rb b/lib/html-proofer/middleware.rb
index b1e7eabb..87ff5511 100644
--- a/lib/html-proofer/middleware.rb
+++ b/lib/html-proofer/middleware.rb
@@ -2,25 +2,24 @@
module HTMLProofer
class Middleware
-
class InvalidHtmlError < StandardError
def initialize(failures)
@failures = failures
end
def message
- "HTML Validation errors (skip by adding `?proofer-ignore` to URL): \n#{@failures.join("\n")}"
+ "HTML Validation errors (skip by adding `?proofer-ignore` to URL): \n#{@failures.join("\n")}"
end
end
def self.options
@options ||= {
- type: :file,
- allow_missing_href: true, # Permitted in html5
- allow_hash_href: true,
+ type: :file,
+ allow_missing_href: true, # Permitted in html5
+ allow_hash_href: true,
check_external_hash: true,
- check_html: true,
- url_ignore: [/.*/], # Don't try to check local files exist
+ check_html: true,
+ url_ignore: [/.*/] # Don't try to check local files exist
}
end
@@ -46,20 +45,21 @@ def initialize(app)
'
0
- raise InvalidHtmlError.new(parsed[:failures])
- end
+ raise InvalidHtmlError, parsed[:failures] unless parsed[:failures].empty?
end
result
end
diff --git a/lib/html-proofer/runner.rb b/lib/html-proofer/runner.rb
index 43284674..e10568f1 100644
--- a/lib/html-proofer/runner.rb
+++ b/lib/html-proofer/runner.rb
@@ -103,9 +103,7 @@ def check_parsed(html, path)
check = Object.const_get(klass).new(src, path, html, @options)
check.run
external_urls = check.external_urls
- if @options[:url_swap]
- external_urls = Hash[check.external_urls.map { |url, file| [swap(url, @options[:url_swap]), file] }]
- end
+ external_urls = Hash[check.external_urls.map { |url, file| [swap(url, @options[:url_swap]), file] }] if @options[:url_swap]
result[:external_urls].merge!(external_urls)
result[:failures].concat(check.issues)
end
@@ -148,6 +146,7 @@ def ignore_file?(file)
def checks
return @checks if defined?(@checks) && !@checks.nil?
+
@checks = HTMLProofer::Check.subchecks.map(&:name)
@checks.delete('FaviconCheck') unless @options[:check_favicon]
@checks.delete('HtmlCheck') unless @options[:check_html]
@@ -159,6 +158,7 @@ def checks
def failed_tests
result = []
return result if @failures.empty?
+
@failures.each { |f| result << f.to_s }
result
end
diff --git a/lib/html-proofer/url_validator.rb b/lib/html-proofer/url_validator.rb
index febd8144..e6496400 100644
--- a/lib/html-proofer/url_validator.rb
+++ b/lib/html-proofer/url_validator.rb
@@ -36,6 +36,7 @@ def run
def remove_query_values
return nil if @external_urls.nil?
+
paths_with_queries = {}
iterable_external_urls = @external_urls.dup
@external_urls.each_key do |url|
@@ -46,6 +47,7 @@ def remove_query_values
nil
end
next if uri.nil? || uri.query.nil?
+
iterable_external_urls.delete(url) unless new_url_query_values?(uri, paths_with_queries)
end
iterable_external_urls
@@ -108,9 +110,9 @@ def establish_queue(external_urls)
external_urls.each_pair do |url, filenames|
url = begin
clean_url(url)
- rescue URI::Error, Addressable::URI::InvalidURIError
- add_external_issue(filenames, "#{url} is an invalid URL")
- next
+ rescue URI::Error, Addressable::URI::InvalidURIError
+ add_external_issue(filenames, "#{url} is an invalid URL")
+ next
end
method = if hash?(url) && @options[:check_external_hash]
@@ -146,20 +148,18 @@ def response_handler(response, filenames)
response_code = response.code
response.body.gsub!("\x00", '')
- if filenames.nil?
- debug_msg = "Received a #{response_code} for #{href}"
- else
- debug_msg = "Received a #{response_code} for #{href} in #{filenames.join(' ')}"
- end
+ debug_msg = if filenames.nil?
+ "Received a #{response_code} for #{href}"
+ else
+ "Received a #{response_code} for #{href} in #{filenames.join(' ')}"
+ end
@logger.log :debug, debug_msg
return if @options[:http_status_ignore].include?(response_code)
if response_code.between?(200, 299)
- unless check_hash_in_2xx_response(href, effective_url, response, filenames)
- @cache.add(href, filenames, response_code)
- end
+ @cache.add(href, filenames, response_code) unless check_hash_in_2xx_response(href, effective_url, response, filenames)
elsif response.timed_out?
handle_timeout(href, filenames, response_code)
elsif response_code.zero?
@@ -168,6 +168,7 @@ def response_handler(response, filenames)
queue_request(:get, href, filenames)
else
return if @options[:only_4xx] && !response_code.between?(400, 499)
+
# Received a non-successful http response.
msg = "External link #{href} failed: #{response_code} #{response.return_message}"
add_external_issue(filenames, msg, response_code)
@@ -191,9 +192,7 @@ def check_hash_in_2xx_response(href, effective_url, response, filenames)
xpath << [%(//*[@name="user-content-#{hash}"]|//*[@id="user-content-#{hash}"])]
# when linking to a file on GitHub, like #L12-L34, only the first "L" portion
# will be identified as a linkable portion
- if hash =~ /\A(L\d)+/
- xpath << [%(//td[@id="#{Regexp.last_match[1]}"])]
- end
+ xpath << [%(//td[@id="#{Regexp.last_match[1]}"])] if hash =~ /\A(L\d)+/
end
return unless body_doc.xpath(xpath.join('|')).empty?
@@ -208,6 +207,7 @@ def handle_timeout(href, filenames, response_code)
msg = "External link #{href} failed: got a time out (response code #{response_code})"
@cache.add(href, filenames, 0, msg)
return if @options[:only_4xx]
+
add_external_issue(filenames, msg, response_code)
end
@@ -218,6 +218,7 @@ def handle_failure(href, filenames, response_code, return_message)
Either way, the return message (if any) from the server is: #{return_message}"
@cache.add(href, filenames, 0, msg)
return if @options[:only_4xx]
+
add_external_issue(filenames, msg, response_code)
end
diff --git a/lib/html-proofer/utils.rb b/lib/html-proofer/utils.rb
index 074ea5ec..56fa513d 100644
--- a/lib/html-proofer/utils.rb
+++ b/lib/html-proofer/utils.rb
@@ -8,7 +8,7 @@ def pluralize(count, single, plural)
"#{count} #{(count == 1 ? single : plural)}"
end
- def create_nokogiri(path)
+ def self.create_nokogiri(path)
content = if File.exist?(path) && !File.directory?(path)
File.open(path).read
else
@@ -17,24 +17,21 @@ def create_nokogiri(path)
Nokogiri::HTML(clean_content(content))
end
- module_function :create_nokogiri
- def swap(href, replacement)
+ def self.swap(href, replacement)
replacement.each do |link, replace|
href = href.gsub(link, replace)
end
href
end
- module_function :swap
# address a problem with Nokogiri's parsing URL entities
# problem from http://git.io/vBYU1
# solution from http://git.io/vBYUi
- def clean_content(string)
+ def self.clean_content(string)
string.gsub(%r{(?:https?:)?//([^>]+)}i) do |url|
url.gsub(/&(?!amp;)/, '&')
end
end
- module_function :clean_content
end
end
diff --git a/lib/html-proofer/version.rb b/lib/html-proofer/version.rb
index e6327891..1066fca9 100644
--- a/lib/html-proofer/version.rb
+++ b/lib/html-proofer/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module HTMLProofer
- VERSION = '3.13.0'.freeze
+ VERSION = '3.13.0'
end
diff --git a/spec/html-proofer/cache_spec.rb b/spec/html-proofer/cache_spec.rb
index 3bfc1b0d..857c51fb 100644
--- a/spec/html-proofer/cache_spec.rb
+++ b/spec/html-proofer/cache_spec.rb
@@ -9,7 +9,7 @@
let(:default_cache_options) { { storage_dir: storage_dir } }
- let (:logger) { HTMLProofer::Log.new(:debug) }
+ let(:logger) { HTMLProofer::Log.new(:debug) }
def read_cache(cache_file)
JSON.parse File.read(cache_file)
@@ -20,7 +20,7 @@ def read_cache(cache_file)
now_time = Time.local(2019, 9, 6, 12, 0, 0)
Timecop.freeze(now_time)
- cache = HTMLProofer::Cache.new(logger, { timeframe: '2M' })
+ cache = HTMLProofer::Cache.new(logger, timeframe: '2M')
check_time = Time.local(2019, 8, 6, 12, 0, 0).to_s
@@ -37,7 +37,7 @@ def read_cache(cache_file)
now_time = Time.local(2019, 9, 6, 12, 0, 0)
Timecop.freeze(now_time)
- cache = HTMLProofer::Cache.new(logger, { timeframe: '2d' })
+ cache = HTMLProofer::Cache.new(logger, timeframe: '2d')
check_time = Time.local(2019, 9, 5, 12, 0, 0).to_s
@@ -54,7 +54,7 @@ def read_cache(cache_file)
now_time = Time.local(2019, 9, 6, 12, 0, 0)
Timecop.freeze(now_time)
- cache = HTMLProofer::Cache.new(logger, { timeframe: '2w' })
+ cache = HTMLProofer::Cache.new(logger, timeframe: '2w')
check_time = Time.local(2019, 8, 30, 12, 0, 0).to_s
@@ -71,7 +71,7 @@ def read_cache(cache_file)
now_time = Time.local(2019, 9, 6, 12, 0, 0)
Timecop.freeze(now_time)
- cache = HTMLProofer::Cache.new(logger, { timeframe: '3h' })
+ cache = HTMLProofer::Cache.new(logger, timeframe: '3h')
check_time = Time.local(2019, 9, 6, 9, 0, 0).to_s
diff --git a/spec/html-proofer/command_spec.rb b/spec/html-proofer/command_spec.rb
index 61d5c75b..9e37e196 100644
--- a/spec/html-proofer/command_spec.rb
+++ b/spec/html-proofer/command_spec.rb
@@ -116,6 +116,7 @@
expect(bin_file).to match(key)
readme.each_line do |line|
next unless line =~ /\| `#{key}`/
+
description = line.split('|')[2].strip
description.gsub!('A hash', 'A comma-separated list')
description.gsub!('An array', 'A comma-separated list')
diff --git a/spec/html-proofer/fixtures/links/broken_root_link_internal.html b/spec/html-proofer/fixtures/links/broken_root_link_internal.html
new file mode 100644
index 00000000..f54e4110
--- /dev/null
+++ b/spec/html-proofer/fixtures/links/broken_root_link_internal.html
@@ -0,0 +1,10 @@
+
+
+
+ Blah blah blah. + Not a real link! +
+ + + diff --git a/spec/html-proofer/fixtures/links/link_to_another_folder.html b/spec/html-proofer/fixtures/links/link_to_another_folder.html new file mode 100644 index 00000000..ac9868cb --- /dev/null +++ b/spec/html-proofer/fixtures/links/link_to_another_folder.html @@ -0,0 +1,8 @@ + + ++ Blah blah blah. + A real link! +
+ + diff --git a/spec/html-proofer/fixtures/links/working_root_link_internal.html b/spec/html-proofer/fixtures/links/working_root_link_internal.html index 9ca8490c..5d1762b3 100644 --- a/spec/html-proofer/fixtures/links/working_root_link_internal.html +++ b/spec/html-proofer/fixtures/links/working_root_link_internal.html @@ -2,8 +2,8 @@- Blah blah blah. - A real link! + Blah blah blah. + Not a real link!
diff --git a/spec/html-proofer/images_spec.rb b/spec/html-proofer/images_spec.rb index 2e3a55f9..a8c9f8a7 100644 --- a/spec/html-proofer/images_spec.rb +++ b/spec/html-proofer/images_spec.rb @@ -180,7 +180,7 @@ it 'translates src via url_swap' do translate_src = "#{FIXTURES_DIR}/images/replace_abs_url_src.html" - proofer = run_proofer(translate_src, :file, { url_swap: { %r{^http://baseurl.com} => '' } }) + proofer = run_proofer(translate_src, :file, url_swap: { %r{^http://baseurl.com} => '' }) expect(proofer.failed_tests).to eq [] end diff --git a/spec/html-proofer/links_spec.rb b/spec/html-proofer/links_spec.rb index bf87b0c4..d3060c79 100644 --- a/spec/html-proofer/links_spec.rb +++ b/spec/html-proofer/links_spec.rb @@ -29,7 +29,7 @@ it 'passes for GitHub hashes to a file on the web when asked' do github_hash = "#{FIXTURES_DIR}/links/github_file_hash.html" - proofer = run_proofer(github_hash, :file, {check_external_hash: true}) + proofer = run_proofer(github_hash, :file, check_external_hash: true) expect(proofer.failed_tests).to eq [] end @@ -79,8 +79,20 @@ expect(proofer.failed_tests.first).to match(%r{internally linking to .\/notreal.html, which does not exist}) end - it 'succeeds for working internal-root-links pointing to other folder' do + it 'fails for broken internal root links' do + broken_root_link_internal_filepath = "#{FIXTURES_DIR}/links/broken_root_link_internal.html" + proofer = run_proofer(broken_root_link_internal_filepath, :file) + expect(proofer.failed_tests.first).to match(%r{internally linking to \/broken_root_link_internalz.html, which does not exist}) + end + + it 'succeeds for working internal root links' do broken_root_link_internal_filepath = "#{FIXTURES_DIR}/links/working_root_link_internal.html" + proofer = run_proofer(broken_root_link_internal_filepath, :file) + expect(proofer.failed_tests).to eq [] + end + + it 'succeeds for working internal-root-links pointing to other folder' do + broken_root_link_internal_filepath = "#{FIXTURES_DIR}/links/link_to_another_folder.html" proofer = run_proofer(broken_root_link_internal_filepath, :file, root_dir: 'spec/html-proofer/fixtures') expect(proofer.failed_tests).to eq [] end diff --git a/spec/html-proofer/middleware_spec.rb b/spec/html-proofer/middleware_spec.rb index 36a1bcd0..af608428 100644 --- a/spec/html-proofer/middleware_spec.rb +++ b/spec/html-proofer/middleware_spec.rb @@ -3,18 +3,18 @@ require 'spec_helper' describe 'Middleware test' do - let(:request) { {'REQUEST_METHOD' => 'GET'} } + let(:request) { { 'REQUEST_METHOD' => 'GET' } } let(:response) { File.open(response_fixture) } - let(:app) { Proc.new { |*args| [200, {}, response] } } + let(:app) { proc { |*_args| [200, {}, response] } } let(:middleware) { HTMLProofer::Middleware.new(app) } subject { middleware.call(request) } context 'with invalid HTML' do let(:response_fixture) { File.join(FIXTURES_DIR, 'html', 'missing_closing_quotes.html') } it 'raises an error' do - expect { + expect do subject - }.to raise_error(HTMLProofer::Middleware::InvalidHtmlError) + end.to raise_error(HTMLProofer::Middleware::InvalidHtmlError) end end @@ -33,7 +33,7 @@ end context 'proofer-ignore' do - let(:skip_request) { {'REQUEST_METHOD' => 'GET', 'QUERY_STRING' => 'proofer-ignore'} } + let(:skip_request) { { 'REQUEST_METHOD' => 'GET', 'QUERY_STRING' => 'proofer-ignore' } } let(:subject) { middleware.call(skip_request) } let(:response_fixture) { File.join(FIXTURES_DIR, 'html', 'missing_closing_quotes.html') } it 'does not raise an error' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7853539e..f9fcf900 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,7 +11,7 @@ require 'timecop' require_relative '../lib/html-proofer' -FIXTURES_DIR = 'spec/html-proofer/fixtures'.freeze +FIXTURES_DIR = 'spec/html-proofer/fixtures' RSpec.configure do |config| # Use color in STDOUT @@ -31,10 +31,10 @@ def capture_stderr(*) original_stderr = $stderr original_stdout = $stdout $stderr = fake_err = StringIO.new - $stdout = fake_out = StringIO.new unless ENV['VERBOSE'] + $stdout = StringIO.new unless ENV['VERBOSE'] begin yield - rescue RuntimeError + rescue RuntimeError # rubocop:disable Lint/HandleExceptions ensure $stderr = original_stderr $stdout = original_stdout unless ENV['VERBOSE']