metric_fu 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY CHANGED
@@ -1,3 +1,11 @@
1
+ === MetricFu 1.5.0 / 2010-4-27
2
+
3
+ * Fixed bug where Flay results were not being reported. Had to remove the ability to remove selected files from flay processing (undocumented feature that may go away soon if it keeps causing problems).
4
+ * Rewrote Flog parsing/processing to use Flog programmatically. Note: the yaml output for Flog has changed significantly - Pages have now become MethodContainers. This probably doesn't matter to you if you are not consuming the metric_fu yaml output.
5
+ * Added support for using config files in Reek and Roodi (roodi support was already there but undocumented).
6
+ * Removed verify_dependencies! as it caused too much confusion to justify the limited set of problems it solved. In the post Bundler world it just didn't seem necessary to limit metric_fu dependencies.
7
+ * Deal with Rails 3 activesupport vs active_support problems. - jinzhu
8
+
1
9
  === MetricFu 1.4.0 / 2010-06-19
2
10
 
3
11
  * Added support for rails_best_practices gem - Richard Huang
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ Spec::Rake::SpecTask.new(:spec) do |t|
10
10
  end
11
11
 
12
12
  MetricFu::Configuration.run do |config|
13
- config.template_class = AwesomeTemplate
13
+ config.roodi = config.roodi.merge(:roodi_config => 'config/roodi_config.yml')
14
14
  end
15
15
 
16
16
  task :default => :spec
@@ -103,6 +103,10 @@ module MetricFu
103
103
  "<a href='#{file_url(name, line)}'>#{link_content(name, line, link_content)}</a>"
104
104
  end
105
105
 
106
+ def round_to_tenths(decimal)
107
+ (decimal * 10).round / 10.0
108
+ end
109
+
106
110
  def link_content(name, line=nil, link_content=nil) # :nodoc:
107
111
  if link_content
108
112
  link_content
@@ -114,6 +118,7 @@ module MetricFu
114
118
  end
115
119
 
116
120
  def file_url(name, line) # :nodoc:
121
+ return '' unless name
117
122
  filename = File.expand_path(name.gsub(/^\//, ''))
118
123
  if MetricFu.configuration.platform.include?('darwin')
119
124
  "txmt://open/?url=file://#{filename}" << (line ? "&line=#{line}" : "")
@@ -113,8 +113,10 @@ module MetricFu
113
113
  :minimum_score => 100,
114
114
  :filetypes => ['rb'] }
115
115
  @flog = { :dirs_to_flog => @code_dirs }
116
- @reek = { :dirs_to_reek => @code_dirs }
117
- @roodi = { :dirs_to_roodi => @code_dirs }
116
+ @reek = { :dirs_to_reek => @code_dirs,
117
+ :config_file_pattern => nil}
118
+ @roodi = { :dirs_to_roodi => @code_dirs,
119
+ :roodi_config => nil}
118
120
  @saikuro = { :output_directory => @scratch_directory + '/saikuro',
119
121
  :input_directory => @code_dirs,
120
122
  :cyclo => "",
@@ -33,7 +33,6 @@ module MetricFu
33
33
  attr_reader :report, :template
34
34
 
35
35
  def initialize(options={})
36
- self.class.verify_dependencies!
37
36
  create_metric_dir_if_missing
38
37
  create_output_dir_if_missing
39
38
  create_data_dir_if_missing
@@ -134,11 +133,6 @@ module MetricFu
134
133
  def round_to_tenths(decimal)
135
134
  (decimal * 10).round / 10.0
136
135
  end
137
-
138
- # Allows subclasses to check for required gems
139
- def self.verify_dependencies!
140
- true
141
- end
142
136
 
143
137
  def emit #:nodoc:
144
138
  raise <<-EOF
@@ -5,12 +5,6 @@ module MetricFu
5
5
  def initialize(options={})
6
6
  super
7
7
  end
8
-
9
- def self.verify_dependencies!
10
- result = `churn --help`
11
- raise 'sudo gem install churn # if you want the churn tasks' unless result.match(/churn/)
12
- end
13
-
14
8
 
15
9
  def emit
16
10
  @output = `churn --yaml`
@@ -1,21 +1,13 @@
1
+ require 'flay'
2
+
1
3
  module MetricFu
2
4
 
3
5
  class Flay < Generator
4
6
 
5
- def self.verify_dependencies!
6
- `flay --help`
7
- raise 'sudo gem install flay # if you want the flay tasks' unless $?.success?
8
- end
9
-
10
7
  def emit
11
- files_to_flay = MetricFu.flay[:dirs_to_flay].map{|dir|
12
- MetricFu.flay[:filetypes].map {|type|
13
- Dir[ File.join(dir, "**/*.#{type}") ]
14
- }.flatten
15
- }
16
- files = remove_excluded_files(files_to_flay.flatten)
17
8
  mimimum_score_parameter = MetricFu.flay[:minimum_score] ? "--mass #{MetricFu.flay[:minimum_score]} " : ""
18
- @output = `flay #{mimimum_score_parameter}#{files.join(" ")}`
9
+
10
+ @output = `flay #{mimimum_score_parameter} #{MetricFu.flay[:dirs_to_flay].join(" ")}`
19
11
  end
20
12
 
21
13
  def analyze
@@ -1,172 +1,98 @@
1
1
  require 'pathname'
2
+ require 'optparse'
3
+ require 'flog'
2
4
 
3
5
  module MetricFu
4
6
 
5
7
  class Flog < Generator
6
- attr_reader :pages
7
-
8
- def self.verify_dependencies!
9
- `flog --help`
10
- raise 'sudo gem install flog # if you want the flog tasks' unless $?.success?
11
- end
12
-
13
- SCORE_FORMAT = "%0.2f"
14
- METHOD_LINE_REGEX = /(\d+\.\d+):\s+([A-Za-z:]+#.*)/
15
- OPERATOR_LINE_REGEX = /\s*(\d+\.\d+):\s(.*)$/
16
8
 
17
9
  def emit
18
- metric_dir = MetricFu::Flog.metric_directory
10
+ files = []
19
11
  MetricFu.flog[:dirs_to_flog].each do |directory|
20
12
  directory = "." if directory=='./'
21
- files = Dir.glob("#{directory}/**/*.rb")
22
- files = remove_excluded_files(files)
23
- files.each do |filename|
24
- output_dir = "#{metric_dir}/#{filename.split("/")[0..-2].join("/")}"
25
- mkdir_p(output_dir, :verbose => false) unless File.directory?(output_dir)
26
- pathname = Pathname.new(filename)
27
- if MetricFu::MD5Tracker.file_changed?(filename, metric_dir)
28
- base_name = pathname.basename.to_s.gsub(/\..*$/,'.txt')
29
- editted_filename = File.join(pathname.dirname.to_s, base_name)
30
- `flog -ad #{filename} > #{metric_dir}/#{editted_filename}`
31
- end
32
- end
13
+ dir_files = Dir.glob("#{directory}/**/*.rb")
14
+ dir_files = remove_excluded_files(dir_files)
15
+ files += dir_files
33
16
  end
17
+ options = ::Flog.parse_options ["--all", "--details"]
18
+
19
+ @flogger = ::Flog.new options
20
+ @flogger.flog files
21
+
34
22
  rescue LoadError
35
23
  if RUBY_PLATFORM =~ /java/
36
24
  puts 'running in jruby - flog tasks not available'
37
- else
38
- puts 'sudo gem install flog # if you want the flog tasks'
39
- end
40
- end
41
-
42
- def parse(text)
43
- summary, methods_summary = text.split "\n\n"
44
- return unless summary
45
- score, average = summary.split("\n").map {|line| line[OPERATOR_LINE_REGEX, 1]}
46
- return nil unless score && methods_summary
47
- page = Flog::Page.new(score, average)
48
- methods_summary.each_line do |method_line|
49
- if match = method_line.match(METHOD_LINE_REGEX)
50
- page.scanned_methods << ScannedMethod.new(match[2], match[1])
51
- elsif match = method_line.match(OPERATOR_LINE_REGEX)
52
- return if page.scanned_methods.empty?
53
- page.scanned_methods.last.operators << Operator.new(match[1], match[2])
54
- end
55
25
  end
56
- page
57
26
  end
58
27
 
59
28
  def analyze
60
- @pages = []
61
- flog_results.each do |path|
62
- page = parse(open(path, "r") { |f| f.read })
63
- if page
64
- page.path = path.sub(metric_directory, "").sub(".txt", ".rb")
65
- #don't include old cached flog results for files that no longer exist.
66
- if is_file_current?(page.path.to_s)
67
- @pages << page
68
- end
29
+ @method_containers = {}
30
+ @flogger.calls.each do |full_method_name, operators|
31
+ container_name = full_method_name.split('#').first
32
+ path = @flogger.method_locations[full_method_name]
33
+ if @method_containers[container_name]
34
+ @method_containers[container_name].add_method(full_method_name, operators, @flogger.totals[full_method_name], path)
35
+ @method_containers[container_name].add_path(path)
36
+ else
37
+ mc = MethodContainer.new(container_name, path)
38
+ mc.add_method(full_method_name, operators, @flogger.totals[full_method_name], path)
39
+ @method_containers[container_name] = mc
69
40
  end
70
41
  end
71
42
  end
72
43
 
73
44
  def to_h
74
- number_of_methods = @pages.inject(0) {|count, page| count += page.scanned_methods.size}
75
- total_flog_score = @pages.inject(0) {|total, page| total += page.score}
76
- sorted_pages = @pages.sort_by {|page| page.highest_score }.reverse
77
- {:flog => { :total => total_flog_score,
78
- :average => average_score(total_flog_score, number_of_methods),
79
- :pages => sorted_pages.map {|page| page.to_h}}}
45
+ sorted_containers = @method_containers.values.sort_by {|c| c.highest_score}.reverse
46
+ {:flog => { :total => @flogger.total,
47
+ :average => @flogger.average,
48
+ :method_containers => sorted_containers.map {|method_container| method_container.to_h}}}
80
49
  end
81
-
82
- private
83
50
 
84
- def is_file_current?(pathname)
85
- pathname = pathname.gsub(/^\//,'')
86
- local_pathname = "./#{pathname}"
87
- exists = false
51
+ end
88
52
 
89
- MetricFu.flog[:dirs_to_flog].each do |directory|
90
- directory = "." if directory=='./'
91
- files = Dir.glob("#{directory}/**/*.rb")
92
- if files.include?(pathname) || files.include?(local_pathname)
93
- exists = true
94
- break
95
- end
96
- end
97
- exists
98
- end
53
+ class MethodContainer
54
+ attr_reader :methods
99
55
 
100
- def average_score(total_flog_score, number_of_methods)
101
- return 0 if total_flog_score == 0
102
- round_to_tenths(total_flog_score/number_of_methods)
56
+ def initialize(name, path)
57
+ @name = name
58
+ add_path path
59
+ @methods = {}
103
60
  end
104
-
105
- def flog_results
106
- Dir.glob("#{metric_directory}/**/*.txt")
107
- end
108
-
109
- class Operator
110
- attr_accessor :score, :operator
111
-
112
- def initialize(score, operator)
113
- @score = score.to_f
114
- @operator = operator
115
- end
116
-
117
- def to_h
118
- {:score => @score, :operator => @operator}
119
- end
120
- end
121
-
122
- class ScannedMethod
123
- attr_accessor :name, :score, :operators, :line
124
61
 
125
- def initialize(name, score, operators = [])
126
- if name.match(/\.rb:\d*/)
127
- @line = name.match(/\.rb:\d*/).to_s.sub('.rb:','')
128
- name = name.match(/\S*/)
129
- end
130
- @name = name
131
- @score = score.to_f
132
- @operators = operators
133
- end
62
+ def add_path path
63
+ return unless path
64
+ @path ||= path.split(':').first
65
+ end
134
66
 
135
- def to_h
136
- {:name => @name,
137
- :score => @score,
138
- :operators => @operators.map {|o| o.to_h},
139
- :line => @line}
140
- end
141
- end
142
-
143
- end
67
+ def add_method(full_method_name, operators, score, path)
68
+ @methods[full_method_name] = {:operators => operators, :score => score, :path => path}
69
+ end
144
70
 
145
- class Flog::Page < MetricFu::Generator
146
- attr_accessor :path, :score, :scanned_methods, :average_score
71
+ def to_h
72
+ { :name => @name,
73
+ :path => @path || '',
74
+ :total_score => total_score,
75
+ :highest_score => highest_score,
76
+ :average_score => average_score,
77
+ :methods => @methods}
78
+ end
147
79
 
148
- def initialize(score, average_score, scanned_methods = [])
149
- @score = score.to_f
150
- @scanned_methods = scanned_methods
151
- @average_score = average_score.to_f
80
+ def highest_score
81
+ method_scores.max
152
82
  end
153
83
 
154
- def filename
155
- File.basename(path, ".txt")
84
+ private
85
+
86
+ def method_scores
87
+ @method_scores ||= @methods.values.map {|v| v[:score] }
156
88
  end
157
89
 
158
- def to_h
159
- {:score => @score,
160
- :scanned_methods => @scanned_methods.map {|sm| sm.to_h},
161
- :highest_score => highest_score,
162
- :average_score => average_score,
163
- :path => path}
90
+ def total_score
91
+ @total_score ||= method_scores.inject(0) {|sum, score| sum += score}
164
92
  end
165
93
 
166
- def highest_score
167
- scanned_methods.inject(0) do |highest, m|
168
- m.score > highest ? m.score : highest
169
- end
94
+ def average_score
95
+ total_score / method_scores.size.to_f
170
96
  end
171
- end
97
+ end
172
98
  end
@@ -1,11 +1,5 @@
1
1
  module MetricFu
2
2
  class RailsBestPractices < Generator
3
-
4
- def self.verify_dependencies!
5
- `rails_best_practices --help`
6
- raise 'sudo gem install rails_best_practices # if you want the rails_best_practices tasks' unless $?.success?
7
- end
8
-
9
3
 
10
4
  def emit
11
5
  @output = `rails_best_practices .`
@@ -2,16 +2,12 @@ module MetricFu
2
2
 
3
3
  class Reek < Generator
4
4
  REEK_REGEX = /^(\S+) (.*) \((.*)\)$/
5
-
6
- def self.verify_dependencies!
7
- `reek --help`
8
- raise 'sudo gem install reek # if you want the reek tasks' unless $?.success?
9
- end
10
-
5
+
11
6
  def emit
12
7
  files_to_reek = MetricFu.reek[:dirs_to_reek].map{|dir| Dir[File.join(dir, "**/*.rb")] }
13
8
  files = remove_excluded_files(files_to_reek.flatten)
14
- @output = `reek #{files.join(" ")}`
9
+ config_file_param = MetricFu.reek[:config_file_pattern] ? "--config #{MetricFu.reek[:config_file_pattern]}" : ''
10
+ @output = `reek #{config_file_param} #{files.join(" ")}`
15
11
  @output = massage_for_reek_12 if reek_12?
16
12
  end
17
13
 
@@ -1,12 +1,6 @@
1
1
  module MetricFu
2
2
  class Roodi < Generator
3
3
 
4
- def self.verify_dependencies!
5
- `roodi --help`
6
- raise 'sudo gem install roodi # if you want the roodi tasks' unless $?.success?
7
- end
8
-
9
-
10
4
  def emit
11
5
  files_to_analyze = MetricFu.roodi[:dirs_to_roodi].map{|dir| Dir[File.join(dir, "**/*.rb")] }
12
6
  files = remove_excluded_files(files_to_analyze.flatten)
@@ -20,6 +20,25 @@ module MetricFu
20
20
  private
21
21
 
22
22
  def calc_top_five_percent_average(metrics)
23
+ return calc_top_five_percent_average_legacy(metrics) if metrics[:flog][:pages]
24
+
25
+ method_scores = metrics[:flog][:method_containers].inject([]) do |method_scores, container|
26
+ method_scores += container[:methods].values.map {|v| v[:score]}
27
+ end
28
+ method_scores.sort!.reverse!
29
+
30
+ number_of_methods_that_is_five_percent = (method_scores.size * 0.05).ceil
31
+
32
+ total_for_five_percent =
33
+ method_scores[0...number_of_methods_that_is_five_percent].inject(0) { |total, score| total += score }
34
+ if number_of_methods_that_is_five_percent == 0
35
+ 0.0
36
+ else
37
+ total_for_five_percent / number_of_methods_that_is_five_percent.to_f
38
+ end
39
+ end
40
+
41
+ def calc_top_five_percent_average_legacy(metrics)
23
42
  methods = metrics[:flog][:pages].inject([]) {|methods, page| methods << page[:scanned_methods]}
24
43
  methods.flatten!
25
44
  methods = methods.sort_by {|method| method[:score]}.reverse
@@ -34,7 +53,6 @@ module MetricFu
34
53
  total_for_five_percent / number_of_methods_that_is_five_percent.to_f
35
54
  end
36
55
  end
37
-
38
56
  end
39
57
 
40
58
  end
data/lib/metric_fu.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  require 'rake'
2
2
  require 'yaml'
3
- require 'activesupport'
3
+ begin
4
+ require 'activesupport'
5
+ rescue LoadError
6
+ require 'active_support'
7
+ end
8
+
4
9
  # Load a few things to make our lives easier elsewhere.
5
10
  module MetricFu
6
11
  LIB_ROOT = File.dirname(__FILE__)
@@ -29,4 +34,4 @@ Dir[File.join(template_dir, 'standard/*.rb')].each {|l| require l}
29
34
  Dir[File.join(template_dir, 'awesome/*.rb')].each {|l| require l}
30
35
  require graph_dir + "/grapher"
31
36
  Dir[File.join(graph_dir, '*.rb')].each {|l| require l}
32
- Dir[File.join(graph_dir, 'engines', '*.rb')].each {|l| require l}
37
+ Dir[File.join(graph_dir, 'engines', '*.rb')].each {|l| require l}
@@ -9,8 +9,8 @@
9
9
  <script language="javascript" src="<%= graph_name %>.js?<%= Time.now.to_i %>" type="text/javascript"></script>
10
10
  <% end %>
11
11
 
12
- <h2>Total Flog score for all methods: <%= @flog[:total]%></h2>
13
- <h2>Average Flog score for all methods: <%= @flog[:average]%></h2>
12
+ <h2>Total Flog score for all methods: <%= round_to_tenths @flog[:total]%></h2>
13
+ <h2>Average Flog score for all methods: <%= round_to_tenths @flog[:average]%></h2>
14
14
 
15
15
  <table>
16
16
  <tr>
@@ -20,31 +20,33 @@
20
20
  <th>Average score</th>
21
21
  <th>Highest score</th>
22
22
  </tr>
23
- <% @flog[:pages].each do |page| %>
23
+ <% @flog[:method_containers].each do |method_container| %>
24
24
  <tr>
25
- <td><a href="#<%= page[:path].gsub(/[^a-z]+/, '_') %>"><%= page[:path] %></a></td>
26
- <td><%= page[:score].round %></td>
27
- <td><%= page[:scanned_methods].length %></td>
28
- <td><%= page[:average_score].round %></td>
29
- <td><%= page[:highest_score].round %></td>
25
+ <td><a href="#<%= method_container[:path].gsub(/[^a-z]+/, '_') %>"><%= method_container[:path] %></a></td>
26
+ <td><%= round_to_tenths method_container[:total_score] %></td>
27
+ <td><%= method_container[:methods].size %></td>
28
+ <td><%= round_to_tenths method_container[:average_score] %></td>
29
+ <td><%= round_to_tenths method_container[:highest_score] %></td>
30
30
  </tr>
31
31
  <% end %>
32
32
  </table>
33
33
 
34
- <% @flog[:pages].each do |page| %>
35
- <h2 id="<%= page[:path].gsub(/[^a-z]+/, '_') %>"><%= link_to_filename page[:path] %></h2>
36
- <% page[:scanned_methods].each do |sm| %>
37
- <p><%= link_to_filename(page[:path],sm[:line],sm[:name]) %></p>
38
- <p>Total Score: <%=sm[:score]%></p>
34
+ <% @flog[:method_containers].each do |method_container| %>
35
+ <h2 id="<%= method_container[:path].gsub(/[^a-z]+/, '_') %>"><%= link_to_filename(method_container[:path]) %></h2>
36
+
37
+ <% method_container[:methods].each do |full_method_name, method_info| %>
38
+ <% path, line = method_info[:path].split(":") if method_info[:path] %>
39
+ <p><%= link_to_filename(path, line, full_method_name) %></p>
40
+ <p>Total Score: <%= round_to_tenths method_info[:score]%></p>
39
41
  <table>
40
42
  <tr>
41
43
  <th>Score</th>
42
44
  <th>Operator</th>
43
45
  </tr>
44
- <% sm[:operators].each do |operator| %>
46
+ <% method_info[:operators].each do |operator, score| %>
45
47
  <tr>
46
- <td><%= operator[:score] %></td>
47
- <td><%= operator[:operator] %></td>
48
+ <td><%= round_to_tenths score %></td>
49
+ <td><%= operator %></td>
48
50
  </tr>
49
51
  <% end %>
50
52
  </table>
@@ -9,45 +9,49 @@
9
9
  <h1>Flog Results</h1>
10
10
  <a href="index.html">back to menu</a>
11
11
  <p><a href='http://ruby.sadi.st/Flog.html'>Flog</a> measures code complexity.</p>
12
- <h2>Total Flog score for all methods: <%= @flog[:total]%></h2>
13
- <h2>Average Flog score for all methods: <%= @flog[:average]%></h2>
14
- <table>
15
- <tr>
16
- <th>File</th>
17
- <th>Total score</th>
18
- <th>Methods</th>
19
- <th>Average score</th>
20
- <th>Highest score</th>
12
+ <h2>Total Flog score for all methods: <%= round_to_tenths @flog[:total]%></h2>
13
+ <h2>Average Flog score for all methods: <%= round_to_tenths @flog[:average]%></h2>
14
+
15
+ <table>
16
+ <tr>
17
+ <th>File</th>
18
+ <th>Total score</th>
19
+ <th>Methods</th>
20
+ <th>Average score</th>
21
+ <th>Highest score</th>
21
22
  </tr>
22
- <% @flog[:pages].each do |page| %>
23
+ <% @flog[:method_containers].each do |method_container| %>
23
24
  <tr>
24
- <td><a href="#<%= page[:path].gsub(/[^a-z]+/, '_') %>"><%= page[:path] %></a></td>
25
- <td><%= page[:score].round %></td>
26
- <td><%= page[:scanned_methods].length %></td>
27
- <td><%= page[:average_score].round %></td>
28
- <td><%= page[:highest_score].round %></td>
25
+ <td><a href="#<%= method_container[:path].gsub(/[^a-z]+/, '_') %>"><%= method_container[:path] %></a></td>
26
+ <td><%= round_to_tenths method_container[:total_score] %></td>
27
+ <td><%= method_container[:methods].size %></td>
28
+ <td><%= round_to_tenths method_container[:average_score] %></td>
29
+ <td><%= round_to_tenths method_container[:highest_score] %></td>
29
30
  </tr>
30
31
  <% end %>
31
32
  </table>
32
33
 
33
- <% @flog[:pages].each do |page| %>
34
- <h2 id="<%= page[:path].gsub(/[^a-z]+/, '_') %>"><%= page[:path] %></h2>
35
- <% page[:scanned_methods].each do |sm| %>
36
- <p><%= sm[:name] %></p>
34
+ <% @flog[:method_containers].each do |method_container| %>
35
+ <h2 id="<%= method_container[:path].gsub(/[^a-z]+/, '_') %>"><%= link_to_filename(method_container[:path]) %></h2>
36
+
37
+ <% method_container[:methods].each do |full_method_name, method_info| %>
38
+ <% path, line = method_info[:path].split(":") if method_info[:path] %>
39
+ <p><%= link_to_filename(path, line, full_method_name) %></p>
40
+ <p>Total Score: <%= round_to_tenths method_info[:score]%></p>
37
41
  <table>
38
42
  <tr>
39
43
  <th>Score</th>
40
44
  <th>Operator</th>
41
45
  </tr>
42
- <% sm[:operators].each do |operator| %>
46
+ <% method_info[:operators].each do |operator, score| %>
43
47
  <tr>
44
- <td><%= operator[:score] %></td>
45
- <td><%= operator[:operator] %></td>
48
+ <td><%= round_to_tenths score %></td>
49
+ <td><%= operator %></td>
46
50
  </tr>
47
51
  <% end %>
48
52
  </table>
49
53
  <% end %>
50
54
  <% end %>
51
- <p>Generated on <%= Time.now.localtime %></p>
55
+ <p>Generated on <%= Time.now.localtime %></p>
52
56
  </body>
53
57
  </html>
@@ -97,12 +97,12 @@ describe MetricFu::Configuration do
97
97
 
98
98
  it 'should set @reek to {:dirs_to_reek => @code_dirs}' do
99
99
  @config.instance_variable_get(:@reek).
100
- should == {:dirs_to_reek => ['lib']}
100
+ should == {:config_file_pattern=>nil, :dirs_to_reek => ['lib']}
101
101
  end
102
102
 
103
103
  it 'should set @roodi to {:dirs_to_roodi => @code_dirs}' do
104
104
  @config.instance_variable_get(:@roodi).
105
- should == {:dirs_to_roodi => ['lib']}
105
+ should == {:roodi_config=>nil, :dirs_to_roodi => ['lib']}
106
106
  end
107
107
 
108
108
  it 'should set @churn to {}' do
@@ -156,29 +156,8 @@ describe MetricFu::Generator do
156
156
  @concrete_class.should_receive(:to_h)
157
157
  @concrete_class.generate_report
158
158
  end
159
-
160
- it "should raise error if the concrete class is missing a required dependency" do
161
- concrete_class_with_missing_gem = Class.new(MetricFu::Generator) do
162
- def self.verify_dependencies!
163
- raise 'gem install something # if you want these tasks'
164
- end
165
- end
166
- lambda { concrete_class_with_missing_gem.generate_report }.should raise_error("gem install something # if you want these tasks")
167
- end
168
159
 
169
160
  end
170
-
171
- describe "instantiation" do
172
- it "should fail is dependencies not verified" do
173
- ConcreteClass.should_receive(:verify_dependencies!).and_raise("Missing a required gem. Please 'gem install something'")
174
- lambda { ConcreteClass.new() }.should raise_error("Missing a required gem. Please 'gem install something'")
175
- end
176
-
177
- it "should succeed when dependencies verified" do
178
- ConcreteClass.should_receive(:verify_dependencies!).and_return(true)
179
- ConcreteClass.new()
180
- end
181
- end
182
161
 
183
162
  describe "path filter" do
184
163
 
@@ -6,7 +6,6 @@ describe Churn do
6
6
  before :each do
7
7
  MetricFu::Configuration.run {}
8
8
  File.stub!(:directory?).and_return(true)
9
- MetricFu::Churn.should_receive(:verify_dependencies!).and_return(true)
10
9
  @changes = {"lib/generators/flog.rb"=>2, "lib/metric_fu.rb"=>3}
11
10
  end
12
11
 
@@ -30,7 +29,6 @@ describe Churn do
30
29
  before :each do
31
30
  MetricFu::Configuration.run {}
32
31
  File.stub!(:directory?).and_return(true)
33
- MetricFu::Churn.should_receive(:verify_dependencies!).and_return(true)
34
32
  end
35
33
 
36
34
  it "should put the changes into a hash" do
@@ -1,29 +1,13 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
2
 
3
3
  describe Flay do
4
- before :each do
5
- MetricFu::Flay.stub!(:verify_dependencies!).and_return(true)
6
- end
7
4
  describe "emit method" do
8
5
  it "should look at the dirs" do
9
6
  MetricFu::Configuration.run {|config| config.flay = { :dirs_to_flay => ['app', 'lib'], :filetypes => ['rb'] } }
10
7
  File.stub!(:directory?).and_return(true)
11
8
  @flay = MetricFu::Flay.new('base_dir')
12
-
13
- Dir.should_receive(:[]).with(File.join("app", "**/*.rb")).and_return("path/to/app")
14
- Dir.should_receive(:[]).with(File.join("lib", "**/*.rb")).and_return("path/to/lib")
15
- @flay.should_receive(:`).with("flay path/to/app path/to/lib")
16
- output = @flay.emit
17
- end
18
9
 
19
- it "should look at the filetypes" do
20
- MetricFu::Configuration.run {|config| config.flay = { :dirs_to_flay => ['lib'], :filetypes => ['rb','haml'] } }
21
- File.stub!(:directory?).and_return(true)
22
- @flay = MetricFu::Flay.new('base_dir')
23
-
24
- Dir.should_receive(:[]).with(File.join("lib", "**/*.rb")).and_return("path/to/lib/stuff.rb")
25
- Dir.should_receive(:[]).with(File.join("lib", "**/*.haml")).and_return("path/to/lib/view/blah.html.haml")
26
- @flay.should_receive(:`).with("flay path/to/lib/stuff.rb path/to/lib/view/blah.html.haml")
10
+ @flay.should_receive(:`).with("flay app lib")
27
11
  output = @flay.emit
28
12
  end
29
13
 
@@ -32,7 +16,7 @@ describe Flay do
32
16
  File.stub!(:directory?).and_return(true)
33
17
  @flay = MetricFu::Flay.new('base_dir')
34
18
 
35
- @flay.should_receive(:`).with("flay --mass 99 ")
19
+ @flay.should_receive(:`).with("flay --mass 99 ")
36
20
  output = @flay.emit
37
21
  end
38
22
  end
@@ -1,262 +1,70 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
2
  describe Flog do
3
3
  before :each do
4
- @text = <<-HERE
5
- 157.9: flog total
6
- 11.3: flog/method average
7
-
8
- 34.8: UsersController#create
9
- 9.2: branch
10
- 6.8: current_user
11
- 5.2: assignment
12
- 3.4: role
13
- 3.0: render
14
- 3.0: ==
15
- 2.8: flash
16
- 1.6: after_create_page
17
- 1.6: params
18
- 1.5: activate!
19
- 1.5: errors
20
- 1.4: login
21
- 1.4: redirect_to
22
- 1.4: []
23
- 1.3: empty?
24
- 1.3: save
25
- 1.2: new
26
- 24.2: UsersController#authorize_user
27
- 4.8: branch
28
- 4.7: current_user
29
- 3.6: params
30
- 3.2: []
31
- 2.6: ==
32
- 1.5: role
33
- 1.5: to_i
34
- 1.5: id
35
- 1.4: new_session_path
36
- 1.3: include?
37
- 1.2: assignment
38
- 1.2: flash
39
- 1.2: redirect_to
40
- 16.4: UsersController#thank_you
41
- 4.0: assignment
42
- 3.3: params
43
- 2.9: []
44
- 2.7: redirect_to
45
- 2.4: branch
46
- 1.5: new_session_path
47
- 1.4: flash
48
- 1.4: activate!
49
- 1.3: can_activate?
50
- 1.2: find_by_id
51
- 14.2: UsersController#update
52
- 3.2: params
53
- 2.8: []
54
- 2.6: assignment
55
- 1.4: login
56
- 1.4: flash
57
- 1.4: redirect_to
58
- 1.3: render
59
- 1.2: branch
60
- 1.2: update_attributes
61
- 1.2: find_by_id
62
- 12.5: UsersController#sanitize_params
63
- 3.9: assignment
64
- 3.6: branch
65
- 3.0: current_user
66
- 1.6: params
67
- 1.5: role
68
- 1.4: []
69
- 1.3: include?
70
- 1.3: ==
71
- 1.2: reject!
72
- 10.6: UsersController#users_have_changed
73
- 3.9: assignment
74
- 2.6: branch
75
- 1.6: params
76
- 1.5: refresh_from_external
77
- 1.4: find_by_id
78
- 1.4: []
79
- 1.2: split
80
- 1.2: each
81
- 1.2: head
82
- 10.0: UsersController#after_create_page
83
- 3.0: current_user
84
- 2.6: id
85
- 2.4: branch
86
- 1.5: role
87
- 1.3: login
88
- 1.3: ==
89
- 8.4: UsersController#add_primary_site
90
- 2.4: assignment
91
- 1.6: params
92
- 1.4: []
93
- 1.4: new
94
- 1.2: find_by_id
95
- 1.2: all
96
- 1.2: render
97
- 7.7: UsersController#none
98
- 3.3: before_filter
99
- 1.1: private
100
- 1.1: caches_page
101
- 1.1: after_filter
102
- 1.1: skip_before_filter
103
- 7.2: UsersController#destroy
104
- 1.8: params
105
- 1.6: []
106
- 1.4: find_by_id
107
- 1.2: destroy
108
- 1.2: redirect_to
109
- 5.9: UsersController#edit
110
- 2.4: assignment
111
- 1.6: params
112
- 1.4: []
113
- 1.2: all
114
- 1.2: find_by_id
115
- 2.7: UsersController#signup
116
- 1.2: render
117
- 1.2: assignment
118
- 1.2: new
119
- 1.7: UsersController#new
120
- 1.2: assignment
121
- 1.2: new
122
- 1.7: UsersController#index
123
- 1.2: assignment
124
- 1.2: all
125
- HERE
126
- MetricFu::Flog.stub!(:verify_dependencies!).and_return(true)
4
+ MetricFu::Configuration.run {}
5
+ File.stub!(:directory?).and_return(true)
6
+ @flog = MetricFu::Flog.new('base_dir')
127
7
  end
128
8
 
129
- describe "parse method" do
130
- before :each do
131
- MetricFu::Configuration.run {}
132
- File.stub!(:directory?).and_return(true)
133
- flog = MetricFu::Flog.new('base_dir')
134
- @flog_page = flog.parse(@text)
135
- end
136
-
137
- it "should find the total score" do
138
- @flog_page.score.should == 157.9
139
- end
140
-
141
- it "should find the average score" do
142
- @flog_page.average_score.should == 11.3
143
- end
144
-
145
- it "should find the scanned method score" do
146
- @flog_page.scanned_methods.first.score.should == 34.8
147
- end
148
-
149
- it "should find the scanned method name" do
150
- @flog_page.scanned_methods.first.name.should == "UsersController#create"
151
- end
152
-
153
- it "should find the scanned method opperators names" do
154
- @flog_page.scanned_methods.first.operators.first.operator.should == "branch"
155
- end
156
-
157
- it "should find the scanned method opperators scores" do
158
- @flog_page.scanned_methods.first.operators.first.score.should == 9.2
159
- end
160
-
161
- it "should find the name of the method even if namespaced" do
162
- text = <<-HERE
163
- 157.9: flog total
164
- 11.3: flog/method average
165
-
166
- 34.8: SomeNamespace::UsersController#create
167
- HERE
168
- flog = MetricFu::Flog.new('base_dir')
169
- flog_page = flog.parse(text)
170
- flog_page.scanned_methods.first.name.should == "SomeNamespace::UsersController#create"
171
- end
172
-
173
- it "should find the line number for the method" do
174
- text = <<-HERE
175
- 157.9: flog total
176
- 11.3: flog/method average
177
-
178
- 34.8: SomeNamespace::UsersController#create lib/blah/file.rb:37
179
- HERE
180
- flog = MetricFu::Flog.new('base_dir')
181
- flog_page = flog.parse(text)
182
- flog_page.scanned_methods.first.line.should == "37"
183
- end
184
-
185
- it "should not add a line number, when none is found" do
186
- text = <<-HERE
187
- 157.9: flog total
188
- 11.3: flog/method average
189
-
190
- 34.8: UsersController#none lib/blah/file.rb
191
- HERE
192
- flog = MetricFu::Flog.new('base_dir')
193
- flog_page = flog.parse(text)
194
- flog_page.scanned_methods.first.line.should == nil
195
- end
196
-
197
- it "should parse empty flog files" do
198
- text = ""
199
- flog = MetricFu::Flog.new('base_dir')
200
- flog_page = flog.parse(text)
201
- flog_page.should be_nil
9
+ describe "emit method" do
10
+ it "should look for files and flog them" do
11
+ Dir.should_receive(:glob).with("lib/**/*.rb").and_return(["found/file.rb"])
12
+ ::Flog.should_receive(:parse_options).with(["--all", "--details"]).and_return("options")
13
+ ::Flog.should_receive(:new).with("options").and_return(flogger = mock('flogger'))
14
+ flogger.should_receive(:flog).with(["found/file.rb"])
15
+ @flog.emit
202
16
  end
203
17
  end
204
18
 
205
- describe "to_h function with results" do
206
- before :each do
207
- MetricFu::Configuration.run {}
208
- File.stub!(:directory?).and_return(true)
209
- flog = MetricFu::Flog.new('base_dir')
210
- flog.should_receive(:open).and_return(@text)
211
- flog.stub!(:is_file_current?).and_return(true)
212
- Dir.should_receive(:glob).and_return(["tmp/metric_fu/scratch/flog/app/controllers/user_controller.txt"])
213
- flog.analyze
214
- @flog_hash = flog.to_h
215
- end
216
-
217
- it "should put the total in the hash" do
218
- @flog_hash[:flog][:total].should == 157.9
219
- end
220
-
221
- it "should put the average in the hash" do
222
- @flog_hash[:flog][:average].should == 11.3
223
- end
224
-
225
- it "should put pages into the hash" do
226
- @flog_hash[:flog][:pages].first[:scanned_methods].first[:score].should == 34.8
227
- end
228
-
229
- it "should put the filename into the hash" do
230
- @flog_hash[:flog][:pages].first[:path].should == "/app/controllers/user_controller.rb"
19
+ describe "analyze method" do
20
+ it "should harvest the flog information and put it into method_containers" do
21
+ first_full_method_name = "ClassName#first_method_name"
22
+ second_full_method_name = "ClassName#second_method_name"
23
+
24
+ flogger = mock('flogger', :calls => {first_full_method_name => {:branch => 11.1, :puts => 1.1},
25
+ second_full_method_name => {:branch => 22.2, :puts => 2.2}},
26
+ :method_locations => {first_full_method_name => '/file/location.rb:11',
27
+ second_full_method_name => '/file/location.rb:22'},
28
+ :totals => {first_full_method_name => 11.11,
29
+ second_full_method_name => 22.22})
30
+ @flog.instance_variable_set(:@flogger, flogger)
31
+ @flog.analyze
32
+ method_containers = @flog.instance_variable_get(:@method_containers)
33
+ method_containers.size.should == 1
34
+
35
+ expected={:methods=>{"ClassName#first_method_name" => { :path=>"/file/location.rb:11",
36
+ :score=>11.11,
37
+ :operators=>{ :branch=>11.1,
38
+ :puts=>1.1}},
39
+ "ClassName#second_method_name" => {:path=>"/file/location.rb:22",
40
+ :score=>22.22,
41
+ :operators=>{ :branch=>22.2,
42
+ :puts=>2.2}}},
43
+ :path=>"/file/location.rb",
44
+ :average_score=>((11.11 + 22.22) / 2.0),
45
+ :total_score=>33.33,
46
+ :highest_score=>22.22,
47
+ :name=>"ClassName"}
48
+
49
+ method_containers["ClassName"].to_h.should == expected
231
50
  end
232
51
  end
233
52
 
234
- describe "to_h function ignore files not current" do
235
- before :each do
236
- MetricFu::Configuration.run {}
237
- File.stub!(:directory?).and_return(true)
238
- flog = MetricFu::Flog.new('base_dir')
239
- flog.should_receive(:open).and_return(@text)
240
- flog.stub!(:is_file_current?).and_return(false)
241
- Dir.should_receive(:glob).and_return(["tmp/metric_fu/scratch/flog/app/controllers/user_controller.txt"])
242
- flog.analyze
243
- @flog_hash = flog.to_h
53
+ describe "to_h method" do
54
+ it "should make-a nice hash" do
55
+ flogger = mock('flogger', :total => 111.1, :average => 7.3)
56
+ @flog.instance_variable_set(:@flogger, flogger)
57
+ method_containers = {:ignore_me_1 => mock('container_1', :highest_score => 11.1, :to_h => 'container_1'),
58
+ :ignore_me_2 => mock('container_2', :highest_score => 33.3, :to_h => 'container_2'),
59
+ :ignore_me_3 => mock('container_3', :highest_score => 22.2, :to_h => 'container_3')}
60
+ @flog.instance_variable_set(:@method_containers, method_containers)
61
+
62
+ expected = {:flog => { :total => 111.1,
63
+ :average => 7.3,
64
+ :method_containers => ['container_2', 'container_3', 'container_1']}}
65
+
66
+ @flog.to_h.should == expected
244
67
  end
245
68
 
246
- it "should put the total in the hash" do
247
- @flog_hash.should == {:flog=>{:total=>0, :pages=>[], :average=>0}}
248
- end
249
-
250
- end
251
-
252
- describe "to_h function with zero total" do
253
- it "should not blow up" do
254
- MetricFu::Configuration.run {}
255
- File.stub!(:directory?).and_return(true)
256
- flog = MetricFu::Flog.new('base_dir')
257
- flog.should_receive(:open).and_return("") # some sort of empty or unparsable file
258
- Dir.should_receive(:glob).and_return(["empty_file.txt"])
259
- flog.analyze
260
- end
261
69
  end
262
70
  end
@@ -1,9 +1,19 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
2
 
3
3
  describe Reek do
4
+ describe "emit" do
5
+ it "should include config parameters" do
6
+ MetricFu::Configuration.run do |config|
7
+ config.reek = {:config_file_pattern => 'lib/config/*.reek', :dirs_to_reek => []}
8
+ end
9
+ reek = MetricFu::Reek.new
10
+ reek.should_receive(:`).with(/--config lib\/config\/\*\.reek/).and_return("")
11
+ reek.emit
12
+ end
13
+ end
14
+
4
15
  describe "analyze method" do
5
16
  before :each do
6
- MetricFu::Reek.stub!(:verify_dependencies!).and_return(true)
7
17
  @lines = <<-HERE
8
18
  "app/controllers/activity_reports_controller.rb" -- 4 warnings:
9
19
  ActivityReportsController#authorize_user calls current_user.primary_site_ids multiple times (Duplication)
@@ -61,7 +71,6 @@ end
61
71
 
62
72
  describe Reek do
63
73
  before :each do
64
- MetricFu::Reek.stub!(:verify_dependencies!).and_return(true)
65
74
  MetricFu::Configuration.run {}
66
75
  @reek = MetricFu::Reek.new
67
76
  @lines11 = <<-HERE
@@ -2,8 +2,9 @@ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
2
 
3
3
  describe MetricFu::FlogGrapher do
4
4
  before :each do
5
- @flog_grapher = MetricFu::FlogGrapher.new
6
5
  MetricFu.configuration
6
+ @flog_grapher = MetricFu::FlogGrapher.new
7
+
7
8
  end
8
9
 
9
10
  it "should respond to flog_total, flog_average and labels" do
@@ -22,18 +23,25 @@ describe MetricFu::FlogGrapher do
22
23
 
23
24
  describe "responding to #get_metrics" do
24
25
  before(:each) do
25
- @metrics = YAML::load(File.open(File.join(File.dirname(__FILE__), "..", "resources", "yml", "20090630.yml")))
26
+ methods = {}
27
+ 100.times do |i|
28
+ methods["method_name_#{i}"] = {:score => i.to_f}
29
+ end
30
+
31
+ @metrics = {:flog => {:total => 111.1,
32
+ :average => 7.7,
33
+ :method_containers => [ {:methods => methods } ] } }
26
34
  @date = "1/2"
27
35
  end
28
36
 
29
37
  it "should push to top_five_percent_average" do
30
- average = (73.6 + 68.5 + 66.1 + 46.6 + 44.8 + 44.1 + 41.2 + 36.0) / 8.0
38
+ average = (99.0 + 98.0 + 97.0 + 96.0 + 95.0) / 5.0
31
39
  @flog_grapher.top_five_percent_average.should_receive(:push).with(average)
32
40
  @flog_grapher.get_metrics(@metrics, @date)
33
41
  end
34
42
 
35
43
  it "should push 9.9 to flog_average" do
36
- @flog_grapher.flog_average.should_receive(:push).with(9.9)
44
+ @flog_grapher.flog_average.should_receive(:push).with(7.7)
37
45
  @flog_grapher.get_metrics(@metrics, @date)
38
46
  end
39
47
 
@@ -42,4 +50,19 @@ describe MetricFu::FlogGrapher do
42
50
  @flog_grapher.get_metrics(@metrics, @date)
43
51
  end
44
52
  end
53
+
54
+ describe "responding to #get_metrics with legacy data" do
55
+ before(:each) do
56
+ @metrics = YAML::load(File.open(File.join(File.dirname(__FILE__), "..", "resources", "yml", "20090630.yml")))
57
+
58
+ @date = "1/2"
59
+ end
60
+
61
+ it "should push to top_five_percent_average" do
62
+ average = (73.6 + 68.5 + 66.1 + 46.6 + 44.8 + 44.1 + 41.2 + 36.0) / 8.0
63
+ @flog_grapher.top_five_percent_average.should_receive(:push).with(average)
64
+ @flog_grapher.get_metrics(@metrics, @date)
65
+ end
66
+ end
67
+
45
68
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metric_fu
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 3
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 4
8
+ - 5
9
9
  - 0
10
- version: 1.4.0
10
+ version: 1.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jake Scruggs
@@ -24,7 +24,7 @@ autorequire:
24
24
  bindir: bin
25
25
  cert_chain: []
26
26
 
27
- date: 2010-06-19 00:00:00 -05:00
27
+ date: 2010-07-27 00:00:00 -05:00
28
28
  default_executable:
29
29
  dependencies:
30
30
  - !ruby/object:Gem::Dependency