Skip to content

Instantly share code, notes, and snippets.

@jhannes
Created May 13, 2011 11:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jhannes/970356 to your computer and use it in GitHub Desktop.
Save jhannes/970356 to your computer and use it in GitHub Desktop.
Refactoring in the 4th dimension
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