Skip to content

Instantly share code, notes, and snippets.

@dkubb
Created October 8, 2008 07:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dkubb/15470 to your computer and use it in GitHub Desktop.
Save dkubb/15470 to your computer and use it in GitHub Desktop.
Ruby CSS Coverage Tester
#!/opt/local/bin/ruby
# Copyright (c) 2007 Dan Kubb <dan.kubb@gmail.com>
# This tool shows any CSS rules that do not apply to HTML. Accepts a single
# argument on the command line, may be either a URI or an HTML file.
require 'rubygems'
require 'csspool'
require 'hpricot'
require 'net/https'
require 'open-uri'
STRING_MATCH = /\s*(?:"(.+?)"|'(.+?)')\s*/
URL_PROPERTY_MATCH = /\s*url\((?:#{STRING_MATCH}|(.+?))\)/
AT_CHARSET_MATCH = /\s*@charset#{STRING_MATCH};/
AT_IMPORT_MATCH = /@import\s(?:#{URL_PROPERTY_MATCH}|#{STRING_MATCH}).*?;/
module Net
class HTTP
# allow testing of sites without valid certificates
def verify_mode=(verify_mode)
end
end
end
module OpenURI
class << self
# allow http and https URIs to redirect to themselves or each other
def redirectable_with_https?(uri1, uri2)
redirectable_without_https?(uri1, uri2) || ([ uri1.scheme, uri2.scheme ] - %w[ http https ]).empty?
end
alias_method :redirectable_without_https?, :redirectable?
alias_method :redirectable?, :redirectable_with_https?
end
end
open(ARGV.shift) do |file|
base = file.respond_to?(:base_uri) ? file.base_uri : ''
html_doc = Hpricot file
# find all linked and embedded stylesheets
css_source = html_doc.search('link[@rel][@href]|style').map do |tag|
case tag.name
when 'link' : open(base + tag[:href]).read if tag[:rel].downcase == 'stylesheet' # xpath/css cannot match case insensitively
when 'style' : tag.inner_html
end
end * ''
# recursively load @import stylesheets and insert them inline
1 while css_source.gsub!(AT_IMPORT_MATCH) do
open(base + Regexp.last_match.captures.compact.first).read.gsub(AT_CHARSET_MATCH, '') # strip embedded @charset at-rules
end
css_doc = CSS::SAC::Parser.new.parse css_source
# Find all CSS rules an HTML page does not use, minus psuedo-class selectors
# Output from most to least specific rules and show the specificity and name
(css_doc.rules - css_doc.find_all_rules_matching(html_doc)).sort.reverse.each do |rule|
next if rule.selector.respond_to?(:condition) && rule.selector.condition.kind_of?(CSS::SAC::Conditions::PseudoClassCondition)
puts "#{rule.selector.specificity.inspect}: #{rule.selector.to_css}"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment