blinkr 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/bin/blinkr +1 -0
- data/blinkr.gemspec +16 -8
- data/lib/blinkr.rb +2 -1
- data/lib/blinkr/cache.rb +5 -1
- data/lib/blinkr/config.rb +2 -1
- data/lib/blinkr/engine.rb +49 -36
- data/lib/blinkr/error.rb +30 -0
- data/lib/blinkr/extensions/a_title.rb +7 -1
- data/lib/blinkr/extensions/empty_a_href.rb +7 -1
- data/lib/blinkr/extensions/img_alt.rb +7 -1
- data/lib/blinkr/extensions/inline_css.rb +13 -2
- data/lib/blinkr/extensions/javascript.rb +5 -1
- data/lib/blinkr/extensions/links.rb +66 -22
- data/lib/blinkr/extensions/meta.rb +37 -8
- data/lib/blinkr/extensions/resources.rb +5 -1
- data/lib/blinkr/hacks.rb +20 -0
- data/lib/blinkr/http_utils.rb +10 -5
- data/lib/blinkr/manticore_wrapper.rb +59 -0
- data/lib/blinkr/phantomjs_wrapper.rb +22 -9
- data/lib/blinkr/report.html.slim +186 -210
- data/lib/blinkr/report.rb +22 -19
- data/lib/blinkr/sitemap.rb +5 -4
- data/lib/blinkr/typhoeus_wrapper.rb +19 -16
- data/lib/blinkr/version.rb +1 -1
- metadata +8 -6
- data/.gitignore +0 -18
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 2b54b1fe0983042827e5f00868dcf9e65ef5c2f2
         | 
| 4 | 
            +
              data.tar.gz: f90a1abe798a9e3cfaebe7544f0e618b4379116d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: bdbee3d503b16a6354a29171b775ff5bfb1667203529b158cc2e26ce3f58749402fea5098dd1a349387050d76e8454861dbe8919d8473cdf57e7d6205b6503c7
         | 
| 7 | 
            +
              data.tar.gz: bfc4cc60420fed8c53c20bcec5b224fb341a3e3a3d53a054aaa2e4cdff2575d5f5b0f62b391c459b4df89cae5875e7b1353ab23723ac99138cd70d13aba7d460
         | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/bin/blinkr
    CHANGED
    
    
    
        data/blinkr.gemspec
    CHANGED
    
    | @@ -4,26 +4,34 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) | |
| 4 4 | 
             
            require 'blinkr/version'
         | 
| 5 5 |  | 
| 6 6 | 
             
            Gem::Specification.new do |spec|
         | 
| 7 | 
            -
              spec.name | 
| 7 | 
            +
              spec.name = 'blinkr'
         | 
| 8 8 | 
             
              spec.version       = Blinkr::VERSION
         | 
| 9 | 
            -
              spec.authors | 
| 10 | 
            -
              spec.email | 
| 9 | 
            +
              spec.authors = ['Pete Muir', 'Jason Porter']
         | 
| 10 | 
            +
              spec.email = %w(pmuir@bleepbleep.org.uk lightguard.jp@gmail.com)
         | 
| 11 11 | 
             
              spec.summary       = %q{A simple broken link checker}
         | 
| 12 12 | 
             
              spec.description   = %q{A broken page and link checker for websites. Optionally uses phantomjs to render pages to check resource loading, links created by JS, and report any JS page load errors.}
         | 
| 13 | 
            -
              spec.homepage | 
| 14 | 
            -
              spec.license | 
| 13 | 
            +
              spec.homepage = 'https://github.com/pmuir/blinkr'
         | 
| 14 | 
            +
              spec.license = 'Apache-2.0'
         | 
| 15 15 |  | 
| 16 16 | 
             
              spec.files         = `git ls-files`.split($/)
         | 
| 17 | 
            +
              spec.files         -= ['.gitignore', '.ruby-version', '.ruby-gemset']
         | 
| 18 | 
            +
             | 
| 19 | 
            +
             | 
| 17 20 | 
             
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         | 
| 18 21 | 
             
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         | 
| 19 | 
            -
              spec.require_paths = [ | 
| 22 | 
            +
              spec.require_paths = ['lib']
         | 
| 20 23 |  | 
| 21 | 
            -
              spec.required_ruby_version = '~>  | 
| 24 | 
            +
              spec.required_ruby_version = '~> 1.9'
         | 
| 22 25 |  | 
| 23 | 
            -
              spec.add_development_dependency  | 
| 26 | 
            +
              spec.add_development_dependency 'bundler', '~> 1.5'
         | 
| 24 27 | 
             
              spec.add_development_dependency 'rake', '~> 10.3'
         | 
| 25 28 | 
             
              spec.add_dependency 'nokogiri', '~> 1.5'
         | 
| 26 29 | 
             
              spec.add_dependency 'typhoeus', '~> 0.7'
         | 
| 27 30 | 
             
              spec.add_dependency 'slim', '~> 3.0'
         | 
| 28 31 | 
             
              spec.add_dependency 'parallel', '~> 1.3'
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              if defined? JRUBY_VERSION
         | 
| 34 | 
            +
                spec.platform = 'java'
         | 
| 35 | 
            +
                spec.add_dependency 'manticore', '~> 0.4'
         | 
| 36 | 
            +
              end
         | 
| 29 37 | 
             
            end
         | 
    
        data/lib/blinkr.rb
    CHANGED
    
    | @@ -2,12 +2,13 @@ require 'blinkr/version' | |
| 2 2 | 
             
            require 'blinkr/engine'
         | 
| 3 3 | 
             
            require 'blinkr/report'
         | 
| 4 4 | 
             
            require 'blinkr/config'
         | 
| 5 | 
            +
            require 'blinkr/error'
         | 
| 5 6 | 
             
            require 'blinkr/typhoeus_wrapper'
         | 
| 6 7 | 
             
            require 'yaml'
         | 
| 7 8 |  | 
| 8 9 | 
             
            module Blinkr
         | 
| 9 10 | 
             
              def self.run(base_url, config = 'blinkr.yaml', single, verbose, vverbose)
         | 
| 10 | 
            -
                args = { | 
| 11 | 
            +
                args = {:base_url => base_url, :verbose => verbose, :vverbose => vverbose}
         | 
| 11 12 | 
             
                if !config.nil? && File.exists?(config)
         | 
| 12 13 | 
             
                  config = Blinkr::Config.read config, args
         | 
| 13 14 | 
             
                else
         | 
    
        data/lib/blinkr/cache.rb
    CHANGED
    
    | @@ -9,7 +9,11 @@ module Blinkr | |
| 9 9 | 
             
                end
         | 
| 10 10 |  | 
| 11 11 | 
             
                def set(request, response)
         | 
| 12 | 
            -
                   | 
| 12 | 
            +
                  if request.is_a? String # HACK for caching resource and js errors
         | 
| 13 | 
            +
                    @memory[request] = response
         | 
| 14 | 
            +
                  else
         | 
| 15 | 
            +
                    @memory[request] = response unless response.timed_out?
         | 
| 16 | 
            +
                  end
         | 
| 13 17 | 
             
                end
         | 
| 14 18 |  | 
| 15 19 | 
             
                def size
         | 
    
        data/lib/blinkr/config.rb
    CHANGED
    
    | @@ -8,7 +8,8 @@ module Blinkr | |
| 8 8 | 
             
                  Config.new(YAML.load_file(file).merge(args).merge({ :config_file => file }))
         | 
| 9 9 | 
             
                end
         | 
| 10 10 |  | 
| 11 | 
            -
                DEFAULTS = {:skips => [], :ignores => [], :max_retrys => 3, :browser => 'typhoeus', | 
| 11 | 
            +
                DEFAULTS = {:skips => [], :ignores => [], :max_retrys => 3, :browser => 'typhoeus',
         | 
| 12 | 
            +
                            :viewport => 1200, :phantomjs_threads => 8, :report => 'blinkr.html'}
         | 
| 12 13 |  | 
| 13 14 | 
             
                def initialize(hash={})
         | 
| 14 15 | 
             
                  super(DEFAULTS.merge(hash))
         | 
    
        data/lib/blinkr/engine.rb
    CHANGED
    
    | @@ -9,6 +9,8 @@ require 'blinkr/extensions/javascript' | |
| 9 9 | 
             
            require 'blinkr/extensions/resources'
         | 
| 10 10 | 
             
            require 'blinkr/extensions/pipeline'
         | 
| 11 11 | 
             
            require 'json'
         | 
| 12 | 
            +
            require 'pathname'
         | 
| 13 | 
            +
            require 'fileutils'
         | 
| 12 14 | 
             
            require 'ostruct'
         | 
| 13 15 |  | 
| 14 16 | 
             
            # Monkeypatch OpenStruct
         | 
| @@ -27,7 +29,7 @@ module Blinkr | |
| 27 29 | 
             
                include HttpUtils
         | 
| 28 30 | 
             
                include Sitemap
         | 
| 29 31 |  | 
| 30 | 
            -
                def initialize | 
| 32 | 
            +
                def initialize(config)
         | 
| 31 33 | 
             
                  @config = config.validate
         | 
| 32 34 | 
             
                  @extensions = []
         | 
| 33 35 | 
             
                  load_pipeline
         | 
| @@ -35,15 +37,25 @@ module Blinkr | |
| 35 37 |  | 
| 36 38 | 
             
                def run
         | 
| 37 39 | 
             
                  context = OpenStruct.new({:pages => {}})
         | 
| 38 | 
            -
                   | 
| 40 | 
            +
                  if defined?(JRUBY_VERSION) && @config.browser == 'manticore'
         | 
| 41 | 
            +
                    require 'blinkr/manticore_wrapper'
         | 
| 42 | 
            +
                    bulk_browser = browser = ManticoreWrapper.new(@config, context)
         | 
| 43 | 
            +
                  else
         | 
| 44 | 
            +
                    bulk_browser = browser = TyphoeusWrapper.new(@config, context)
         | 
| 45 | 
            +
                  end
         | 
| 39 46 | 
             
                  browser = PhantomJSWrapper.new(@config, context) if @config.browser == 'phantomjs'
         | 
| 40 47 | 
             
                  page_count = 0
         | 
| 41 | 
            -
                   | 
| 48 | 
            +
                  urls = sitemap_locations.uniq
         | 
| 49 | 
            +
                  puts "Fetching #{urls.size} pages from sitemap"
         | 
| 50 | 
            +
                  browser.process_all(urls, @config.max_page_retrys) do |response, resource_errors, javascript_errors|
         | 
| 51 | 
            +
                    url = response.request.base_url
         | 
| 42 52 | 
             
                    if response.success?
         | 
| 43 | 
            -
                      url = response.request.base_url
         | 
| 44 53 | 
             
                      puts "Loaded page #{url}" if @config.verbose
         | 
| 45 54 | 
             
                      body = Nokogiri::HTML(response.body)
         | 
| 46 | 
            -
                      page = OpenStruct.new({ | 
| 55 | 
            +
                      page = OpenStruct.new({:response => response, :body => body.freeze,
         | 
| 56 | 
            +
                                             :errors => ErrorArray.new(@config),
         | 
| 57 | 
            +
                                             :resource_errors => resource_errors || [],
         | 
| 58 | 
            +
                                             :javascript_errors => javascript_errors || []})
         | 
| 47 59 | 
             
                      context.pages[url] = page
         | 
| 48 60 | 
             
                      collect page
         | 
| 49 61 | 
             
                      page_count += 1
         | 
| @@ -51,25 +63,26 @@ module Blinkr | |
| 51 63 | 
             
                      puts "#{response.code} #{response.status_message} Unable to load page #{url} #{'(' + response.return_message + ')' unless response.return_message.nil?}"
         | 
| 52 64 | 
             
                    end
         | 
| 53 65 | 
             
                  end
         | 
| 54 | 
            -
                   | 
| 55 | 
            -
                   | 
| 56 | 
            -
                  puts "Loaded #{page_count} pages using #{browser.name}. | 
| 57 | 
            -
                   | 
| 66 | 
            +
                  puts 'Executing Typhoeus::Hydra.run, this could take awhile' if @config.browser == 'typhoeus'
         | 
| 67 | 
            +
                  # browser.hydra.run if @config.browser == 'typhoeus'
         | 
| 68 | 
            +
                  puts "Loaded #{page_count} pages using #{browser.name}."
         | 
| 69 | 
            +
                  puts 'Analyzing pages'
         | 
| 70 | 
            +
                  analyze context, bulk_browser
         | 
| 71 | 
            +
                  context.pages.reject! { |_, page| page.errors.empty? }
         | 
| 72 | 
            +
             | 
| 58 73 | 
             
                  unless @config.export.nil?
         | 
| 59 | 
            -
                     | 
| 60 | 
            -
                      file.write(context.to_json)
         | 
| 61 | 
            -
                    end
         | 
| 74 | 
            +
                    FileUtils.mkdir_p Pathname.new(@config.report).parent
         | 
| 62 75 | 
             
                  end
         | 
| 63 76 | 
             
                  Blinkr::Report.new(context, self, @config).render
         | 
| 64 77 | 
             
                end
         | 
| 65 78 |  | 
| 66 | 
            -
                def append | 
| 67 | 
            -
                   | 
| 79 | 
            +
                def append(context)
         | 
| 80 | 
            +
                  execute :append, context
         | 
| 68 81 | 
             
                end
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                def transform | 
| 82 | 
            +
             | 
| 83 | 
            +
                def transform(page, error, &block)
         | 
| 71 84 | 
             
                  default = yield
         | 
| 72 | 
            -
                  result =  | 
| 85 | 
            +
                  result = execute(:transform, page, error, default)
         | 
| 73 86 | 
             
                  if result.empty?
         | 
| 74 87 | 
             
                    default
         | 
| 75 88 | 
             
                  else
         | 
| @@ -77,33 +90,33 @@ module Blinkr | |
| 77 90 | 
             
                  end
         | 
| 78 91 | 
             
                end
         | 
| 79 92 |  | 
| 80 | 
            -
                def analyze | 
| 81 | 
            -
                   | 
| 93 | 
            +
                def analyze(context, typhoeus)
         | 
| 94 | 
            +
                  execute :analyze, context, typhoeus
         | 
| 82 95 | 
             
                end
         | 
| 83 96 |  | 
| 84 | 
            -
                def collect | 
| 85 | 
            -
                   | 
| 97 | 
            +
                def collect(page)
         | 
| 98 | 
            +
                  execute :collect, page
         | 
| 86 99 | 
             
                end
         | 
| 87 100 |  | 
| 88 101 | 
             
                private
         | 
| 89 102 |  | 
| 90 103 | 
             
                class ErrorArray < Array
         | 
| 91 104 |  | 
| 92 | 
            -
                  def initialize | 
| 105 | 
            +
                  def initialize(config)
         | 
| 93 106 | 
             
                    @config = config
         | 
| 94 107 | 
             
                  end
         | 
| 95 108 |  | 
| 96 | 
            -
                  def << | 
| 97 | 
            -
                     | 
| 98 | 
            -
                      super
         | 
| 99 | 
            -
                    else
         | 
| 109 | 
            +
                  def <<(error)
         | 
| 110 | 
            +
                    if @config.ignored?(error.url, error.code, error.message)
         | 
| 100 111 | 
             
                      self
         | 
| 112 | 
            +
                    else
         | 
| 113 | 
            +
                      super
         | 
| 101 114 | 
             
                    end
         | 
| 102 115 | 
             
                  end
         | 
| 103 116 |  | 
| 104 117 | 
             
                end
         | 
| 105 118 |  | 
| 106 | 
            -
                def extension | 
| 119 | 
            +
                def extension(ext)
         | 
| 107 120 | 
             
                  @extensions << ext
         | 
| 108 121 | 
             
                end
         | 
| 109 122 |  | 
| @@ -113,7 +126,7 @@ module Blinkr | |
| 113 126 | 
             
                  extension Blinkr::Extensions::Resources.new @config
         | 
| 114 127 | 
             
                end
         | 
| 115 128 |  | 
| 116 | 
            -
                def  | 
| 129 | 
            +
                def execute(method, *args)
         | 
| 117 130 | 
             
                  result = []
         | 
| 118 131 | 
             
                  @extensions.each do |e|
         | 
| 119 132 | 
             
                    result << e.send(method, *args) if e.respond_to? method
         | 
| @@ -122,24 +135,24 @@ module Blinkr | |
| 122 135 | 
             
                end
         | 
| 123 136 |  | 
| 124 137 | 
             
                def load_pipeline
         | 
| 125 | 
            -
                   | 
| 138 | 
            +
                  if @config.pipeline.nil?
         | 
| 139 | 
            +
                    puts 'Loaded default pipeline' if @config.verbose
         | 
| 140 | 
            +
                    default_pipeline
         | 
| 141 | 
            +
                  else
         | 
| 126 142 | 
             
                    pipeline_file = File.join(File.dirname(@config.config_file), @config.pipeline)
         | 
| 127 | 
            -
                    if | 
| 128 | 
            -
                      p = eval(File.read( | 
| 143 | 
            +
                    if File.exists?(pipeline_file)
         | 
| 144 | 
            +
                      p = eval(File.read(pipeline_file), nil, pipeline_file, 1).load @config
         | 
| 129 145 | 
             
                      p.extensions.each do |e|
         | 
| 130 | 
            -
                        extension( | 
| 146 | 
            +
                        extension(e)
         | 
| 131 147 | 
             
                      end
         | 
| 132 148 | 
             
                      if @config.verbose
         | 
| 133 149 | 
             
                        puts "Loaded custom pipeline from #{@config.pipeline}"
         | 
| 134 | 
            -
                        pipeline = @extensions.inject{|memo, v| "#{memo}, #{v}" }
         | 
| 150 | 
            +
                        pipeline = @extensions.inject { |memo, v| "#{memo}, #{v}" }
         | 
| 135 151 | 
             
                        puts "Pipeline: #{pipeline}"
         | 
| 136 152 | 
             
                      end
         | 
| 137 153 | 
             
                    else
         | 
| 138 154 | 
             
                      raise "Cannot find pipeline file #{pipeline_file}"
         | 
| 139 155 | 
             
                    end
         | 
| 140 | 
            -
                  else
         | 
| 141 | 
            -
                    puts "Loaded default pipeline" if @config.verbose
         | 
| 142 | 
            -
                    default_pipeline
         | 
| 143 156 | 
             
                  end
         | 
| 144 157 | 
             
                end
         | 
| 145 158 |  | 
    
        data/lib/blinkr/error.rb
    ADDED
    
    | @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module Blinkr
         | 
| 2 | 
            +
              SEVERITY = [:success, :info, :warning, :danger]
         | 
| 3 | 
            +
              class Error
         | 
| 4 | 
            +
                attr_reader :severity, :category, :type, :title, :message, :snippet, :icon, :code, :detail, :url
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def initialize (opts = {})
         | 
| 7 | 
            +
                  raise TypeError 'severity must be a string or symbol' unless opts[:severity].is_a?(String) || opts[:severity].is_a?(Symbol)
         | 
| 8 | 
            +
                  raise 'severity not a recognized value' unless SEVERITY.include? opts[:severity].to_sym
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  @severity = opts[:severity]
         | 
| 11 | 
            +
                  @category = opts[:category]
         | 
| 12 | 
            +
                  @type = opts[:type]
         | 
| 13 | 
            +
                  @title = opts[:title]
         | 
| 14 | 
            +
                  @message = opts[:message]
         | 
| 15 | 
            +
                  @snippet = opts[:snippet]
         | 
| 16 | 
            +
                  @icon = opts[:icon]
         | 
| 17 | 
            +
                  @code = opts[:code]
         | 
| 18 | 
            +
                  @url = opts[:url]
         | 
| 19 | 
            +
                  @detail = opts[:detail]
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def to_json(*args)
         | 
| 23 | 
            +
                  content = {}
         | 
| 24 | 
            +
                  instance_variables.each do |v|
         | 
| 25 | 
            +
                    content[v.to_s[1..-1]] = instance_variable_get v
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                  content.to_json
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require 'blinkr/error'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Blinkr
         | 
| 2 4 | 
             
              module Extensions
         | 
| 3 5 | 
             
                class ATitle
         | 
| @@ -8,7 +10,11 @@ module Blinkr | |
| 8 10 |  | 
| 9 11 | 
             
                  def collect page
         | 
| 10 12 | 
             
                    page.body.css('a:not([title])').each do |a|
         | 
| 11 | 
            -
                      page.errors <<  | 
| 13 | 
            +
                      page.errors << Blinkr::Error.new({:severity => 'info', :category => 'SEO',
         | 
| 14 | 
            +
                                                        :type => '<a title=""> missing',
         | 
| 15 | 
            +
                                                        :title => "#{a['href']} (line #{a.line})",
         | 
| 16 | 
            +
                                                        :message => '<a title=""> missing',
         | 
| 17 | 
            +
                                                        :snippet => a.to_s, :icon => 'fa-info'})
         | 
| 12 18 | 
             
                    end
         | 
| 13 19 | 
             
                  end
         | 
| 14 20 |  | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require 'blinkr/error'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Blinkr
         | 
| 2 4 | 
             
              module Extensions
         | 
| 3 5 | 
             
                class EmptyAHref
         | 
| @@ -9,7 +11,11 @@ module Blinkr | |
| 9 11 | 
             
                  def collect page
         | 
| 10 12 | 
             
                    page.body.css('a[href]').each do |a|
         | 
| 11 13 | 
             
                      if a['href'].empty?
         | 
| 12 | 
            -
                        page.errors <<  | 
| 14 | 
            +
                        page.errors << Blinkr::Error.new({:severity => 'info', :category => 'HTML Compatibility/Correctness',
         | 
| 15 | 
            +
                                                          :type => '<a href=""> empty',
         | 
| 16 | 
            +
                                                          :title => %Q{<a href=""> empty (line #{a.line})},
         | 
| 17 | 
            +
                                                          :message => %Q{<a href=""> empty}, :snippet => a.to_s,
         | 
| 18 | 
            +
                                                          :icon => 'fa-info'})
         | 
| 13 19 | 
             
                      end
         | 
| 14 20 | 
             
                    end
         | 
| 15 21 | 
             
                  end
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require 'blinkr/error'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Blinkr
         | 
| 2 4 | 
             
              module Extensions
         | 
| 3 5 | 
             
                class ImgAlt
         | 
| @@ -8,7 +10,11 @@ module Blinkr | |
| 8 10 |  | 
| 9 11 | 
             
                  def collect page
         | 
| 10 12 | 
             
                    page.body.css('img:not([alt])').each do |img|
         | 
| 11 | 
            -
                      page.errors << OpenStruct.new({ | 
| 13 | 
            +
                      page.errors << OpenStruct.new({:severity => 'warning', :category => 'SEO',
         | 
| 14 | 
            +
                                                     :type => '<img alt=""> missing',
         | 
| 15 | 
            +
                                                     :title => "#{img['src']} (line #{img.line})",
         | 
| 16 | 
            +
                                                     :message => '<img alt=""> missing', :snippet => img.to_s,
         | 
| 17 | 
            +
                                                     :icon => 'fa-info'})
         | 
| 12 18 | 
             
                    end
         | 
| 13 19 | 
             
                  end
         | 
| 14 20 |  | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require 'blinkr/error'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Blinkr
         | 
| 2 4 | 
             
              module Extensions
         | 
| 3 5 | 
             
                class InlineCss
         | 
| @@ -9,9 +11,18 @@ module Blinkr | |
| 9 11 | 
             
                  def collect page
         | 
| 10 12 | 
             
                    page.body.css('[style]').each do |elm|
         | 
| 11 13 | 
             
                      if elm['style'] == ""
         | 
| 12 | 
            -
                        page.errors <<  | 
| 14 | 
            +
                        page.errors << Blinkr::Error.new({:severity => 'info', :category => 'HTML Compatibility/Correctness',
         | 
| 15 | 
            +
                                                          :type => 'style attribute is empty',
         | 
| 16 | 
            +
                                                          :title => %Q{"#{elm['style']}" (line #{elm.line})},
         | 
| 17 | 
            +
                                                          :message => 'style attribute is empty', :snippet => elm.to_s,
         | 
| 18 | 
            +
                                                          :icon => 'fa-info'})
         | 
| 13 19 | 
             
                      else
         | 
| 14 | 
            -
                        page.errors <<  | 
| 20 | 
            +
                        page.errors << Blinkr::Error.new({:severity => 'info',
         | 
| 21 | 
            +
                                                          :category => 'HTML Compatibility/Correctness',
         | 
| 22 | 
            +
                                                          :type => 'Inline CSS detected',
         | 
| 23 | 
            +
                                                          :title => %Q{"#{elm['style']}" (line #{elm.line})},
         | 
| 24 | 
            +
                                                          :message => 'inline style', :snippet => elm.to_s,
         | 
| 25 | 
            +
                                                          :icon => 'fa-info'})
         | 
| 15 26 | 
             
                      end
         | 
| 16 27 | 
             
                    end
         | 
| 17 28 | 
             
                  end
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require 'blinkr/error'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Blinkr
         | 
| 2 4 | 
             
              module Extensions
         | 
| 3 5 | 
             
                class JavaScript
         | 
| @@ -8,7 +10,9 @@ module Blinkr | |
| 8 10 |  | 
| 9 11 | 
             
                  def collect page
         | 
| 10 12 | 
             
                    page.javascript_errors.each do |error|
         | 
| 11 | 
            -
                      page.errors <<  | 
| 13 | 
            +
                      page.errors << Blinkr::Error.new(:severity => 'danger', :category => 'JavaScript',
         | 
| 14 | 
            +
                                                       :type => 'JavaScript error', :title => error['msg'],
         | 
| 15 | 
            +
                                                       :snippet => error['trace'], :icon => 'fa-gears')
         | 
| 12 16 | 
             
                    end
         | 
| 13 17 | 
             
                  end
         | 
| 14 18 |  | 
| @@ -1,50 +1,94 @@ | |
| 1 | 
            +
            require 'uri'
         | 
| 2 | 
            +
            require 'blinkr/error'
         | 
| 1 3 | 
             
            require 'blinkr/http_utils'
         | 
| 2 4 |  | 
| 3 5 | 
             
            module Blinkr
         | 
| 4 6 | 
             
              module Extensions
         | 
| 5 7 | 
             
                class Links
         | 
| 6 | 
            -
                  include HttpUtils
         | 
| 8 | 
            +
                  include Blinkr::HttpUtils
         | 
| 7 9 |  | 
| 8 | 
            -
                  def initialize | 
| 10 | 
            +
                  def initialize(config)
         | 
| 9 11 | 
             
                    @config = config
         | 
| 10 12 | 
             
                    @links = {}
         | 
| 11 13 | 
             
                  end
         | 
| 12 14 |  | 
| 13 | 
            -
                  def collect | 
| 15 | 
            +
                  def collect(page)
         | 
| 14 16 | 
             
                    page.body.css('a[href]').each do |a|
         | 
| 15 17 | 
             
                      attr = a.attribute('href')
         | 
| 16 18 | 
             
                      src = page.response.effective_url
         | 
| 17 19 | 
             
                      url = attr.value
         | 
| 18 | 
            -
                       | 
| 19 | 
            -
             | 
| 20 | 
            -
                         | 
| 21 | 
            -
             | 
| 20 | 
            +
                      unless @config.skipped?(url)
         | 
| 21 | 
            +
                        url = sanitize url, src
         | 
| 22 | 
            +
                        unless url.nil?
         | 
| 23 | 
            +
                          @links[url] ||= []
         | 
| 24 | 
            +
                          @links[url] << {:page => page, :line => attr.line, :snippet => attr.parent.to_s}
         | 
| 25 | 
            +
                        end
         | 
| 22 26 | 
             
                      end
         | 
| 23 27 | 
             
                    end
         | 
| 24 28 | 
             
                  end
         | 
| 25 29 |  | 
| 26 | 
            -
                  def analyze | 
| 27 | 
            -
                    puts  | 
| 28 | 
            -
                    puts " #{@links.length} links to check " | 
| 29 | 
            -
                    puts  | 
| 30 | 
            -
                    @links. | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 30 | 
            +
                  def analyze(context, browser)
         | 
| 31 | 
            +
                    puts '----------------------'
         | 
| 32 | 
            +
                    puts " #{@links.length} links to check "
         | 
| 33 | 
            +
                    puts '----------------------'
         | 
| 34 | 
            +
                    external_links = @links.reject { |k| k.start_with? @config.base_url }
         | 
| 35 | 
            +
                    processed = 0
         | 
| 36 | 
            +
                    # Find the internal links
         | 
| 37 | 
            +
                    @links.select{|k| k.start_with? @config.base_url}.each do |url, locations|
         | 
| 38 | 
            +
                      link = URI.parse(url)
         | 
| 39 | 
            +
                      link.fragment = nil
         | 
| 40 | 
            +
                      link.query = nil
         | 
| 41 | 
            +
                      unless context.pages.keys.include?(link.to_s) || context.pages.keys.include?((link.to_s + '/'))
         | 
| 42 | 
            +
                        locations.each do |location|
         | 
| 43 | 
            +
                          location[:page].errors << Blinkr::Error.new({:severity => :warning,
         | 
| 44 | 
            +
                                                                       :category => 'Resource missing from sitemap',
         | 
| 45 | 
            +
                                                                       :type => '<a href=""> target missing from sitemap',
         | 
| 46 | 
            +
                                                                       :url => url, :title => "#{url} (line #{location[:line]})",
         | 
| 47 | 
            +
                                                                       :code => nil,
         | 
| 48 | 
            +
                                                                       :message => 'Missing from sitemap',
         | 
| 49 | 
            +
                                                                       :detail => 'Checked with Typheous',
         | 
| 50 | 
            +
                                                                       :snippet => location[:snippet],
         | 
| 51 | 
            +
                                                                       :icon => 'fa-bookmark-o'
         | 
| 52 | 
            +
                                                                      })
         | 
| 53 | 
            +
                          # It wasn't in the sitemap, so we'll add it to the "external_links" to still be checked
         | 
| 54 | 
            +
                          external_links[url] = locations
         | 
| 55 | 
            +
                        end
         | 
| 56 | 
            +
                      end
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
                    external_links.each do |url, metadata|
         | 
| 59 | 
            +
                      # if link start_with? @config.base_url check to see if it's in the sitemap.xml
         | 
| 60 | 
            +
                      browser.process(url, @config.max_retrys, :method => :get, :followlocation => true) do |resp|
         | 
| 61 | 
            +
                        puts "Loaded #{url} via #{browser.name} #{'(cached)' if resp.cached?}" if @config.verbose
         | 
| 62 | 
            +
                        if resp.code.to_i < 200 || resp.code.to_i > 300
         | 
| 63 | 
            +
                          response = resp
         | 
| 64 | 
            +
             | 
| 34 65 | 
             
                          metadata.each do |src|
         | 
| 35 | 
            -
                             | 
| 36 | 
            -
                            if  | 
| 37 | 
            -
                              message =  | 
| 66 | 
            +
                            detail = nil
         | 
| 67 | 
            +
                            if response.status_message.nil?
         | 
| 68 | 
            +
                              message = response.return_message
         | 
| 38 69 | 
             
                            else
         | 
| 39 | 
            -
                              message =  | 
| 40 | 
            -
                              detail =  | 
| 70 | 
            +
                              message = response.status_message
         | 
| 71 | 
            +
                              detail = response.return_message unless resp.return_message == 'No error'
         | 
| 72 | 
            +
                            end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                            severity = :danger
         | 
| 75 | 
            +
                            if response.code.to_i >= 300 && response.code.to_i < 400
         | 
| 76 | 
            +
                              severity = :warning
         | 
| 41 77 | 
             
                            end
         | 
| 42 | 
            -
                            src[:page].errors <<  | 
| 78 | 
            +
                            src[:page].errors << Blinkr::Error.new({:severity => severity,
         | 
| 79 | 
            +
                            :category => 'Resources missing',
         | 
| 80 | 
            +
                            :type => '<a href=""> target cannot be loaded',
         | 
| 81 | 
            +
                            :url => url, :title => "#{url} (line #{src[:line]})",
         | 
| 82 | 
            +
                            :code => response.code.to_i, :message => message,
         | 
| 83 | 
            +
                            :detail => detail, :snippet => src[:snippet],
         | 
| 84 | 
            +
                            :icon => 'fa-bookmark-o'}) unless response.success?
         | 
| 43 85 | 
             
                          end
         | 
| 44 86 | 
             
                        end
         | 
| 87 | 
            +
                        processed += 1
         | 
| 88 | 
            +
                        puts "Processed #{processed} of #{external_links.size}" if @config.verbose
         | 
| 45 89 | 
             
                      end
         | 
| 46 90 | 
             
                    end
         | 
| 47 | 
            -
                     | 
| 91 | 
            +
                    browser.hydra.run if browser.is_a? Blinkr::TyphoeusWrapper
         | 
| 48 92 | 
             
                  end
         | 
| 49 93 |  | 
| 50 94 | 
             
                end
         |