code_metric_fu 4.14.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.
Files changed (296) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/.metrics +3 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +15 -0
  6. data/.rubocop_todo.yml +69 -0
  7. data/.simplecov +74 -0
  8. data/.travis.yml +22 -0
  9. data/.yardopts +4 -0
  10. data/AUTHORS +12 -0
  11. data/CONTRIBUTING.md +47 -0
  12. data/CONTRIBUTORS +76 -0
  13. data/DEV.md +76 -0
  14. data/Gemfile +74 -0
  15. data/Guardfile +30 -0
  16. data/HISTORY.md +705 -0
  17. data/MIT-LICENSE +22 -0
  18. data/README.md +299 -0
  19. data/Rakefile +27 -0
  20. data/TODO.md +118 -0
  21. data/appveyor.yml +31 -0
  22. data/bin/metric_fu +9 -0
  23. data/bin/mf-cane +10 -0
  24. data/bin/mf-churn +10 -0
  25. data/bin/mf-flay +10 -0
  26. data/bin/mf-reek +10 -0
  27. data/bin/mf-roodi +10 -0
  28. data/bin/mf-saikuro +10 -0
  29. data/certs/bf4.pem +22 -0
  30. data/checksum/.gitkeep +0 -0
  31. data/checksum/metric_fu-4.10.0.gem.sha512 +1 -0
  32. data/checksum/metric_fu-4.11.0.gem.sha512 +1 -0
  33. data/checksum/metric_fu-4.11.1.gem.sha512 +1 -0
  34. data/checksum/metric_fu-4.11.2.gem.sha512 +1 -0
  35. data/checksum/metric_fu-4.11.3.gem.sha512 +1 -0
  36. data/checksum/metric_fu-4.11.4.gem.sha512 +1 -0
  37. data/checksum/metric_fu-4.12.0.gem.sha512 +1 -0
  38. data/checksum/metric_fu-4.2.0.gem.sha512 +1 -0
  39. data/checksum/metric_fu-4.2.1.gem.sha512 +1 -0
  40. data/checksum/metric_fu-4.3.0.gem.sha512 +1 -0
  41. data/checksum/metric_fu-4.3.1.gem.sha512 +1 -0
  42. data/checksum/metric_fu-4.4.0.gem.sha512 +1 -0
  43. data/checksum/metric_fu-4.4.1.gem.sha512 +1 -0
  44. data/checksum/metric_fu-4.4.2.gem.sha512 +1 -0
  45. data/checksum/metric_fu-4.4.3.gem.sha512 +1 -0
  46. data/checksum/metric_fu-4.4.4.gem.sha512 +1 -0
  47. data/checksum/metric_fu-4.5.0.gem.sha512 +1 -0
  48. data/checksum/metric_fu-4.5.1.gem.sha512 +1 -0
  49. data/checksum/metric_fu-4.5.2.gem.sha512 +1 -0
  50. data/checksum/metric_fu-4.6.0.gem.sha512 +1 -0
  51. data/checksum/metric_fu-4.7.0.gem.sha512 +1 -0
  52. data/checksum/metric_fu-4.7.1.gem.sha512 +1 -0
  53. data/checksum/metric_fu-4.7.2.gem.sha512 +1 -0
  54. data/checksum/metric_fu-4.7.3.gem.sha512 +1 -0
  55. data/checksum/metric_fu-4.7.4.gem.sha512 +1 -0
  56. data/checksum/metric_fu-4.8.0.gem.sha512 +1 -0
  57. data/checksum/metric_fu-4.9.0.gem.sha512 +1 -0
  58. data/config/roodi_config.yml +22 -0
  59. data/config/rubocop.yml +269 -0
  60. data/gem_tasks/build.rake +197 -0
  61. data/gem_tasks/rubocop.rake +10 -0
  62. data/gem_tasks/usage_test.rake +19 -0
  63. data/gem_tasks/yard.rake +24 -0
  64. data/lib/metric_fu/calculate.rb +10 -0
  65. data/lib/metric_fu/cli/client.rb +26 -0
  66. data/lib/metric_fu/cli/helper.rb +80 -0
  67. data/lib/metric_fu/cli/parser.rb +138 -0
  68. data/lib/metric_fu/configuration.rb +150 -0
  69. data/lib/metric_fu/constantize.rb +57 -0
  70. data/lib/metric_fu/data_structures/line_numbers.rb +112 -0
  71. data/lib/metric_fu/data_structures/location.rb +110 -0
  72. data/lib/metric_fu/data_structures/sexp_node.rb +107 -0
  73. data/lib/metric_fu/environment.rb +129 -0
  74. data/lib/metric_fu/errors/analysis_error.rb +4 -0
  75. data/lib/metric_fu/formatter/html.rb +96 -0
  76. data/lib/metric_fu/formatter/syntax.rb +45 -0
  77. data/lib/metric_fu/formatter/yaml.rb +18 -0
  78. data/lib/metric_fu/formatter.rb +40 -0
  79. data/lib/metric_fu/gem_run.rb +70 -0
  80. data/lib/metric_fu/gem_version.rb +92 -0
  81. data/lib/metric_fu/generator.rb +135 -0
  82. data/lib/metric_fu/io.rb +132 -0
  83. data/lib/metric_fu/loader.rb +105 -0
  84. data/lib/metric_fu/logger.rb +62 -0
  85. data/lib/metric_fu/logging/mf_debugger.rb +23 -0
  86. data/lib/metric_fu/metric.rb +143 -0
  87. data/lib/metric_fu/metrics/cane/generator.rb +95 -0
  88. data/lib/metric_fu/metrics/cane/grapher.rb +37 -0
  89. data/lib/metric_fu/metrics/cane/metric.rb +34 -0
  90. data/lib/metric_fu/metrics/cane/report.html.erb +87 -0
  91. data/lib/metric_fu/metrics/cane/violations.rb +46 -0
  92. data/lib/metric_fu/metrics/churn/generator.rb +37 -0
  93. data/lib/metric_fu/metrics/churn/hotspot.rb +43 -0
  94. data/lib/metric_fu/metrics/churn/metric.rb +29 -0
  95. data/lib/metric_fu/metrics/churn/report.html.erb +58 -0
  96. data/lib/metric_fu/metrics/flay/generator.rb +51 -0
  97. data/lib/metric_fu/metrics/flay/grapher.rb +37 -0
  98. data/lib/metric_fu/metrics/flay/hotspot.rb +52 -0
  99. data/lib/metric_fu/metrics/flay/metric.rb +28 -0
  100. data/lib/metric_fu/metrics/flay/report.html.erb +29 -0
  101. data/lib/metric_fu/metrics/flog/generator.rb +113 -0
  102. data/lib/metric_fu/metrics/flog/grapher.rb +77 -0
  103. data/lib/metric_fu/metrics/flog/hotspot.rb +46 -0
  104. data/lib/metric_fu/metrics/flog/metric.rb +29 -0
  105. data/lib/metric_fu/metrics/flog/report.html.erb +50 -0
  106. data/lib/metric_fu/metrics/hotspots/analysis/analyzed_problems.rb +34 -0
  107. data/lib/metric_fu/metrics/hotspots/analysis/analyzer_tables.rb +114 -0
  108. data/lib/metric_fu/metrics/hotspots/analysis/grouping.rb +23 -0
  109. data/lib/metric_fu/metrics/hotspots/analysis/groupings.rb +12 -0
  110. data/lib/metric_fu/metrics/hotspots/analysis/problems.rb +20 -0
  111. data/lib/metric_fu/metrics/hotspots/analysis/ranked_problem_location.rb +70 -0
  112. data/lib/metric_fu/metrics/hotspots/analysis/ranking.rb +29 -0
  113. data/lib/metric_fu/metrics/hotspots/analysis/rankings.rb +91 -0
  114. data/lib/metric_fu/metrics/hotspots/analysis/record.rb +32 -0
  115. data/lib/metric_fu/metrics/hotspots/analysis/scoring_strategies.rb +24 -0
  116. data/lib/metric_fu/metrics/hotspots/analysis/table.rb +67 -0
  117. data/lib/metric_fu/metrics/hotspots/generator.rb +40 -0
  118. data/lib/metric_fu/metrics/hotspots/hotspot.rb +87 -0
  119. data/lib/metric_fu/metrics/hotspots/hotspot_analyzer.rb +61 -0
  120. data/lib/metric_fu/metrics/hotspots/metric.rb +20 -0
  121. data/lib/metric_fu/metrics/hotspots/report.html.erb +60 -0
  122. data/lib/metric_fu/metrics/rails_best_practices/generator.rb +47 -0
  123. data/lib/metric_fu/metrics/rails_best_practices/grapher.rb +38 -0
  124. data/lib/metric_fu/metrics/rails_best_practices/metric.rb +31 -0
  125. data/lib/metric_fu/metrics/rails_best_practices/report.html.erb +22 -0
  126. data/lib/metric_fu/metrics/rcov/external_client.rb +22 -0
  127. data/lib/metric_fu/metrics/rcov/generator.rb +75 -0
  128. data/lib/metric_fu/metrics/rcov/grapher.rb +37 -0
  129. data/lib/metric_fu/metrics/rcov/hotspot.rb +46 -0
  130. data/lib/metric_fu/metrics/rcov/metric.rb +61 -0
  131. data/lib/metric_fu/metrics/rcov/rcov_format_coverage.rb +149 -0
  132. data/lib/metric_fu/metrics/rcov/rcov_line.rb +48 -0
  133. data/lib/metric_fu/metrics/rcov/report.html.erb +40 -0
  134. data/lib/metric_fu/metrics/rcov/simplecov_formatter.rb +74 -0
  135. data/lib/metric_fu/metrics/reek/generator.rb +97 -0
  136. data/lib/metric_fu/metrics/reek/grapher.rb +55 -0
  137. data/lib/metric_fu/metrics/reek/hotspot.rb +95 -0
  138. data/lib/metric_fu/metrics/reek/metric.rb +26 -0
  139. data/lib/metric_fu/metrics/reek/report.html.erb +35 -0
  140. data/lib/metric_fu/metrics/roodi/generator.rb +41 -0
  141. data/lib/metric_fu/metrics/roodi/grapher.rb +37 -0
  142. data/lib/metric_fu/metrics/roodi/hotspot.rb +39 -0
  143. data/lib/metric_fu/metrics/roodi/metric.rb +24 -0
  144. data/lib/metric_fu/metrics/roodi/report.html.erb +22 -0
  145. data/lib/metric_fu/metrics/saikuro/generator.rb +145 -0
  146. data/lib/metric_fu/metrics/saikuro/hotspot.rb +51 -0
  147. data/lib/metric_fu/metrics/saikuro/metric.rb +31 -0
  148. data/lib/metric_fu/metrics/saikuro/parsing_element.rb +37 -0
  149. data/lib/metric_fu/metrics/saikuro/report.html.erb +71 -0
  150. data/lib/metric_fu/metrics/saikuro/scratch_file.rb +108 -0
  151. data/lib/metric_fu/metrics/stats/generator.rb +82 -0
  152. data/lib/metric_fu/metrics/stats/grapher.rb +40 -0
  153. data/lib/metric_fu/metrics/stats/hotspot.rb +35 -0
  154. data/lib/metric_fu/metrics/stats/metric.rb +28 -0
  155. data/lib/metric_fu/metrics/stats/report.html.erb +44 -0
  156. data/lib/metric_fu/reporter.rb +37 -0
  157. data/lib/metric_fu/reporting/graphs/graph.rb +69 -0
  158. data/lib/metric_fu/reporting/graphs/grapher.rb +66 -0
  159. data/lib/metric_fu/reporting/result.rb +59 -0
  160. data/lib/metric_fu/run.rb +82 -0
  161. data/lib/metric_fu/tasks/metric_fu.rake +54 -0
  162. data/lib/metric_fu/templates/_gem_info.html.erb +8 -0
  163. data/lib/metric_fu/templates/_graph.html.erb +2 -0
  164. data/lib/metric_fu/templates/_report_footer.html.erb +1 -0
  165. data/lib/metric_fu/templates/configuration.rb +25 -0
  166. data/lib/metric_fu/templates/css/bluff.css +15 -0
  167. data/lib/metric_fu/templates/css/buttons.css +82 -0
  168. data/lib/metric_fu/templates/css/default.css +43 -0
  169. data/lib/metric_fu/templates/css/integrity.css +337 -0
  170. data/lib/metric_fu/templates/css/rcov.css +32 -0
  171. data/lib/metric_fu/templates/css/reset.css +7 -0
  172. data/lib/metric_fu/templates/css/syntax.css +19 -0
  173. data/lib/metric_fu/templates/index.html.erb +13 -0
  174. data/lib/metric_fu/templates/javascripts/bluff-min.js +1 -0
  175. data/lib/metric_fu/templates/javascripts/bluff_graph.js +15 -0
  176. data/lib/metric_fu/templates/javascripts/excanvas.js +35 -0
  177. data/lib/metric_fu/templates/javascripts/highcharts.js +294 -0
  178. data/lib/metric_fu/templates/javascripts/highcharts_graph.js +38 -0
  179. data/lib/metric_fu/templates/javascripts/js-class.js +1 -0
  180. data/lib/metric_fu/templates/javascripts/standalone-framework.js +17 -0
  181. data/lib/metric_fu/templates/javascripts/utils.js +9 -0
  182. data/lib/metric_fu/templates/layout.html.erb +41 -0
  183. data/lib/metric_fu/templates/metrics_template.rb +86 -0
  184. data/lib/metric_fu/templates/report.html.erb +31 -0
  185. data/lib/metric_fu/templates/report.rb +41 -0
  186. data/lib/metric_fu/templates/template.rb +247 -0
  187. data/lib/metric_fu/utility.rb +79 -0
  188. data/lib/metric_fu/version.rb +9 -0
  189. data/lib/metric_fu.rb +143 -0
  190. data/metric_fu.gemspec +72 -0
  191. data/spec/capture_warnings.rb +55 -0
  192. data/spec/cli/helper_spec.rb +165 -0
  193. data/spec/dummy/.gitignore +1 -0
  194. data/spec/dummy/.gitkeep +0 -0
  195. data/spec/dummy/.metrics +4 -0
  196. data/spec/dummy/lib/.gitkeep +0 -0
  197. data/spec/dummy/lib/bad_encoding.rb +6 -0
  198. data/spec/dummy/spec/.gitkeep +0 -0
  199. data/spec/fixtures/20090630.yml +7922 -0
  200. data/spec/fixtures/coverage-153.rb +11 -0
  201. data/spec/fixtures/coverage.rb +13 -0
  202. data/spec/fixtures/exit0.sh +3 -0
  203. data/spec/fixtures/exit1.sh +3 -0
  204. data/spec/fixtures/hotspots/flog.yml +86 -0
  205. data/spec/fixtures/hotspots/generator.yml +47 -0
  206. data/spec/fixtures/hotspots/generator_analysis.yml +53 -0
  207. data/spec/fixtures/hotspots/reek.yml +14 -0
  208. data/spec/fixtures/hotspots/roodi.yml +13 -0
  209. data/spec/fixtures/hotspots/saikuro.yml +27 -0
  210. data/spec/fixtures/hotspots/several_metrics.yml +47 -0
  211. data/spec/fixtures/hotspots/stats.yml +4 -0
  212. data/spec/fixtures/hotspots/three_metrics_on_same_file.yml +36 -0
  213. data/spec/fixtures/line_numbers/foo.rb +33 -0
  214. data/spec/fixtures/line_numbers/module.rb +11 -0
  215. data/spec/fixtures/line_numbers/module_surrounds_class.rb +15 -0
  216. data/spec/fixtures/line_numbers/two_classes.rb +11 -0
  217. data/spec/fixtures/metric_missing.yml +1 -0
  218. data/spec/fixtures/rcov_output.txt +135 -0
  219. data/spec/fixtures/saikuro/app/controllers/sessions_controller.rb_cyclo.html +10 -0
  220. data/spec/fixtures/saikuro/app/controllers/users_controller.rb_cyclo.html +16 -0
  221. data/spec/fixtures/saikuro/index_cyclo.html +155 -0
  222. data/spec/fixtures/saikuro_sfiles/thing.rb_cyclo.html +11 -0
  223. data/spec/metric_fu/calculate_spec.rb +21 -0
  224. data/spec/metric_fu/configuration_spec.rb +90 -0
  225. data/spec/metric_fu/data_structures/line_numbers_spec.rb +63 -0
  226. data/spec/metric_fu/data_structures/location_spec.rb +110 -0
  227. data/spec/metric_fu/formatter/configuration_spec.rb +44 -0
  228. data/spec/metric_fu/formatter/html_spec.rb +138 -0
  229. data/spec/metric_fu/formatter/yaml_spec.rb +61 -0
  230. data/spec/metric_fu/formatter_spec.rb +49 -0
  231. data/spec/metric_fu/gem_version_spec.rb +12 -0
  232. data/spec/metric_fu/generator_spec.rb +130 -0
  233. data/spec/metric_fu/loader_spec.rb +10 -0
  234. data/spec/metric_fu/metric_spec.rb +46 -0
  235. data/spec/metric_fu/metrics/cane/configuration_spec.rb +22 -0
  236. data/spec/metric_fu/metrics/cane/generator_spec.rb +184 -0
  237. data/spec/metric_fu/metrics/churn/configuration_spec.rb +13 -0
  238. data/spec/metric_fu/metrics/churn/generator_spec.rb +64 -0
  239. data/spec/metric_fu/metrics/flay/configuration_spec.rb +13 -0
  240. data/spec/metric_fu/metrics/flay/generator_spec.rb +105 -0
  241. data/spec/metric_fu/metrics/flay/grapher_spec.rb +57 -0
  242. data/spec/metric_fu/metrics/flog/configuration_spec.rb +18 -0
  243. data/spec/metric_fu/metrics/flog/generator_spec.rb +77 -0
  244. data/spec/metric_fu/metrics/flog/grapher_spec.rb +107 -0
  245. data/spec/metric_fu/metrics/hotspots/analysis/analyzed_problems_spec.rb +104 -0
  246. data/spec/metric_fu/metrics/hotspots/analysis/analyzer_tables_spec.rb +71 -0
  247. data/spec/metric_fu/metrics/hotspots/analysis/ranking_spec.rb +30 -0
  248. data/spec/metric_fu/metrics/hotspots/analysis/rankings_spec.rb +97 -0
  249. data/spec/metric_fu/metrics/hotspots/analysis/table_spec.rb +6 -0
  250. data/spec/metric_fu/metrics/hotspots/generator_spec.rb +46 -0
  251. data/spec/metric_fu/metrics/hotspots/hotspot_analyzer_spec.rb +10 -0
  252. data/spec/metric_fu/metrics/hotspots/hotspot_spec.rb +16 -0
  253. data/spec/metric_fu/metrics/rails_best_practices/configuration_spec.rb +55 -0
  254. data/spec/metric_fu/metrics/rails_best_practices/generator_spec.rb +33 -0
  255. data/spec/metric_fu/metrics/rails_best_practices/grapher_spec.rb +62 -0
  256. data/spec/metric_fu/metrics/rcov/configuration_spec.rb +28 -0
  257. data/spec/metric_fu/metrics/rcov/generator_spec.rb +22 -0
  258. data/spec/metric_fu/metrics/rcov/grapher_spec.rb +57 -0
  259. data/spec/metric_fu/metrics/rcov/hotspot_spec.rb +20 -0
  260. data/spec/metric_fu/metrics/rcov/rcov_line_spec.rb +89 -0
  261. data/spec/metric_fu/metrics/rcov/simplecov_formatter_spec.rb +67 -0
  262. data/spec/metric_fu/metrics/reek/configuration_spec.rb +13 -0
  263. data/spec/metric_fu/metrics/reek/generator_spec.rb +169 -0
  264. data/spec/metric_fu/metrics/reek/grapher_spec.rb +66 -0
  265. data/spec/metric_fu/metrics/roodi/configuration_spec.rb +14 -0
  266. data/spec/metric_fu/metrics/roodi/generator_spec.rb +82 -0
  267. data/spec/metric_fu/metrics/roodi/grapher_spec.rb +57 -0
  268. data/spec/metric_fu/metrics/saikuro/configuration_spec.rb +25 -0
  269. data/spec/metric_fu/metrics/saikuro/generator_spec.rb +71 -0
  270. data/spec/metric_fu/metrics/stats/generator_spec.rb +96 -0
  271. data/spec/metric_fu/metrics/stats/grapher_spec.rb +69 -0
  272. data/spec/metric_fu/reporter_spec.rb +41 -0
  273. data/spec/metric_fu/reporting/graphs/graph_spec.rb +44 -0
  274. data/spec/metric_fu/reporting/graphs/grapher_spec.rb +24 -0
  275. data/spec/metric_fu/reporting/result_spec.rb +50 -0
  276. data/spec/metric_fu/run_spec.rb +197 -0
  277. data/spec/metric_fu/templates/configuration_spec.rb +51 -0
  278. data/spec/metric_fu/templates/metrics_template_spec.rb +11 -0
  279. data/spec/metric_fu/templates/report_spec.rb +15 -0
  280. data/spec/metric_fu/templates/template_spec.rb +233 -0
  281. data/spec/metric_fu/utility_spec.rb +12 -0
  282. data/spec/metric_fu_spec.rb +33 -0
  283. data/spec/quality_spec.rb +114 -0
  284. data/spec/shared/configured.rb +45 -0
  285. data/spec/shared/test_coverage.rb +95 -0
  286. data/spec/spec_helper.rb +54 -0
  287. data/spec/support/deferred_garbaged_collection.rb +33 -0
  288. data/spec/support/helper_methods.rb +32 -0
  289. data/spec/support/matcher_create_file.rb +37 -0
  290. data/spec/support/matcher_create_files.rb +43 -0
  291. data/spec/support/suite.rb +26 -0
  292. data/spec/support/test_fixtures.rb +37 -0
  293. data/spec/support/timeout.rb +7 -0
  294. data/spec/support/usage_test.rb +150 -0
  295. data/spec/usage_test_spec.rb +93 -0
  296. metadata +757 -0
@@ -0,0 +1,87 @@
1
+ <h3>Cane Results</h3>
2
+
3
+ <p><a href='https://github.com/square/cane'>Cane</a> reports code quality threshold violations.</p>
4
+
5
+ <%= render_partial 'graph', {:graph_name => 'cane'} %>
6
+
7
+ <% if @cane[:violations][:abc_complexity] && @cane[:violations][:abc_complexity].size > 0 %>
8
+ <h3>Methods exceeding allowed Abc complexity (<%= @cane[:violations][:abc_complexity].size %>)</h3>
9
+ <table>
10
+ <tr>
11
+ <th>File</th>
12
+ <th>Method</th>
13
+ <th>Complexity</th>
14
+ </tr>
15
+ <% count = 0 %>
16
+ <% @cane[:violations][:abc_complexity].each do |violation| %>
17
+ <tr class='<%= cycle("light", "dark", count) %>'>
18
+ <td><%=link_to_filename(violation[:file])%></td>
19
+ <td><%=violation[:method]%></td>
20
+ <td><%=violation[:complexity]%></td>
21
+ </tr>
22
+ <% count += 1 %>
23
+ <% end %>
24
+ </table>
25
+ <% end %>
26
+ <% if @cane[:violations][:line_style] && @cane[:violations][:line_style].size > 0 %>
27
+ <h3>Lines violating style requirements (<%= @cane[:violations][:line_style].size %>)</h3>
28
+ <table>
29
+ <tr>
30
+ <th>File</th>
31
+ <th>Description</th>
32
+ </tr>
33
+ <% count = 0 %>
34
+ <% @cane[:violations][:line_style].each do |violation| %>
35
+ <tr class='<%= cycle("light", "dark", count) %>'>
36
+ <td><%=link_to_filename(*violation[:line].split(':'))%></td>
37
+ <td><%=violation[:description]%></td>
38
+ </tr>
39
+ <% count += 1 %>
40
+ <% end %>
41
+ </table>
42
+ <% end %>
43
+ <% if @cane[:violations][:documentation] && @cane[:violations][:documentation].size > 0 %>
44
+ <h3>Missing documentation (<%= @cane[:violations][:documentation].size %>)</h3>
45
+ <table>
46
+ <tr>
47
+ <th>Description</th>
48
+ </tr>
49
+ <% @cane[:violations][:documentation].each do |violation| %>
50
+ <tr>
51
+ <td><%=violation[:description]%></td>
52
+ </tr>
53
+ <% end %>
54
+ </table>
55
+ <% end %>
56
+ <% if @cane[:violations][:comment] && @cane[:violations][:comment].size > 0 %>
57
+ <h3>Class definitions requiring comments (<%= @cane[:violations][:comment].size %>)</h3>
58
+ <table>
59
+ <tr>
60
+ <th>File</th>
61
+ <th>Class</th>
62
+ </tr>
63
+ <% count = 0 %>
64
+ <% @cane[:violations][:comment].each do |violation| %>
65
+ <tr class='<%= cycle("light", "dark", count) %>'>
66
+ <td><%=link_to_filename(*violation[:line].split(':'))%></td>
67
+ <td><%=violation[:class_name]%></td>
68
+ </tr>
69
+ <% count += 1 %>
70
+ <% end %>
71
+ </table>
72
+ <% end %>
73
+ <% if @cane[:violations][:others] && @cane[:violations][:others].size > 0 %>
74
+ <h3>Others (<%= @cane[:violations][:others].size %>)</h3>
75
+ <table>
76
+ <tr>
77
+ <th>Description</th>
78
+ </tr>
79
+ <% @cane[:violations][:others].each do |violation| %>
80
+ <tr>
81
+ <td><%=violation[:description]%></td>
82
+ </tr>
83
+ <% end %>
84
+ </table>
85
+ <% end %>
86
+
87
+ <%= render_partial 'report_footer' %>
@@ -0,0 +1,46 @@
1
+ module MetricFu
2
+ module CaneViolations
3
+ class AbcComplexity
4
+ def self.parse(violation_list)
5
+ violation_list.split(/\n/).map do |violation|
6
+ file, method, complexity = violation.split
7
+ { file: file, method: method, complexity: complexity }
8
+ end
9
+ end
10
+ end
11
+
12
+ class LineStyle
13
+ def self.parse(violation_list)
14
+ violation_list.split(/\n/).map do |violation|
15
+ line, description = violation.split(/\s{2,}/).reject { |x|x.strip == "" }
16
+ { line: line, description: description }
17
+ end
18
+ end
19
+ end
20
+
21
+ class Comment
22
+ def self.parse(violation_list)
23
+ violation_list.split(/\n/).map do |violation|
24
+ line, class_name = violation.split
25
+ { line: line, class_name: class_name }
26
+ end
27
+ end
28
+ end
29
+
30
+ class Documentation
31
+ def self.parse(violation_list)
32
+ violation_list.split(/\n/).map do |violation|
33
+ { description: violation.strip }
34
+ end
35
+ end
36
+ end
37
+
38
+ class Others
39
+ def self.parse(violation_list)
40
+ violation_list.split(/\n/).map do |violation|
41
+ { description: violation.strip }
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,37 @@
1
+ module MetricFu
2
+ class ChurnGenerator < Generator
3
+ def self.metric
4
+ :churn
5
+ end
6
+
7
+ ###
8
+ # options available are what can be passed to churn_calculator
9
+ # https://github.com/danmayer/churn#library-options
10
+ ###
11
+ def emit
12
+ @output = run(options)
13
+ end
14
+
15
+ def analyze
16
+ if @output.nil? || @output.size.zero?
17
+ @churn = { churn: {} }
18
+ else
19
+ @churn = @output
20
+ end
21
+ @churn
22
+ end
23
+
24
+ # ensure hash only has the :churn key
25
+ def to_h
26
+ { churn: @churn[:churn] }
27
+ end
28
+
29
+ # @param args [Hash] churn metric run options
30
+ # @return [Hash] churn results
31
+ def run(args)
32
+ # @note passing in false to report will return a hash
33
+ # instead of the default String
34
+ ::Churn::ChurnCalculator.new(args).report(false)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,43 @@
1
+ class MetricFu::ChurnHotspot < MetricFu::Hotspot
2
+ COLUMNS = %w{times_changed}
3
+
4
+ def columns
5
+ COLUMNS
6
+ end
7
+
8
+ def name
9
+ :churn
10
+ end
11
+
12
+ def map_strategy
13
+ :present
14
+ end
15
+
16
+ def reduce_strategy
17
+ :sum
18
+ end
19
+
20
+ def score_strategy
21
+ :calculate_score
22
+ end
23
+
24
+ def calculate_score(metric_ranking, item)
25
+ flat_churn_score = 0.50
26
+ metric_ranking.scored?(item) ? flat_churn_score : 0
27
+ end
28
+
29
+ def generate_records(data, table)
30
+ return if data == nil
31
+ Array(data[:changes]).each do |change|
32
+ table << {
33
+ "metric" => :churn,
34
+ "times_changed" => change[:times_changed],
35
+ "file_path" => change[:file_path]
36
+ }
37
+ end
38
+ end
39
+
40
+ def present_group(group)
41
+ "detected high level of churn (changed #{group[0].times_changed} times)"
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ module MetricFu
2
+ class MetricChurn < Metric
3
+ def name
4
+ :churn
5
+ end
6
+
7
+ def default_run_options
8
+ {
9
+ start_date: '"1 year ago"',
10
+ minimum_churn_count: 10,
11
+ ignore_files: [],
12
+ data_directory: MetricFu::Io::FileSystem.scratch_directory(name)
13
+ }
14
+ end
15
+
16
+ def has_graph?
17
+ false
18
+ end
19
+
20
+ def enable
21
+ super
22
+ end
23
+
24
+ def activate
25
+ activate_library("churn/calculator")
26
+ super
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,58 @@
1
+ <h3>Source Control Churn Results</h3>
2
+ <p>Files that change a lot in your project may be bad a sign.
3
+ This task uses your source control log to identify those files.
4
+ </p>
5
+ <table>
6
+ <tr>
7
+ <th>File Path</th>
8
+ <th>Times Changed</th>
9
+ </tr>
10
+ <% count = 0 %>
11
+ <% if @churn[:changes] %>
12
+ <% @churn[:changes].each do |change| %>
13
+ <tr>
14
+ <td><%= link_to_filename(change[:file_path]) %></td>
15
+ <td><%= change[:times_changed] %></td>
16
+ </tr>
17
+ <% count += 1 %>
18
+ <% end %>
19
+ <% end %>
20
+ </table>
21
+
22
+ <% if @churn[:class_churn] %>
23
+ <p>Classes that change a lot in your project may be bad a sign.</p>
24
+ <table>
25
+ <tr>
26
+ <th>File Path</th>
27
+ <th>Times Changed</th>
28
+ </tr>
29
+ <% count = 0 %>
30
+ <% @churn[:class_churn].each do |change| %>
31
+ <tr>
32
+ <td><%= link_to_filename(change['klass']['file']) %> <%= change['klass']['klass'] %></td>
33
+ <td><%= change['times_changed'] %></td>
34
+ </tr>
35
+ <% count += 1 %>
36
+ <% end %>
37
+ </table>
38
+ <% end %>
39
+
40
+ <% if @churn[:method_churn] %>
41
+ <p>Methods that change a lot in your project may be bad a sign.</p>
42
+ <table>
43
+ <tr>
44
+ <th>File Path</th>
45
+ <th>Times Changed</th>
46
+ </tr>
47
+ <% count = 0 %>
48
+ <% @churn[:method_churn].each do |change| %>
49
+ <tr>
50
+ <td><%= link_to_filename(change['method']['file']) %> <%= change['method']['method'] %></td>
51
+ <td><%= change['times_changed'] %></td>
52
+ </tr>
53
+ <% count += 1 %>
54
+ <% end %>
55
+ </table>
56
+ <% end %>
57
+
58
+ <%= render_partial 'report_footer' %>
@@ -0,0 +1,51 @@
1
+ module MetricFu
2
+ class FlayGenerator < Generator
3
+ def self.metric
4
+ :flay
5
+ end
6
+
7
+ def emit
8
+ args = "#{minimum_duplication_mass} #{dirs_to_flay}"
9
+ @output = run!(args)
10
+ end
11
+
12
+ def analyze
13
+ @matches = @output.chomp.split("\n\n").map { |m| m.split("\n ") }
14
+ end
15
+
16
+ def to_h
17
+ { flay: calculate_result(@matches) }
18
+ end
19
+
20
+ # TODO: move into analyze method
21
+ def calculate_result(matches)
22
+ total_score = matches.shift.first.split("=").last.strip
23
+ target = []
24
+ matches.each do |problem|
25
+ reason = problem.shift.strip
26
+ lines_info = problem.map do |full_line|
27
+ name, line = full_line.split(":").map(&:strip)
28
+ { name: name, line: line }
29
+ end
30
+ target << [reason: reason, matches: lines_info]
31
+ end
32
+ {
33
+ total_score: total_score,
34
+ matches: target.flatten
35
+ }
36
+ end
37
+
38
+ private
39
+
40
+ def minimum_duplication_mass
41
+ flay_mass = options[:minimum_score]
42
+ return "" unless flay_mass
43
+
44
+ "--mass #{flay_mass} "
45
+ end
46
+
47
+ def dirs_to_flay
48
+ options[:dirs_to_flay].join(" ")
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,37 @@
1
+ MetricFu.reporting_require { "graphs/grapher" }
2
+ module MetricFu
3
+ class FlayGrapher < Grapher
4
+ attr_accessor :flay_score, :labels
5
+
6
+ def self.metric
7
+ :flay
8
+ end
9
+
10
+ def initialize
11
+ super
12
+ @flay_score = []
13
+ @labels = {}
14
+ end
15
+
16
+ def get_metrics(metrics, date)
17
+ if metrics && metrics[:flay]
18
+ @flay_score.push(metrics[:flay][:total_score].to_i)
19
+ @labels.update(@labels.size => date)
20
+ end
21
+ end
22
+
23
+ def title
24
+ "Flay: duplication"
25
+ end
26
+
27
+ def data
28
+ [
29
+ ["flay", @flay_score.join(",")]
30
+ ]
31
+ end
32
+
33
+ def output_filename
34
+ "flay.js"
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,52 @@
1
+ class MetricFu::FlayHotspot < MetricFu::Hotspot
2
+ COLUMNS = %w{flay_reason flay_matching_reason}
3
+
4
+ def columns
5
+ COLUMNS
6
+ end
7
+
8
+ def name
9
+ :flay
10
+ end
11
+
12
+ def map_strategy
13
+ :present
14
+ end
15
+
16
+ def reduce_strategy
17
+ :sum
18
+ end
19
+
20
+ def score_strategy
21
+ :percentile
22
+ end
23
+
24
+ def generate_records(data, table)
25
+ return if data == nil
26
+ Array(data[:matches]).each do |match|
27
+ problems = match[:reason]
28
+ matching_reason = problems.gsub(/^[0-9]+\) /, "").gsub(/\:[0-9]+/, "")
29
+ files = []
30
+ locations = []
31
+ match[:matches].each do |file_match|
32
+ file_path = file_match[:name].sub(%r{^/}, "")
33
+ locations << "#{file_path}:#{file_match[:line]}"
34
+ files << file_path
35
+ end
36
+ files = files.uniq
37
+ files.each do |file|
38
+ table << {
39
+ "metric" => name,
40
+ "file_path" => file,
41
+ "flay_reason" => problems + " files: #{locations.join(', ')}",
42
+ "flay_matching_reason" => matching_reason
43
+ }
44
+ end
45
+ end
46
+ end
47
+
48
+ def present_group(group)
49
+ occurences = group.size
50
+ "found #{occurences} code duplications"
51
+ end
52
+ end
@@ -0,0 +1,28 @@
1
+ module MetricFu
2
+ class MetricFlay < Metric
3
+ def name
4
+ :flay
5
+ end
6
+
7
+ def default_run_options
8
+ { dirs_to_flay: MetricFu::Io::FileSystem.directory("code_dirs"),
9
+ # MetricFu has been setting the minimum score as 100 for
10
+ # a long time. This is a really big number, considering
11
+ # the default is 16. Setting it to nil to use the Flay default.
12
+ minimum_score: nil,
13
+ }
14
+ end
15
+
16
+ def has_graph?
17
+ true
18
+ end
19
+
20
+ def enable
21
+ super
22
+ end
23
+
24
+ def activate
25
+ super
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ <h3>Flay Results</h3>
2
+
3
+ <p><a href='http://ruby.sadi.st/Flay.html'>Flay</a> analyzes ruby code for structural similarities.</p>
4
+
5
+ <%= render_partial 'graph', {:graph_name => 'flay'} %>
6
+
7
+ <h4>Total Score (lower is better): <%= @flay[:total_score] %></h4>
8
+ <h5>Scores less than <%= MetricFu::Metric.get_metric('flay').run_options[:minimum_score] %> are not shown or part of the total</h5>
9
+
10
+ <table>
11
+ <tr>
12
+ <th>Files</th>
13
+ <th>Matches</th>
14
+ </tr>
15
+ <% count = 0 %>
16
+ <% @flay[:matches].each do |match| %>
17
+ <tr class='<%= cycle("light", "dark", count) %>'>
18
+ <td>
19
+ <% match[:matches].each do |file| %>
20
+ <%= link_to_filename(file[:name], file[:line]) %><br/>
21
+ <% end %>
22
+ </td>
23
+ <td><%= match[:reason] %></td>
24
+ </tr>
25
+ <% count += 1 %>
26
+ <% end %>
27
+ </table>
28
+
29
+ <%= render_partial 'report_footer' %>
@@ -0,0 +1,113 @@
1
+ require "pathname"
2
+ require "optparse"
3
+
4
+ module MetricFu
5
+ class FlogGenerator < Generator
6
+ def self.metric
7
+ :flog
8
+ end
9
+
10
+ def emit
11
+ parse_options = FlogCLI.parse_options [
12
+ "--all",
13
+ options[:continue] ? "--continue" : nil,
14
+ ].compact
15
+ @flogger = FlogCLI.new parse_options
16
+ @flogger.flog *files_to_flog
17
+ end
18
+
19
+ def analyze
20
+ @method_containers = {}
21
+ @flogger.calculate
22
+ @flogger.each_by_score do |full_method_name, score, operators|
23
+ container_name = full_method_name.split("#").first
24
+ path = @flogger.method_locations[full_method_name]
25
+ if @method_containers[container_name]
26
+ @method_containers[container_name].add_method(full_method_name, operators, score, path)
27
+ @method_containers[container_name].add_path(path)
28
+ else
29
+ mc = MethodContainer.new(container_name, path)
30
+ mc.add_method(full_method_name, operators, score, path)
31
+ @method_containers[container_name] = mc
32
+ end
33
+ end
34
+ end
35
+
36
+ def to_h
37
+ sorted_containers = @method_containers.values.sort_by(&:highest_score).reverse
38
+ { flog: { total: @flogger.total_score,
39
+ average: @flogger.average,
40
+ method_containers: sorted_containers.map(&:to_h) } }
41
+ end
42
+
43
+ def per_file_info(out)
44
+ @method_containers.each_pair do |_klass, container|
45
+ container.methods.each_pair do |_method_name, data|
46
+ next if data[:path].nil?
47
+
48
+ file, line = data[:path].split(":")
49
+
50
+ out[file][line] << { type: :flog, description: "Score of %.2f" % data[:score] }
51
+ end
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def files_to_flog
58
+ options[:dirs_to_flog].flatten.map do |p|
59
+ if File.directory? p then
60
+ Dir[File.join(p, '**/*.{rb,rake}')]
61
+ else
62
+ p
63
+ end
64
+ end.flatten
65
+ end
66
+ end
67
+
68
+ class MethodContainer
69
+ attr_reader :methods
70
+
71
+ def initialize(name, path)
72
+ @name = name
73
+ add_path path
74
+ @methods = {}
75
+ end
76
+
77
+ def add_path(path)
78
+ return unless path
79
+ @path ||= path.split(":").first
80
+ end
81
+
82
+ def add_method(full_method_name, operators, score, path)
83
+ @methods[full_method_name] = { operators: operators, score: score, path: path }
84
+ end
85
+
86
+ def to_h
87
+ { name: @name,
88
+ path: @path || "",
89
+ total_score: total_score,
90
+ highest_score: highest_score,
91
+ average_score: average_score,
92
+ methods: @methods }
93
+ end
94
+
95
+ def highest_score
96
+ method_scores.max
97
+ end
98
+
99
+ private
100
+
101
+ def method_scores
102
+ @method_scores ||= @methods.values.map { |v| v[:score] }
103
+ end
104
+
105
+ def total_score
106
+ @total_score ||= method_scores.inject(0) { |sum, score| sum += score }
107
+ end
108
+
109
+ def average_score
110
+ total_score / method_scores.size.to_f
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,77 @@
1
+ MetricFu.reporting_require { "graphs/grapher" }
2
+ module MetricFu
3
+ class FlogGrapher < Grapher
4
+ attr_accessor :flog_average, :labels, :top_five_percent_average
5
+
6
+ def self.metric
7
+ :flog
8
+ end
9
+
10
+ def initialize
11
+ super
12
+ @flog_average = []
13
+ @labels = {}
14
+ @top_five_percent_average = []
15
+ end
16
+
17
+ def get_metrics(metrics, date)
18
+ if metrics && metrics[:flog]
19
+ @top_five_percent_average.push(calc_top_five_percent_average(metrics))
20
+ @flog_average.push(metrics[:flog][:average])
21
+ @labels.update(@labels.size => date)
22
+ end
23
+ end
24
+
25
+ def title
26
+ "Flog: code complexity"
27
+ end
28
+
29
+ def data
30
+ [
31
+ ["average", @flog_average.join(",")],
32
+ ["top 5% average", @top_five_percent_average.join(",")]
33
+ ]
34
+ end
35
+
36
+ def output_filename
37
+ "flog.js"
38
+ end
39
+
40
+ private
41
+
42
+ def calc_top_five_percent_average(metrics)
43
+ return calc_top_five_percent_average_legacy(metrics) if metrics[:flog][:pages]
44
+
45
+ method_scores = metrics[:flog][:method_containers].inject([]) do |method_scores, container|
46
+ method_scores += container[:methods].values.map { |v| v[:score] }
47
+ end
48
+ method_scores.sort!.reverse!
49
+
50
+ number_of_methods_that_is_five_percent = (method_scores.size * 0.05).ceil
51
+
52
+ total_for_five_percent =
53
+ method_scores[0...number_of_methods_that_is_five_percent].inject(0) { |total, score| total += score }
54
+ if number_of_methods_that_is_five_percent == 0
55
+ 0.0
56
+ else
57
+ total_for_five_percent / number_of_methods_that_is_five_percent.to_f
58
+ end
59
+ end
60
+
61
+ def calc_top_five_percent_average_legacy(metrics)
62
+ methods = metrics[:flog][:pages].inject([]) { |methods, page| methods << page[:scanned_methods] }
63
+ methods.flatten!
64
+ methods = methods.sort_by { |method| method[:score] }.reverse
65
+
66
+ number_of_methods_that_is_five_percent = (methods.size * 0.05).ceil
67
+
68
+ total_for_five_percent =
69
+ methods[0...number_of_methods_that_is_five_percent].inject(0) { |total, method| total += method[:score] }
70
+ if number_of_methods_that_is_five_percent == 0
71
+ 0.0
72
+ else
73
+ total_for_five_percent / number_of_methods_that_is_five_percent.to_f
74
+ end
75
+ end
76
+ end
77
+ end