class Churn::ChurnCalculator

The work horse of the the churn library. This class takes user input, determins the SCM the user is using. It then determines changes made during this revision. Finally it reads all the changes from previous revisions and displays human readable output on the command line. It can also ouput a yaml format readable by other tools such as metric_fu and Caliper.

Public Class Methods

new(options={}) click to toggle source

intialized the churn calculator object

# File lib/churn/calculator.rb, line 30
def initialize(options={})
  @churn_options = ChurnOptions.new.set_options(options)
  
  @minimum_churn_count = @churn_options.minimum_churn_count
  @ignores             = @churn_options.ignores
  @source_control      = SourceControl.set_source_control(@churn_options.start_date)

  @changes          = {}
  @revision_changes = {}
  @class_changes    = {}
  @method_changes   = {}
end
to_s(hash) click to toggle source

Pretty print the data as a string for the user

# File lib/churn/calculator.rb, line 135
def self.to_s(hash)
  result = seperator
  result +="* Revision Changes \n"
  result += seperator
  result += display_array("Files", hash[:changed_files], :fields=>[:to_str], :headers=>{:to_str=>'file'})
  result += "\n"
  result += display_array("Classes", hash[:changed_classes])
  result += "\n"
  result += display_array("Methods", hash[:changed_methods]) + "\n"
  result += seperator
  result +="* Project Churn \n"
  result += seperator
  result += "\n"
  result += display_array("Files", hash[:changes])
  result += "\n"
  class_churn = collect_items(hash[:class_churn], 'klass')
  result += display_array("Classes", class_churn)
  result += "\n"
  method_churn = collect_items(hash[:method_churn], 'method')
  result += display_array("Methods", method_churn)
end

Public Instance Methods

analyze() click to toggle source

Analyze the source control data, filter, sort, and find more information on the editted files

# File lib/churn/calculator.rb, line 99
def analyze
  @changes = sort_changes(@changes)
  @changes = @changes.map {|file_path, times_changed| {:file_path => file_path, :times_changed => times_changed }}

  calculate_revision_changes

  @method_changes = sort_changes(@method_changes)
  @method_changes = @method_changes.map {|method, times_changed| {'method' => method, 'times_changed' => times_changed }}
  @class_changes  = sort_changes(@class_changes)
  @class_changes  = @class_changes.map {|klass, times_changed| {'klass' => klass, 'times_changed' => times_changed }}
end
emit() click to toggle source

Emits various data from source control to be analyses later… Currently this is broken up like this as a throwback to metric_fu

# File lib/churn/calculator.rb, line 93
def emit
  @changes   = parse_log_for_changes.reject {|file, change_count| change_count < @minimum_churn_count || @ignores.any?{ |ignore| file.match(/#{ignore}/) } }
  @revisions = parse_log_for_revision_changes
end
generate_history() click to toggle source

this method generates the past history of a churn project from first commit to current running the report for oldest commits first so they are built up correctly

# File lib/churn/calculator.rb, line 70
def generate_history
  if @source_control.is_a?(GitAnalyzer)
    begin
      history_starting_point = Chronic.parse(@churn_options.history)
      @source_control.get_commit_history.each do |commit|
        %xgit checkout #{commit}`
        commit_date = %xgit show -s --format="%ci"`
        commit_date = Time.parse(commit_date)
        next if commit_date < history_starting_point
        #7776000 == 3.months without adding active support depenancy
        start_date  = (commit_date - 7776000)
        %xchurn -s "#{start_date}"`
      end
    ensure
      %xgit checkout master`
    end
    "churn history complete, this has munipulated git please make sure you are back on HEAD where you expect to be"
  else
    raise "currently generate history only supports git"
  end
end
remote_report() click to toggle source
# File lib/churn/calculator.rb, line 58
def remote_report
  if @churn_options.report_host
    puts "posting churn results to #{@churn_options.report_host}"
    data = {:name => @churn_options.name, :revision => @revisions.first, :data => self.to_h}.to_json        
    RestClient.post @churn_options.report_host, {"results" => data}, :content_type => :json, :accept => :json
  end
rescue Errno::ECONNREFUSED
  puts "error posting churn results connection refused to host: #{@churn_options.report_host}"
end
report(print = true) click to toggle source

prepares the data for the given project to be reported. reads git/svn logs analyzes the output, generates a report and either formats as a nice string or returns hash. @param [Bolean] format to return the data, true for string or false for hash @return [Object] returns either a pretty string or a hash representing the chrun of the project

# File lib/churn/calculator.rb, line 47
def report(print = true)
  if @churn_options.history
    generate_history
  else
    emit
    analyze
    remote_report
    print ? self.to_s : self.to_h
  end
end
to_h() click to toggle source

collect all the data into a single hash data structure.

# File lib/churn/calculator.rb, line 112
def to_h
  hash                        = {:churn => {:changes => @changes}}
  hash[:churn][:class_churn]  = @class_changes
  hash[:churn][:method_churn] = @method_changes
  #detail the most recent changes made this revision
  first_revision         = @revisions.first
  first_revision_changes = @revision_changes[first_revision]
  if first_revision_changes
    changes = first_revision_changes
    hash[:churn][:changed_files]   = changes[:files]
    hash[:churn][:changed_classes] = changes[:classes]
    hash[:churn][:changed_methods] = changes[:methods]
  end
  #TODO crappy place to do this but save hash to revision file but while entirely under metric_fu only choice
  ChurnHistory.store_revision_history(first_revision, hash, @churn_options.data_directory)
  hash
end
to_s() click to toggle source
# File lib/churn/calculator.rb, line 130
def to_s
  ChurnCalculator.to_s(to_h[:churn])
end