Class: FlogGauntlet

Inherits:
Gauntlet
  • Object
show all
Defined in:
lib/gauntlet_flog.rb

Overview

:stopdoc:

Constant Summary collapse

MY_PROJECTS =
Regexp.union(*my_projects)

Instance Method Summary collapse

Instance Method Details

#display_report(max = 10) ⇒ Object


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/gauntlet_flog.rb', line 38

def display_report max = 10
  scores = @data.reject { |k,v| v[:total].nil? or v[:methods].empty? }
  project_numbers = scores.map { |k,v| [k, v[:methods].values] }
  project_stats = project_numbers.map { |k,v| [k, scores[k][:size], v.average, v.stddev] }

  method_count = 0
  project_stats.each do |_, n, _, _|
    method_count += n
  end

  group_by_owner

  title "Statistics" do
    flog_numbers = scores.map { |k,v| v[:total] }
    method_counts = scores.map { |k,v| v[:size] }

    puts "total # gems      : %8d" % scores.size
    puts "total # methods   : %8d" % method_count
    puts "avg methods / gem : %8.2f (%8.2f stddev)" % [method_counts.average, method_counts.stddev]
    puts "avg flog / gem    : %8.2f (%8.2f stddev)" % [flog_numbers.average, flog_numbers.stddev]
  end

  worst = scores.sort_by { |k,v| -v[:total] }.first(max)
  report_worst "Worst Projects EVAR", worst do |project, score|
    owner = $owners[project].join(', ') rescue nil
    owner = "Some Lazy Bastard" if owner.empty?
    raise "#{project} seems not to have an owner" if owner.nil?
    [score[:total], project, owner]
  end

  worst = {}
  scores.each do |long_name, spec|
    name = long_name.sub(/-(\d+\.)*\d+\.gem$/, '')
    spec[:methods].each do |method_name, score|
      worst[[name, method_name]] = score
    end
  end

  worst = worst.sort_by { |_,v| -v }.first(max)

  max_size = worst.map { |(name, meth), score| name.size }.max
  title "Worth Methods EVAR"
  worst.each_with_index do |((name, meth), score), i|
    puts "%3d: %9.2f: %-#{max_size}s %s" % [i + 1, score, name, meth]
  end

  report "Methods per Gem", project_stats.sort_by { |n, c, a, sd| -c }.first(max)
  report "Avg Flog / Method", project_stats.sort_by { |n, c, a, sd| -a }.first(max)

  $score_per_owner = Hash.new(0.0)
  $projects_per_owner = Hash.new { |h,k| h[k] = {} }
  $owners.each do |project, owners|
    next unless scores.has_key? project # bad project
    owners.each do |owner|
      next if owner =~ /FI\XME full name|NOT Ryan Davis/
      score = scores[project][:total] || 1000000
      $projects_per_owner[owner][project] = score
      $score_per_owner[owner] += score
    end
  end

  report_bad_people "Top Flog Scores per Developer" do
    $projects_per_owner.sort_by { |k,v| -v.values.average }.first(max)
  end

  report_bad_people "Most Prolific Developers" do |k,v|
    $projects_per_owner.sort_by { |k,v| [-v.size, -$score_per_owner[k]] }.first(max)
  end
end

#group_by_ownerObject


173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/gauntlet_flog.rb', line 173

def group_by_owner
  latest_gems.each do |spec|
    name  = spec.name
    owner = spec.authors.compact
    owner = Array(spec.email) if owner.empty?
    owner.map! { |o| o.sub(/\s*[^ \[email protected]].*$/, '') }
    owner = ["NOT Ryan Davis"] if owner.include? "Ryan Davis" and name !~ MY_PROJECTS

    # because we screwed these up back before hoe
    owner << "Eric Hodel" if name =~ /bfts|RubyToC|ParseTree|heckle/

    $owners[spec.full_name] = owner.uniq || 'omg I have no idea'
  end
end

#report(title, data) ⇒ Object


144
145
146
147
148
149
150
151
# File 'lib/gauntlet_flog.rb', line 144

def report title, data
  max = data.map { |d| d.first.size }.max

  title "Top #{data.size} #{title}" if title
  data.each_with_index do |(n, c, a, s), i|
    puts "%4d: %-#{max}s: %5d methods, %8.2f +/- %8.2f flog" % [i + 1, n, c, a, s]
  end
end

#report_bad_people(section) ⇒ Object


153
154
155
156
157
158
159
160
161
162
# File 'lib/gauntlet_flog.rb', line 153

def report_bad_people section
  title section
  bad_people = yield
  max_size = bad_people.map { |a| a.first.size }.max
  fmt = "%4d: %-#{max_size}s: %2d projects %8.1f tot %8.1f avg"
  bad_people.each_with_index do |(name, projects), i|
    avg = projects.values.average
    puts fmt % [i + 1, name, projects.size, $score_per_owner[name], avg]
  end
end

#report_worst(section, data) ⇒ Object


164
165
166
167
168
169
170
171
# File 'lib/gauntlet_flog.rb', line 164

def report_worst section, data
  title section do
    max_size = data.map { |k| k.first.size }.max
    data.each_with_index do |(k,v), i|
      puts "%3d: %9.2f: %-#{max_size}s %s" % [i + 1, *yield(k, v)]
    end
  end
end

#run(name) ⇒ Object


32
33
34
35
36
# File 'lib/gauntlet_flog.rb', line 32

def run name
  warn name
  self.data[name] = score_for '.'
  self.dirty = true
end

#score_for(dir) ⇒ Object

OTHER


112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/gauntlet_flog.rb', line 112

def score_for dir
  # files = `find #{dir} -name \\*.rb | grep -v gen.*templ`.split(/\n/)
  files = Dir["**/*.rb"].reject { |f| f =~ /gen.*templ|gemspec.rb/ }

  flogger = Flog.new
  flogger.flog_files files
  methods = flogger.totals.reject { |k,v| k =~ /\#none$/ }
  n = 20
  topN = Hash[*methods.sort_by { |k,v| -v }.first(n).flatten]
  {
    :max     => methods.values.max,
    :total   => flogger.total_score,
    :size    => methods.size,
    :average => flogger.average,
    :stddev  => flogger.stddev,
    :methods => topN,
  }
rescue SyntaxError => e
  warn e.inspect + " at " + e.backtrace.first(5).join(', ') if $v
  $syntax_error.dup
rescue => e
  warn e.inspect + " at " + e.backtrace.first(5).join(', ') if $v
  $misc_error.dup
end

#title(heading) ⇒ Object


137
138
139
140
141
142
# File 'lib/gauntlet_flog.rb', line 137

def title heading
  puts
  puts "#{heading}:"
  puts
  yield if block_given?
end