Class: Deadweight

Inherits:
Object
  • Object
show all
Defined in:
lib/deadweight.rb,
lib/deadweight/cli.rb,
lib/deadweight/hijack.rb,
lib/deadweight/rake_task.rb,
lib/deadweight/hijack/rails.rb,
lib/deadweight/rack/capturing_middleware.rb

Defined Under Namespace

Modules: Hijack, Rack Classes: CLI, FetchError, RakeTask

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeDeadweight



19
20
21
22
23
24
25
26
27
28
# File 'lib/deadweight.rb', line 19

def initialize
  @root = 'http://localhost:3000'
  @stylesheets = []
  @pages = []
  @rules = ""
  @ignore_selectors = []
  @mechanize = false
  @log_file = STDERR
  yield self and run if block_given?
end

Instance Attribute Details

#ignore_selectorsObject

Returns the value of attribute ignore_selectors



16
17
18
# File 'lib/deadweight.rb', line 16

def ignore_selectors
  @ignore_selectors
end

#log_fileObject

Returns the value of attribute log_file



16
17
18
# File 'lib/deadweight.rb', line 16

def log_file
  @log_file
end

#mechanizeObject

Returns the value of attribute mechanize



16
17
18
# File 'lib/deadweight.rb', line 16

def mechanize
  @mechanize
end

#pagesObject

Returns the value of attribute pages



16
17
18
# File 'lib/deadweight.rb', line 16

def pages
  @pages
end

#parsed_rulesObject (readonly)

Returns the value of attribute parsed_rules



17
18
19
# File 'lib/deadweight.rb', line 17

def parsed_rules
  @parsed_rules
end

#rootObject

Returns the value of attribute root



16
17
18
# File 'lib/deadweight.rb', line 16

def root
  @root
end

#rulesObject

Returns the value of attribute rules



16
17
18
# File 'lib/deadweight.rb', line 16

def rules
  @rules
end

#stylesheetsObject

Returns the value of attribute stylesheets



16
17
18
# File 'lib/deadweight.rb', line 16

def stylesheets
  @stylesheets
end

#unused_selectorsObject (readonly)

Returns the value of attribute unused_selectors



17
18
19
# File 'lib/deadweight.rb', line 17

def unused_selectors
  @unused_selectors
end

Instance Method Details

#add_css!(css) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/deadweight.rb', line 47

def add_css!(css)
  parser = CssParser::Parser.new
  parser.add_block!(css)

  selector_count = 0

  parser.each_selector do |selector, declarations, specificity|
    next if @unused_selectors.include?(selector)
    next if selector =~ @ignore_selectors
    next if has_pseudo_classes(selector) and @unused_selectors.include?(strip(selector))

    @unused_selectors << selector
    @parsed_rules[selector] = declarations

    selector_count += 1
  end

  selector_count
end

#agentObject

Returns the Mechanize instance, if mechanize is set to true.



137
138
139
# File 'lib/deadweight.rb', line 137

def agent
  @agent ||= initialize_agent
end

#analyze(html) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/deadweight.rb', line 30

def analyze(html)
  doc = Nokogiri::HTML(html)

  @unused_selectors.collect do |selector, declarations|
    # We test against the selector stripped of any pseudo classes,
    # but we report on the selector with its pseudo classes.
    stripped_selector = strip(selector)

    next if stripped_selector.empty?

    if doc.search(stripped_selector).any?
      log.puts("  #{selector.green}")
      selector
    end
  end
end

#dump(output) ⇒ Object



126
127
128
# File 'lib/deadweight.rb', line 126

def dump(output)
  output.puts(@unused_selectors)
end

#fetch(path) ⇒ Object

Fetch a path, using Mechanize if mechanize is set to true.



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/deadweight.rb', line 142

def fetch(path)
  log.puts(path)

  loc = root + path

  if @mechanize
    loc = "file://#{File.expand_path(loc)}" unless loc =~ %r{^\w+://}

    begin
      page = agent.get(loc)
    rescue Mechanize::ResponseCodeError => e
      raise FetchError.new("#{loc} returned a response code of #{e.response_code}")
    end

    log.puts("#{loc} redirected to #{page.uri}".red) unless page.uri.to_s == loc

    page.body
  else
    begin
      open(loc).read
    rescue Errno::ENOENT
      raise FetchError.new("#{loc} was not found")
    rescue OpenURI::HTTPError => e
      raise FetchError.new("retrieving #{loc} raised an HTTP error: #{e.message}")
    end
  end
end

#process!(html) ⇒ Object



130
131
132
133
134
# File 'lib/deadweight.rb', line 130

def process!(html)
  analyze(html).each do |selector|
    @unused_selectors.delete(selector)
  end
end

#reportObject



85
86
87
88
89
# File 'lib/deadweight.rb', line 85

def report
  log.puts
  log.puts "found #{@unused_selectors.size} unused selectors out of #{@total_selectors} total".yellow
  log.puts
end

#reset!Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/deadweight.rb', line 67

def reset!
  @parsed_rules     = {}
  @unused_selectors = []

  @stylesheets.each do |path|
    new_selector_count = add_css!(fetch(path))
    log.puts("  found #{new_selector_count} selectors".yellow)
  end

  if @rules and !@rules.empty?
    new_selector_count = add_css!(@rules)
    log.puts
    log.puts("Added #{new_selector_count} extra selectors".yellow)
  end

  @total_selectors = @unused_selectors.size
end

#runObject

Find all unused CSS selectors and return them as an array.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/deadweight.rb', line 92

def run
  reset!

  pages.each do |page|
    log.puts

    if page.respond_to?(:read)
      html = page.read
    elsif page.respond_to?(:call)
      result = instance_eval(&page)

      html = case result
             when String
               result
             else
               @agent.page.body
             end
    else
      begin
        html = fetch(page)
      rescue FetchError => e
        log.puts(e.message.red)
        next
      end
    end

    process!(html)
  end

  report

  @unused_selectors
end