metric_fu 4.8.0 → 4.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.metrics +1 -66
  5. data/.travis.yml +1 -0
  6. data/CONTRIBUTORS +13 -11
  7. data/DEV.md +21 -18
  8. data/Gemfile +1 -2
  9. data/Gemfile.devtools +0 -1
  10. data/HISTORY.md +7 -1
  11. data/README.md +79 -19
  12. data/Rakefile +0 -1
  13. data/checksum/metric_fu-4.8.0.gem.sha512 +1 -0
  14. data/gem_tasks/usage_test.rake +30 -0
  15. data/lib/metric_fu/configuration.rb +6 -1
  16. data/lib/metric_fu/data_structures/line_numbers.rb +1 -1
  17. data/lib/metric_fu/environment.rb +2 -7
  18. data/lib/metric_fu/logging/mf_debugger.rb +4 -4
  19. data/lib/metric_fu/metric.rb +2 -2
  20. data/lib/metric_fu/metrics/cane/template_awesome/cane.html.erb +74 -85
  21. data/lib/metric_fu/metrics/churn/churn.rb +1 -2
  22. data/lib/metric_fu/metrics/flay/template_awesome/flay.html.erb +2 -1
  23. data/lib/metric_fu/metrics/flog/template_awesome/flog.html.erb +2 -1
  24. data/lib/metric_fu/metrics/rails_best_practices/template_awesome/rails_best_practices.html.erb +2 -1
  25. data/lib/metric_fu/metrics/rcov/external_client.rb +24 -0
  26. data/lib/metric_fu/metrics/rcov/rcov.rb +9 -100
  27. data/lib/metric_fu/metrics/rcov/rcov_format_coverage.rb +140 -0
  28. data/lib/metric_fu/metrics/rcov/simplecov_formatter.rb +64 -0
  29. data/lib/metric_fu/metrics/rcov/template_awesome/rcov.html.erb +5 -1
  30. data/lib/metric_fu/metrics/reek/reek_grapher.rb +7 -1
  31. data/lib/metric_fu/metrics/reek/template_awesome/reek.html.erb +2 -1
  32. data/lib/metric_fu/metrics/roodi/template_awesome/roodi.html.erb +2 -1
  33. data/lib/metric_fu/metrics/stats/template_awesome/stats.html.erb +2 -2
  34. data/lib/metric_fu/reporting/graphs/grapher.rb +5 -20
  35. data/lib/metric_fu/reporting/templates/awesome/awesome_template.rb +1 -1
  36. data/lib/metric_fu/reporting/templates/awesome/layout.html.erb +8 -3
  37. data/lib/metric_fu/reporting/templates/javascripts/bluff_graph.js +15 -0
  38. data/lib/metric_fu/reporting/templates/javascripts/excanvas.js +1 -1
  39. data/lib/metric_fu/reporting/templates/javascripts/highcharts.js +294 -0
  40. data/lib/metric_fu/reporting/templates/javascripts/highcharts_graph.js +38 -0
  41. data/lib/metric_fu/reporting/templates/javascripts/standalone-framework.js +17 -0
  42. data/lib/metric_fu/reporting/templates/javascripts/utils.js +9 -0
  43. data/lib/metric_fu/templates/css/bluff.css +10 -10
  44. data/lib/metric_fu/templates/css/integrity.css +3 -0
  45. data/lib/metric_fu/templates/report.html.erb +3 -4
  46. data/lib/metric_fu/version.rb +1 -1
  47. data/metric_fu.gemspec +1 -0
  48. data/spec/fixtures/coverage.rb +13 -0
  49. data/spec/fixtures/exit0.sh +3 -0
  50. data/spec/fixtures/exit1.sh +3 -0
  51. data/spec/metric_fu/formatter/html_spec.rb +2 -2
  52. data/spec/metric_fu/metrics/rcov/simplecov_formatter_spec.rb +41 -0
  53. data/spec/spec_helper.rb +7 -8
  54. data/spec/support/usage_test.rb +134 -0
  55. data/spec/usage_test_spec.rb +69 -0
  56. metadata +39 -3
  57. metadata.gz.sig +0 -0
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env rake
2
2
  require 'bundler/setup'
3
3
 
4
-
5
4
  Dir['./gem_tasks/*.rake'].each do |task|
6
5
  import(task)
7
6
  end
@@ -0,0 +1 @@
1
+ d46528ba18e30ce561e3d0dfb4245ee2e4b7ff72a895cff24cb4bb4a86ace4ed3f759eba96b26aa9e512ebd253d78d9697423bf468c09a09fb764597977f26c2
@@ -0,0 +1,30 @@
1
+ require 'redcarpet'
2
+ require 'English'
3
+ require 'tmpdir'
4
+ ROOT_PATH = File.expand_path("..", File.dirname(__FILE__))
5
+ require File.join(ROOT_PATH, 'spec', 'support', 'usage_test')
6
+ LIB_PATH = File.join(ROOT_PATH, 'lib')
7
+ BIN_PATH = File.join(ROOT_PATH, 'bin')
8
+ EXAMPLE_FILES = [
9
+ File.join(ROOT_PATH, 'README.md'),
10
+ File.join(ROOT_PATH, 'DEV.md')
11
+ ]
12
+ task "load_path" do
13
+ $LOAD_PATH.unshift(LIB_PATH)
14
+ $VERBOSE = nil
15
+ ENV['PATH'] = "#{BIN_PATH}:#{ENV['PATH']}"
16
+ ENV['CC_BUILD_ARTIFACTS'] = 'turn_off_browser_opening'
17
+ end
18
+ desc "Test that documentation usage works"
19
+ task "usage_test" => %w[load_path] do
20
+ usage_test = UsageTest.new
21
+ usage_test.test_files(EXAMPLE_FILES)
22
+ end
23
+
24
+ class HTMLRenderAndVerifyCodeBlocks < Redcarpet::Render::HTML
25
+
26
+ def block_code(code, language)
27
+ SnippetRunner.new(code, language).test!
28
+ end
29
+
30
+ end
@@ -78,6 +78,7 @@ module MetricFu
78
78
  @templates_configuration = MetricFu::Templates::Configuration.new
79
79
  MetricFu::Formatter::Templates.templates_configuration = @templates_configuration
80
80
  @formatters = []
81
+ @graph_engine = :bluff
81
82
  end
82
83
 
83
84
  # This allows us to have a nice syntax like:
@@ -128,8 +129,12 @@ module MetricFu
128
129
  MetricFu::Metric.enabled_metrics.select{|metric|metric.has_graph?}.map(&:name)
129
130
  end
130
131
 
132
+ def configure_graph_engine(graph_engine)
133
+ @graph_engine = graph_engine
134
+ end
135
+
131
136
  def graph_engine
132
- :bluff
137
+ @graph_engine
133
138
  end
134
139
 
135
140
  # This allows us to configure the templates with:
@@ -37,7 +37,7 @@ module MetricFu
37
37
  end
38
38
 
39
39
  # @param method [String] the method name being queried
40
- # @erturn [Integer, nil] the line number at which the given method is defined
40
+ # @return [Integer, nil] the line number at which the given method is defined
41
41
  def start_line_for_method(method)
42
42
  return nil unless @locations.has_key?(method)
43
43
  @locations[method].first
@@ -123,14 +123,9 @@ module MetricFu
123
123
  end
124
124
 
125
125
  def ruby_strangely_makes_accessors_private?
126
- ruby192? || jruby?
126
+ @private_accessors ||= ruby192? || jruby?
127
127
  end
128
+ module_function :ruby_strangely_makes_accessors_private?
128
129
 
129
- # HACK: for using this module via inclusion in Configuration
130
- def self.included(host_class)
131
- def host_class.ruby_strangely_makes_accessors_private?
132
- @private_accessors ||= allocate.ruby_strangely_makes_accessors_private?
133
- end
134
- end
135
130
  end
136
131
  end
@@ -23,8 +23,8 @@ module MfDebugger
23
23
  end
24
24
  # From episode 029 of Ruby Tapas by Avdi
25
25
  # https://rubytapas.dpdcart.com/subscriber/post?id=88
26
- def self.capture_output(&block)
27
- old_stdout = STDOUT.clone
26
+ def self.capture_output(stream=STDOUT, &block)
27
+ old_stdout = stream.clone
28
28
  pipe_r, pipe_w = IO.pipe
29
29
  pipe_r.sync = true
30
30
  output = ""
@@ -36,10 +36,10 @@ module MfDebugger
36
36
  rescue EOFError
37
37
  end
38
38
  end
39
- STDOUT.reopen(pipe_w)
39
+ stream.reopen(pipe_w)
40
40
  yield
41
41
  ensure
42
- STDOUT.reopen(old_stdout)
42
+ stream.reopen(old_stdout)
43
43
  pipe_w.close
44
44
  reader.join
45
45
  pipe_r.close
@@ -62,12 +62,12 @@ module MetricFu
62
62
  @configured_run_options
63
63
  end
64
64
 
65
- # @return default metric run options [Hash]
65
+ # @return [Hash] default metric run options
66
66
  def default_run_options
67
67
  not_implemented
68
68
  end
69
69
 
70
- # @return metric_options [Hash]
70
+ # @return [Hash] metric_options
71
71
  def has_graph?
72
72
  not_implemented
73
73
  end
@@ -1,100 +1,89 @@
1
- <html>
2
- <head>
3
- <title>Cane Results</title>
4
- <style>
5
- <%= inline_css("css/default.css") %>
6
- </style>
7
- </head>
1
+ <h3>Cane Results</h3>
8
2
 
9
- <body>
10
- <h1>Cane Results</h1>
11
- <a href="index.html">back to menu</a>
12
- <h2>Total Violations: <%= @cane[:total_violations] %></h2>
13
- <p><a href='https://github.com/square/cane'>Cane</a> reports code quality threshold violations.</p>
3
+ <p><a href='https://github.com/square/cane'>Cane</a> reports code quality threshold violations.</p>
14
4
 
15
- <% graph_name = 'cane' %>
16
- <canvas id="graph"></canvas>
17
- <script language="javascript" src="<%= graph_name %>.js?<%= Time.now.to_i %>" type="text/javascript"></script>
5
+ <div id="graph_container"></div>
18
6
 
19
- <% if @cane[:violations][:abc_complexity] && @cane[:violations][:abc_complexity].size > 0 %>
20
- <h3>Methods exceeding allowed Abc complexity (<%= @cane[:violations][:abc_complexity].size %>)</h3>
21
- <table>
22
- <tr>
23
- <th>File</th>
24
- <th>Method</th>
25
- <th>Complexity</th>
7
+ <% graph_name = 'cane' %>
8
+ <script language="javascript" src="<%= graph_name %>.js?<%= Time.now.to_i %>" type="text/javascript"></script>
9
+
10
+ <% if @cane[:violations][:abc_complexity] && @cane[:violations][:abc_complexity].size > 0 %>
11
+ <h3>Methods exceeding allowed Abc complexity (<%= @cane[:violations][:abc_complexity].size %>)</h3>
12
+ <table>
13
+ <tr>
14
+ <th>File</th>
15
+ <th>Method</th>
16
+ <th>Complexity</th>
17
+ </tr>
18
+ <% count = 0 %>
19
+ <% @cane[:violations][:abc_complexity].each do |violation| %>
20
+ <tr class='<%= cycle("light", "dark", count) %>'>
21
+ <td><%=violation[:file]%></td>
22
+ <td><%=violation[:method]%></td>
23
+ <td><%=violation[:complexity]%></td>
26
24
  </tr>
27
- <% count = 0 %>
28
- <% @cane[:violations][:abc_complexity].each do |violation| %>
29
- <tr class='<%= cycle("light", "dark", count) %>'>
30
- <td><%=violation[:file]%></td>
31
- <td><%=violation[:method]%></td>
32
- <td><%=violation[:complexity]%></td>
33
- </tr>
34
- <% count += 1 %>
35
- <% end %>
36
- </table>
25
+ <% count += 1 %>
37
26
  <% end %>
38
- <% if @cane[:violations][:line_style] && @cane[:violations][:line_style].size > 0 %>
39
- <h3>Lines violating style requirements (<%= @cane[:violations][:line_style].size %>)</h3>
40
- <table>
41
- <tr>
42
- <th>File</th>
43
- <th>Description</th>
27
+ </table>
28
+ <% end %>
29
+ <% if @cane[:violations][:line_style] && @cane[:violations][:line_style].size > 0 %>
30
+ <h3>Lines violating style requirements (<%= @cane[:violations][:line_style].size %>)</h3>
31
+ <table>
32
+ <tr>
33
+ <th>File</th>
34
+ <th>Description</th>
35
+ </tr>
36
+ <% count = 0 %>
37
+ <% @cane[:violations][:line_style].each do |violation| %>
38
+ <tr class='<%= cycle("light", "dark", count) %>'>
39
+ <td><%=violation[:line]%></td>
40
+ <td><%=violation[:description]%></td>
44
41
  </tr>
45
- <% count = 0 %>
46
- <% @cane[:violations][:line_style].each do |violation| %>
47
- <tr class='<%= cycle("light", "dark", count) %>'>
48
- <td><%=violation[:line]%></td>
49
- <td><%=violation[:description]%></td>
50
- </tr>
51
- <% count += 1 %>
52
- <% end %>
53
- </table>
42
+ <% count += 1 %>
54
43
  <% end %>
55
- <% if @cane[:violations][:documentation] && @cane[:violations][:documentation].size > 0 %>
56
- <h3>Missing documentation (<%= @cane[:violations][:documentation].size %>)</h3>
57
- <table>
44
+ </table>
45
+ <% end %>
46
+ <% if @cane[:violations][:documentation] && @cane[:violations][:documentation].size > 0 %>
47
+ <h3>Missing documentation (<%= @cane[:violations][:documentation].size %>)</h3>
48
+ <table>
49
+ <tr>
50
+ <th>Description</th>
51
+ </tr>
52
+ <% @cane[:violations][:documentation].each do |violation| %>
58
53
  <tr>
59
- <th>Description</th>
54
+ <td><%=violation[:description]%></td>
60
55
  </tr>
61
- <% @cane[:violations][:documentation].each do |violation| %>
62
- <tr>
63
- <td><%=violation[:description]%></td>
64
- </tr>
65
- <% end %>
66
- </table>
67
56
  <% end %>
68
- <% if @cane[:violations][:comment] && @cane[:violations][:comment].size > 0 %>
69
- <h3>Class definitions requiring comments (<%= @cane[:violations][:comment].size %>)</h3>
70
- <table>
71
- <tr>
72
- <th>File</th>
73
- <th>Class</th>
57
+ </table>
58
+ <% end %>
59
+ <% if @cane[:violations][:comment] && @cane[:violations][:comment].size > 0 %>
60
+ <h3>Class definitions requiring comments (<%= @cane[:violations][:comment].size %>)</h3>
61
+ <table>
62
+ <tr>
63
+ <th>File</th>
64
+ <th>Class</th>
65
+ </tr>
66
+ <% count = 0 %>
67
+ <% @cane[:violations][:comment].each do |violation| %>
68
+ <tr class='<%= cycle("light", "dark", count) %>'>
69
+ <td><%=violation[:line]%></td>
70
+ <td><%=violation[:class_name]%></td>
74
71
  </tr>
75
- <% count = 0 %>
76
- <% @cane[:violations][:comment].each do |violation| %>
77
- <tr class='<%= cycle("light", "dark", count) %>'>
78
- <td><%=violation[:line]%></td>
79
- <td><%=violation[:class_name]%></td>
80
- </tr>
81
- <% count += 1 %>
82
- <% end %>
83
- </table>
72
+ <% count += 1 %>
84
73
  <% end %>
85
- <% if @cane[:violations][:others] && @cane[:violations][:others].size > 0 %>
86
- <h3>Others (<%= @cane[:violations][:others].size %>)</h3>
87
- <table>
74
+ </table>
75
+ <% end %>
76
+ <% if @cane[:violations][:others] && @cane[:violations][:others].size > 0 %>
77
+ <h3>Others (<%= @cane[:violations][:others].size %>)</h3>
78
+ <table>
79
+ <tr>
80
+ <th>Description</th>
81
+ </tr>
82
+ <% @cane[:violations][:others].each do |violation| %>
88
83
  <tr>
89
- <th>Description</th>
84
+ <td><%=violation[:description]%></td>
90
85
  </tr>
91
- <% @cane[:violations][:others].each do |violation| %>
92
- <tr>
93
- <td><%=violation[:description]%></td>
94
- </tr>
95
- <% end %>
96
- </table>
97
86
  <% end %>
98
- <p>Generated on <%= Time.now.localtime %></p>
99
- </body>
100
- </html>
87
+ </table>
88
+ <% end %>
89
+ <p>Generated on <%= Time.now.localtime %></p>
@@ -27,10 +27,9 @@ module MetricFu
27
27
  def to_h
28
28
  {:churn => @churn[:churn]}
29
29
  end
30
-
30
+
31
31
  # @param args [Hash] churn metric run options
32
32
  # @return [Hash] churn results
33
- # @example {something}
34
33
  def run(args)
35
34
  # @note passing in false to report will return a hash
36
35
  # instead of the default String
@@ -2,8 +2,9 @@
2
2
 
3
3
  <p><a href='http://ruby.sadi.st/Flay.html'>Flay</a> analyzes ruby code for structural similarities.</p>
4
4
 
5
+ <div id="graph_container"></div>
6
+
5
7
  <% graph_name = 'flay' %>
6
- <canvas id="graph"></canvas>
7
8
  <script language="javascript" src="<%= graph_name %>.js?<%= Time.now.to_i %>" type="text/javascript"></script>
8
9
 
9
10
  <h4>Total Score (lower is better): <%= @flay[:total_score] %></h4>
@@ -1,8 +1,9 @@
1
1
  <h3>Flog Results</h3>
2
2
  <p><a href='http://ruby.sadi.st/Flog.html'>Flog</a> measures code complexity.</p>
3
3
 
4
+ <div id="graph_container"></div>
5
+
4
6
  <% graph_name = 'flog' %>
5
- <canvas id="graph"></canvas>
6
7
  <script language="javascript" src="<%= graph_name %>.js?<%= Time.now.to_i %>" type="text/javascript"></script>
7
8
 
8
9
  <h2>Total Flog score for all methods: <%= round_to_tenths @flog[:total]%></h2>
@@ -2,8 +2,9 @@
2
2
 
3
3
  <p><a href="http://github.com/railsbp/rails_best_practices">rails_best_practices</a> is a code metric tool for rails projects.</p>
4
4
 
5
+ <div id="graph_container"></div>
6
+
5
7
  <% graph_name = 'rails_best_practices' %>
6
- <canvas id="graph"></canvas>
7
8
  <script language="javascript" src="<%= graph_name %>.js?<%= Time.now.to_i %>" type="text/javascript"></script>
8
9
 
9
10
  <table>
@@ -0,0 +1,24 @@
1
+ # Reads and writes external coverage files as BINARY
2
+ module MetricFu
3
+ class RCovTestCoverageClient
4
+
5
+ def initialize(coverage_file)
6
+ @file_path = Pathname(coverage_file)
7
+ @file_path.dirname.mkpath
8
+ end
9
+
10
+ def post_results(payload)
11
+ mf_log "Saving coverage payload to #{@file_path}"
12
+ dump(payload)
13
+ end
14
+
15
+ def load
16
+ File.binread(@file_path)
17
+ end
18
+
19
+ def dump(payload)
20
+ File.open(@file_path, 'wb') {|file| file.write(payload) }
21
+ end
22
+
23
+ end
24
+ end
@@ -1,29 +1,17 @@
1
1
  MetricFu.lib_require { 'utility' }
2
2
  MetricFu.lib_require { 'calculate' }
3
3
  MetricFu.data_structures_require { 'line_numbers' }
4
+ require_relative 'rcov_format_coverage'
5
+ require_relative 'external_client'
4
6
 
5
7
  module MetricFu
6
8
 
7
9
  class RcovGenerator < MetricFu::Generator
8
- NEW_FILE_MARKER = /^={80}$/.freeze
9
10
 
10
11
  def self.metric
11
12
  :rcov
12
13
  end
13
14
 
14
- class Line
15
- attr_accessor :content, :was_run
16
-
17
- def initialize(content, was_run)
18
- @content = content
19
- @was_run = was_run
20
- end
21
-
22
- def to_h
23
- {:content => @content, :was_run => @was_run}
24
- end
25
- end
26
-
27
15
  def emit
28
16
  if run_rcov?
29
17
  mf_debug "** Running the specs/tests in the [#{options[:environment]}] environment"
@@ -54,105 +42,26 @@ module MetricFu
54
42
  end
55
43
 
56
44
  def analyze
57
- output = load_output
58
- output = output.split(NEW_FILE_MARKER)
59
-
60
- output.shift # Throw away the first entry - it's the execution time etc.
61
-
62
- files = assemble_files(output)
63
-
64
- @global_total_lines = 0
65
- @global_total_lines_run = 0
66
-
67
- @rcov = add_coverage_percentage(files)
45
+ rcov_text = load_output
46
+ formatter = MetricFu::RCovFormatCoverage.new(rcov_text)
47
+ @rcov = formatter.to_h
68
48
  end
69
49
 
70
50
  def to_h
71
- global_percent_run = ((@global_total_lines_run.to_f / @global_total_lines.to_f) * 100)
72
- add_method_data
73
- {:rcov => @rcov.merge({:global_percent_run => round_to_tenths(global_percent_run) })}
51
+ {
52
+ :rcov => @rcov
53
+ }
74
54
  end
75
55
 
76
56
  private
77
57
 
78
- def add_method_data
79
- @rcov.each_pair do |file_path, info|
80
- file_contents = ""
81
- coverage = []
82
-
83
- info[:lines].each_with_index do |line, index|
84
- file_contents << "#{line[:content]}\n"
85
- coverage << line[:was_run]
86
- end
87
-
88
- begin
89
- line_numbers = MetricFu::LineNumbers.new(file_contents)
90
- rescue StandardError => e
91
- raise e unless e.message =~ /you shouldn't be able to get here/
92
- mf_log "ruby_parser blew up while trying to parse #{file_path}. You won't have method level Rcov information for this file."
93
- next
94
- end
95
-
96
- method_coverage_map = {}
97
- coverage.each_with_index do |covered, index|
98
- line_number = index + 1
99
- if line_numbers.in_method?(line_number)
100
- method_name = line_numbers.method_at_line(line_number)
101
- method_coverage_map[method_name] ||= {}
102
- method_coverage_map[method_name][:total] ||= 0
103
- method_coverage_map[method_name][:total] += 1
104
- method_coverage_map[method_name][:uncovered] ||= 0
105
- method_coverage_map[method_name][:uncovered] += 1 if !covered
106
- end
107
- end
108
-
109
- @rcov[file_path][:methods] = {}
110
-
111
- method_coverage_map.each do |method_name, coverage_data|
112
- @rcov[file_path][:methods][method_name] = (coverage_data[:uncovered] / coverage_data[:total].to_f) * 100.0
113
- end
114
-
115
- end
116
- end
117
-
118
- def assemble_files(output)
119
- files = {}
120
- output.each_slice(2) {|out| files[out.first.strip] = out.last}
121
- files.each_pair {|fname, content| files[fname] = content.split("\n") }
122
- files.each_pair do |fname, content|
123
- content.map! do |raw_line|
124
- covered_line = raw_line.match(/^!!/).nil?
125
- Line.new(raw_line[3..-1], covered_line).to_h
126
- end
127
- content.reject! {|line| line[:content].to_s == '' }
128
- files[fname] = {:lines => content}
129
- end
130
- files
131
- end
132
-
133
- # TODO: remove multiple side effects
134
- # sets global ivars and
135
- # modifies the param passed in
136
- def add_coverage_percentage(files)
137
- files.each_pair do |fname, content|
138
- lines = content[:lines]
139
- lines_run = lines.count {|line| line[:was_run] }
140
- total_lines = lines.length
141
- integer_percent = Calculate.integer_percent(lines_run, total_lines)
142
-
143
- files[fname][:percent_run] = integer_percent
144
- @global_total_lines_run += lines_run
145
- @global_total_lines += total_lines
146
- end
147
- end
148
-
149
58
  # We never run rcov anymore
150
59
  def run_rcov?
151
60
  false
152
61
  end
153
62
 
154
63
  def load_output
155
- File.read(output_file)
64
+ MetricFu::RCovTestCoverageClient.new(output_file).load
156
65
  end
157
66
 
158
67
  def output_file