metric_fu 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,18 +8,39 @@ module MetricFu
8
8
 
9
9
  def analyze
10
10
  output = File.open(metric_directory + '/stats.txt').read
11
- output = output.split("\n")
12
- output = output.find_all {|line| line[0].chr != "+" }
13
- output = output.find_all {|line| line[0].chr != "(" }
14
- output.shift
15
- totals = output.pop
16
- totals = totals.split(" ").find_all {|el| ! el.empty? }
11
+ lines = remove_noise(output)
12
+
17
13
  @stats = {}
14
+
15
+ set_global_stats(lines.pop)
16
+ set_granular_stats(lines)
17
+
18
+ @stats
19
+ end
20
+
21
+ def to_h
22
+ {:stats => @stats}
23
+ end
24
+
25
+ private
26
+
27
+ def remove_noise(output)
28
+ lines = output.split("\n")
29
+ lines = lines.find_all {|line| line[0].chr != "+" }
30
+ lines = lines.find_all {|line| line[0].chr != "(" }
31
+ lines.shift
32
+ lines
33
+ end
34
+
35
+ def set_global_stats(totals)
36
+ totals = totals.split(" ").find_all {|el| ! el.empty? }
18
37
  @stats[:codeLOC] = totals[0].match(/\d.*/)[0].to_i
19
38
  @stats[:testLOC] = totals[1].match(/\d.*/)[0].to_i
20
39
  @stats[:code_to_test_ratio] = totals[2].match(/1\:(\d.*)/)[1].to_f
21
-
22
- @stats[:lines] = output.map do |line|
40
+ end
41
+
42
+ def set_granular_stats(lines)
43
+ @stats[:lines] = lines.map do |line|
23
44
  elements = line.split("|")
24
45
  elements.map! {|el| el.strip }
25
46
  elements = elements.find_all {|el| ! el.empty? }
@@ -32,11 +53,6 @@ module MetricFu
32
53
  end
33
54
  info_line
34
55
  end
35
- @stats
36
- end
37
-
38
- def to_h
39
- {:stats => @stats}
40
56
  end
41
57
 
42
58
  end
@@ -83,4 +83,31 @@ module MetricFu
83
83
  File.open(File.join(MetricFu.output_directory, 'roodi.js'), 'w') {|f| f << content }
84
84
  end
85
85
  end
86
+
87
+ class StatsBluffGrapher < StatsGrapher
88
+ def graph!
89
+ content = <<-EOS
90
+ #{BLUFF_DEFAULT_OPTIONS}
91
+ g.title = 'Stats: LOC & LOT';
92
+ g.data('LOC', [#{@loc_counts.join(',')}]);
93
+ g.data('LOT', [#{@lot_counts.join(',')}])
94
+ g.labels = #{@labels.to_json};
95
+ g.draw();
96
+ EOS
97
+ File.open(File.join(MetricFu.output_directory, 'stats.js'), 'w') {|f| f << content }
98
+ end
99
+ end
100
+
101
+ class RailsBestPracticesBluffGrapher < RailsBestPracticesGrapher
102
+ def graph!
103
+ content = <<-EOS
104
+ #{BLUFF_DEFAULT_OPTIONS}
105
+ g.title = 'Rails Best Practices: design problems';
106
+ g.data('rails_best_practices', [#{@rails_best_practices_count.join(',')}]);
107
+ g.labels = #{@labels.to_json};
108
+ g.draw();
109
+ EOS
110
+ File.open(File.join(MetricFu.output_directory, 'rails_best_practices.js'), 'w') {|f| f << content }
111
+ end
112
+ end
86
113
  end
@@ -1,7 +1,7 @@
1
1
  module MetricFu
2
2
  module GchartGrapher
3
3
  COLORS = %w{009999 FF7400 A60000 008500 E6399B 344AD7 00B860 D5CCB9}
4
- GCHART_GRAPH_SIZE = "1000x300" # maximum permitted image size is 300000 pixels
4
+ GCHART_GRAPH_SIZE = "945x317" # maximum permitted image size is 300000 pixels
5
5
 
6
6
  NUMBER_OF_TICKS = 6
7
7
  def determine_y_axis_scale(values)
@@ -23,7 +23,7 @@ module MetricFu
23
23
  include MetricFu::GchartGrapher
24
24
 
25
25
  def self.require_graphing_gem
26
- require 'gchart'
26
+ require 'gchart' if MetricFu.graph_engine == :gchart
27
27
  rescue LoadError
28
28
  puts "#"*99 + "\n" +
29
29
  "If you want to use google charts for graphing, you'll need to install the googlecharts rubygem." +
@@ -55,7 +55,8 @@ module MetricFu
55
55
  :data => [@flog_average, @top_five_percent_average],
56
56
  :stacked => false,
57
57
  :bar_colors => COLORS[0..1],
58
- :legend => ['average', 'top 5%25 average'],
58
+ :legend => ['average', 'top 5% average'],
59
+ :custom => "chdlp=t",
59
60
  :max_value => @max_value,
60
61
  :axis_with_labels => 'x,y',
61
62
  :axis_labels => [@labels.values, @yaxis],
@@ -93,6 +94,7 @@ module MetricFu
93
94
  :stacked => false,
94
95
  :bar_colors => COLORS,
95
96
  :legend => legend,
97
+ :custom => "chdlp=t",
96
98
  :max_value => @max_value,
97
99
  :axis_with_labels => 'x,y',
98
100
  :axis_labels => [@labels.values, @yaxis],
@@ -115,4 +117,23 @@ module MetricFu
115
117
  :filename => File.join(MetricFu.output_directory, 'roodi.png'))
116
118
  end
117
119
  end
120
+
121
+ class StatsGchartGrapher < StatsGrapher
122
+ def graph!
123
+ determine_y_axis_scale(@loc_counts + @lot_counts)
124
+ url = Gchart.line(
125
+ :size => GCHART_GRAPH_SIZE,
126
+ :title => URI.escape("Stats: LOC & LOT"),
127
+ :data => [@loc_counts, @lot_counts],
128
+ :bar_colors => COLORS[0..1],
129
+ :legend => ['Lines of code', 'Lines of test'],
130
+ :custom => "chdlp=t",
131
+ :max_value => @max_value,
132
+ :axis_with_labels => 'x,y',
133
+ :axis_labels => [@labels.values, @yaxis],
134
+ :format => 'file',
135
+ :filename => File.join(MetricFu.output_directory, 'stats.png'))
136
+ end
137
+ end
138
+
118
139
  end
@@ -0,0 +1,25 @@
1
+ module MetricFu
2
+
3
+ class RailsBestPracticesGrapher < Grapher
4
+
5
+ attr_accessor :rails_best_practices_count, :labels
6
+
7
+ def initialize
8
+ super
9
+ @rails_best_practices_count = []
10
+ @labels = {}
11
+ end
12
+
13
+ def get_metrics(metrics, date)
14
+ if metrics[:rails_best_practices] && metrics[:rails_best_practices][:problems]
15
+ size = metrics[:rails_best_practices][:problems].size
16
+ else
17
+ size = 0
18
+ end
19
+ @rails_best_practices_count.push(size)
20
+ @labels.update( { @labels.size => date })
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,23 @@
1
+
2
+ module MetricFu
3
+
4
+ class StatsGrapher < Grapher
5
+
6
+ attr_accessor :loc_counts, :lot_counts, :labels
7
+
8
+ def initialize
9
+ super
10
+ self.loc_counts = []
11
+ self.lot_counts = []
12
+ self.labels = {}
13
+ end
14
+
15
+ def get_metrics(metrics, date)
16
+ self.loc_counts.push(metrics[:stats][:codeLOC].to_i)
17
+ self.lot_counts.push(metrics[:stats][:testLOC].to_i)
18
+ self.labels.update( { self.labels.size => date })
19
+ end
20
+
21
+ end
22
+
23
+ end
data/lib/metric_fu.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rake'
2
2
  require 'yaml'
3
+ require 'activesupport'
3
4
  # Load a few things to make our lives easier elsewhere.
4
5
  module MetricFu
5
6
  LIB_ROOT = File.dirname(__FILE__)
@@ -34,7 +34,7 @@
34
34
  <% @flog[:pages].each do |page| %>
35
35
  <h2 id="<%= page[:path].gsub(/[^a-z]+/, '_') %>"><%= link_to_filename page[:path] %></h2>
36
36
  <% page[:scanned_methods].each do |sm| %>
37
- <p><%= sm[:name] %></p>
37
+ <p><%= link_to_filename(page[:path],sm[:line],sm[:name]) %></p>
38
38
  <p>Total Score: <%=sm[:score]%></p>
39
39
  <table>
40
40
  <tr>
@@ -23,6 +23,9 @@
23
23
  <% end %>
24
24
  <% if @stats %>
25
25
  <li class='even failure'><a href="stats.html">Stats</a></li>
26
+ <% end %>
27
+ <% if @rails_best_practices %>
28
+ <li class='even failure'><a href="rails_best_practices.html">Rails Best Practices report</a></li>
26
29
  <% end %>
27
30
  </ul>
28
31
  <p>Generated on <%= Time.now.localtime %></p>
@@ -0,0 +1,27 @@
1
+ <h3>Rails Best Practices Results</h3>
2
+
3
+ <p><a href="http://github.com/flyerhzm/rails_best_practices">rails_best_practices</a> checks quality of rails app files according to ihower’s presentation from Kungfu RailsConf in Shanghai China.</p>
4
+
5
+ <% graph_name = 'rails_best_practices' %>
6
+ <% if MetricFu.configuration.graph_engine == :gchart %>
7
+ <img src="<%= graph_name %>.png?<%= Time.now.to_i %>" />
8
+ <% else %>
9
+ <canvas id="graph"></canvas>
10
+ <script language="javascript" src="<%= graph_name %>.js?<%= Time.now.to_i %>" type="text/javascript"></script>
11
+ <% end %>
12
+
13
+ <table>
14
+ <tr>
15
+ <th>File Path</th>
16
+ <th>Warning</th>
17
+ </tr>
18
+ <% count = 0 %>
19
+ <% @rails_best_practices[:problems].each do |problem| %>
20
+ <tr class='<%= cycle("light", "dark", count) %>'>
21
+ <td><%= link_to_filename(problem[:file], problem[:line]) %></td>
22
+ <td><%= problem[:problem] %></td>
23
+ </tr>
24
+ <% count += 1 %>
25
+ <% end %>
26
+ </table>
27
+ <p>Generated on <%= Time.now.localtime %></p>
@@ -1,4 +1,14 @@
1
1
  <h3>Rake Stats Results</h3>
2
+
3
+ <% graph_name = 'stats' %>
4
+ <% if MetricFu.configuration.graph_engine == :gchart %>
5
+ <img src="<%= graph_name %>.png?<%= Time.now.to_i %>" />
6
+ <% else %>
7
+ <canvas id="graph"></canvas>
8
+ <script language="javascript" src="<%= graph_name %>.js?<%= Time.now.to_i %>" type="text/javascript"></script>
9
+ <% end %>
10
+
11
+
2
12
  <p>Rails rake stats results.</p>
3
13
  <table>
4
14
  <tr>
@@ -32,6 +32,9 @@
32
32
  <% if @stats %>
33
33
  <p><a href="stats.html">Stats report</a></p>
34
34
  <% end %>
35
+ <% if @rails_best_practices %>
36
+ <p><a href="rails_best_practices.html">Rails Best Practices report</a></p>
37
+ <% end %>
35
38
  <p>Generated on <%= Time.now.localtime %></p>
36
39
  </body>
37
40
  </html>
@@ -0,0 +1,29 @@
1
+ <html>
2
+ <head>
3
+ <title>Rails Best Practices Results</title>
4
+ <style>
5
+ <%= inline_css("default.css") %>
6
+ </style>
7
+ </head>
8
+
9
+ <body>
10
+ <h1>Rails Best Practices Results</h1>
11
+ <a href="index.html">back to menu</a>
12
+ <p><a href="http://github.com/flyerhzm/rails_best_practices">rails_best_practices</a> checks quality of rails app files according to ihower’s presentation from Kungfu RailsConf in Shanghai China.</p>
13
+ <table>
14
+ <tr>
15
+ <th>File Path</th>
16
+ <th>Warning</th>
17
+ </tr>
18
+ <% count = 0 %>
19
+ <% @rails_best_practices[:problems].each do |problem| %>
20
+ <tr class='<%= cycle("light", "dark", count) %>'>
21
+ <td><%= problem[:file] %>:<%= problem[:line] %></td>
22
+ <td><%= problem[:problem] %></td>
23
+ </tr>
24
+ <% count += 1 %>
25
+ <% end %>
26
+ </table>
27
+ <p>Generated on <%= Time.now.localtime %></p>
28
+ </body>
29
+ </html>
@@ -87,7 +87,7 @@ describe MetricFu::Configuration do
87
87
 
88
88
  it 'should set @flay to {:dirs_to_flay => @code_dirs}' do
89
89
  @config.instance_variable_get(:@flay).
90
- should == {:dirs_to_flay => ['lib'], :minimum_score => 100}
90
+ should == {:dirs_to_flay => ['lib'], :filetypes=>["rb"], :minimum_score => 100}
91
91
  end
92
92
 
93
93
  it 'should set @flog to {:dirs_to_flog => @code_dirs}' do
@@ -134,7 +134,8 @@ describe MetricFu::Configuration do
134
134
  "--no-color",
135
135
  "--profile",
136
136
  "--rails",
137
- "--exclude /gems/,/Library/,/usr/,spec"]}
137
+ "--exclude /gems/,/Library/,/usr/,spec"],
138
+ :external => nil}
138
139
  end
139
140
 
140
141
  it 'should set @saikuro to { :output_directory => @scratch_directory + "/saikuro",
@@ -6,7 +6,7 @@ describe Flay do
6
6
  end
7
7
  describe "emit method" do
8
8
  it "should look at the dirs" do
9
- MetricFu::Configuration.run {|config| config.flay = { :dirs_to_flay => ['app', 'lib'] } }
9
+ MetricFu::Configuration.run {|config| config.flay = { :dirs_to_flay => ['app', 'lib'], :filetypes => ['rb'] } }
10
10
  File.stub!(:directory?).and_return(true)
11
11
  @flay = MetricFu::Flay.new('base_dir')
12
12
 
@@ -15,6 +15,17 @@ describe Flay do
15
15
  @flay.should_receive(:`).with("flay path/to/app path/to/lib")
16
16
  output = @flay.emit
17
17
  end
18
+
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")
27
+ output = @flay.emit
28
+ end
18
29
 
19
30
  it "should limit flay scores by the minimum_score" do
20
31
  MetricFu::Configuration.run {|config| config.flay = { :dirs_to_flay => [], :minimum_score => 99 } }
@@ -170,6 +170,30 @@ describe Flog do
170
170
  flog_page.scanned_methods.first.name.should == "SomeNamespace::UsersController#create"
171
171
  end
172
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
+
173
197
  it "should parse empty flog files" do
174
198
  text = ""
175
199
  flog = MetricFu::Flog.new('base_dir')
@@ -4,8 +4,11 @@ describe "Bluff graphers responding to #graph!" do
4
4
  it "should write chart file" do
5
5
  MetricFu.configuration
6
6
  graphs = {}
7
- MetricFu::AVAILABLE_GRAPHS.each do |graph|
8
- graphs[graph] = MetricFu.const_get("#{graph.to_s.capitalize}BluffGrapher").new
7
+ available_graphs = MetricFu::AVAILABLE_GRAPHS + [:stats]
8
+ available_graphs.each do |graph|
9
+ grapher_name = graph.to_s.gsub("MetricFu::",'').gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
10
+ grapher_name = grapher_name+"BluffGrapher"
11
+ graphs[graph] = MetricFu.const_get(grapher_name).new
9
12
  end
10
13
  graphs.each do |key, val|
11
14
  val.graph!
@@ -13,4 +16,4 @@ describe "Bluff graphers responding to #graph!" do
13
16
  lambda{ File.open(File.join(output_dir, "#{key.to_s.downcase}.js")) }.should_not raise_error
14
17
  end
15
18
  end
16
- end
19
+ end
@@ -1,4 +1,15 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper")
2
+ describe MetricFu::Grapher do
3
+ describe "require_graphing_gem" do
4
+ it "should give a warning if trying to use gchart but gem is not installed" do
5
+ MetricFu::Configuration.run {|config| config.graph_engine = :gchart}
6
+ MetricFu::Grapher.should_receive(:require).with('gchart').and_raise(LoadError)
7
+ MetricFu::Grapher.should_receive(:puts).with(/If you want to use google charts/)
8
+ MetricFu::Grapher.require_graphing_gem
9
+ end
10
+ end
11
+ end
12
+
2
13
  describe MetricFu::GchartGrapher do
3
14
  describe "determine_y_axis_scale" do
4
15
  it "should set defaults when empty array" do
@@ -21,7 +32,7 @@ end
21
32
 
22
33
  describe "Gchart graphers" do
23
34
  before :each do
24
- MetricFu.configuration
35
+ MetricFu::Configuration.run {|config| config.graph_engine = :gchart}
25
36
  end
26
37
 
27
38
  describe "FlayGchartGrapher graph! method" do
@@ -47,7 +58,8 @@ describe "Gchart graphers" do
47
58
  :title => URI.escape("Flog: code complexity"),
48
59
  :stacked => false,
49
60
  :bar_colors => MetricFu::GchartGrapher::COLORS[0..1],
50
- :legend => ['average', 'top 5%25 average'],
61
+ :legend => ['average', 'top 5% average'],
62
+ :custom => "chdlp=t",
51
63
  :axis_with_labels => 'x,y',
52
64
  :format => 'file',
53
65
  :filename => File.join(MetricFu.output_directory, 'flog.png'),
@@ -105,4 +117,23 @@ describe "Gchart graphers" do
105
117
  grapher.graph!
106
118
  end
107
119
  end
120
+
121
+ describe "StatsGchartGrapher graph! method" do
122
+ it "should set static values for graph" do
123
+ grapher = StatsGchartGrapher.new
124
+ expected = {
125
+ :size => MetricFu::GchartGrapher::GCHART_GRAPH_SIZE,
126
+ :title => URI.escape("Stats: LOC & LOT"),
127
+ :bar_colors => MetricFu::GchartGrapher::COLORS[0..1],
128
+ :legend => ['Lines of code', 'Lines of test'],
129
+ :custom => "chdlp=t",
130
+ :axis_with_labels => 'x,y',
131
+ :format => 'file',
132
+ :filename => File.join(MetricFu.output_directory, 'stats.png'),
133
+ }
134
+ Gchart.should_receive(:line).with(hash_including(expected))
135
+ grapher.graph!
136
+ end
137
+ end
138
+
108
139
  end