Class: Churn::ChurnCalculator

Inherits:
Object
  • Object
show all
Defined in:
lib/churn/calculator.rb

Overview

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.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ ChurnCalculator

intialized the churn calculator object



30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/churn/calculator.rb', line 30

def initialize(options={})
  @churn_options = ChurnOptions.instance.set_options(options)
  
  @minimum_churn_count = @churn_options.minimum_churn_count
  @ignore_files        = @churn_options.ignore_files
  @source_control      = SourceControl.set_source_control(@churn_options.start_date)

  @changes          = {}
  @revision_changes = {}
  @class_changes    = {}
  @method_changes   = {}
end

Class Method Details

.to_s(hash) ⇒ Object

Pretty print the data as a string for the user



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# 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

Instance Method Details

#analyzeObject

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



99
100
101
102
103
104
105
106
107
108
109
# 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

#emitObject

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



93
94
95
96
# File 'lib/churn/calculator.rb', line 93

def emit
  @changes   = parse_log_for_changes.reject {|file, change_count| change_count < @minimum_churn_count || @ignore_files.include?(file) }
  @revisions = parse_log_for_revision_changes
end

#generate_historyObject

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



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# 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|
        `git checkout #{commit}`
        commit_date = `git 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)
        `churn -s "#{start_date}"`
      end
    ensure
      `git 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_reportObject



58
59
60
61
62
63
64
65
66
# 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) ⇒ Object

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.

Parameters:

  • format (Bolean)

    to return the data, true for string or false for hash

Returns:

  • (Object)

    returns either a pretty string or a hash representing the chrun of the project



47
48
49
50
51
52
53
54
55
56
# 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_hObject

collect all the data into a single hash data structure.



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# 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)
  hash
end

#to_sObject



130
131
132
# File 'lib/churn/calculator.rb', line 130

def to_s
  ChurnCalculator.to_s(to_h[:churn])
end