Created
May 13, 2011 11:06
-
-
Save jhannes/970356 to your computer and use it in GitHub Desktop.
Refactoring in the 4th dimension
This file contains 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
require 'rubygems' | |
require 'awesome_print' | |
load 'repodepot.rb' | |
class CodeEvent | |
def full_method_name | |
class_name + "#" + method_name | |
end | |
def time | |
@time ||= Time.parse(date) | |
end | |
def lines | |
@lines ||= line_count.to_i | |
end | |
def c | |
@c = complexity.to_f | |
end | |
end | |
class MethodTimeline | |
def self.create(events) | |
timelines = [] | |
events_per_method = events.group_by { |e| e.full_method_name } | |
events_per_method.each { | |
|full_method_name, events| # array of [full_method_name, [array of event]] | |
timelines << MethodTimeline.new(events) | |
} | |
timelines | |
end | |
def initialize(events) | |
@events = events.sort_by { |e| e.time } | |
@full_method_name = events.last.full_method_name | |
end | |
def full_method_name | |
@full_method_name | |
end | |
def commits | |
@events.collect { |e| e.commit } | |
end | |
def deltas | |
@events.transitions | |
end | |
end | |
def complexity_time_line_for_method(events, full_method_name) | |
events.select { |e| e.full_method_name == full_method_name }. | |
sort_by { |e| e.time }. | |
collect { |e| [e.time, e.c, e.commit] } | |
end | |
def large_method_size(events) | |
# large methods => largest 5% of methods | |
events.sort_by { |e| e.lines }.reverse[events.count/20].lines | |
end | |
def large_method_drops_in_complexity(delta, threshold) | |
delta[1].c < delta[0].c && delta[0].lines > threshold | |
end | |
def commits_with_large_methods_that_reduced_in_complexity(events) | |
threshold = large_method_size(events) | |
timelines = MethodTimeline.create(events) | |
commits = [] | |
for method_timeline in timelines | |
for delta in method_timeline.deltas | |
if large_method_drops_in_complexity(delta, threshold) | |
commits << delta[1].commit | |
end | |
end | |
end | |
commits | |
end | |
def new_methods_per_commit(events, commits) | |
events_for_commits = events.select { |e| commits.include? e.commit } | |
method_timelines = {} | |
for timeline in MethodTimeline.create(events) | |
method_timelines[timeline.full_method_name] = timeline | |
end | |
result = {} | |
commits.each { |commit| result[commit] = 0 } | |
for e in events_for_commits | |
method = method_timelines[e.full_method_name] | |
if method.commits.first == e.commit | |
result[e.commit] += 1 | |
end | |
end | |
result | |
end | |
def sort_events_by_complexity_change(events) | |
g = events.group_by { |e| e.full_method_name } | |
methods_and_max_c = g.collect { | |
|method_stat| | |
max_c_change = method_stat[1].sort_by { |e| e.time }.transitions.map { | |
|delta| delta[1].c - delta[0].c | |
}.max | |
[method_stat[0], max_c_change ] | |
} | |
methods_and_max_c.sort_by { |x| x[1] || 0 } | |
end | |
def total_complexity_by_date(events) | |
complexity_by_date = Hash.new(0) | |
for event in events | |
complexity_by_date[event.time.to_date] += event.c | |
end | |
complexity_by_date | |
end | |
if __FILE__ == $0 | |
puts "reading...." | |
events = read_events('active_merchant') | |
puts "analyzing...." | |
ap sort_events_by_complexity_change(events) | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment