Created
October 8, 2008 07:55
-
-
Save dkubb/15470 to your computer and use it in GitHub Desktop.
Ruby CSS Coverage Tester
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/opt/local/bin/ruby | |
# Copyright (c) 2007 Dan Kubb <[email protected]> | |
# 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