fastruby-metric_fu 5.0.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 +18 -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 +58 -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 +29 -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.rb +151 -0
  65. data/lib/metric_fu/calculate.rb +10 -0
  66. data/lib/metric_fu/cli/client.rb +26 -0
  67. data/lib/metric_fu/cli/helper.rb +80 -0
  68. data/lib/metric_fu/cli/parser.rb +138 -0
  69. data/lib/metric_fu/configuration.rb +150 -0
  70. data/lib/metric_fu/constantize.rb +57 -0
  71. data/lib/metric_fu/data_structures/line_numbers.rb +112 -0
  72. data/lib/metric_fu/data_structures/location.rb +110 -0
  73. data/lib/metric_fu/data_structures/sexp_node.rb +107 -0
  74. data/lib/metric_fu/environment.rb +129 -0
  75. data/lib/metric_fu/errors/analysis_error.rb +4 -0
  76. data/lib/metric_fu/formatter.rb +40 -0
  77. data/lib/metric_fu/formatter/html.rb +96 -0
  78. data/lib/metric_fu/formatter/syntax.rb +45 -0
  79. data/lib/metric_fu/formatter/yaml.rb +18 -0
  80. data/lib/metric_fu/gem_run.rb +70 -0
  81. data/lib/metric_fu/gem_version.rb +92 -0
  82. data/lib/metric_fu/generator.rb +135 -0
  83. data/lib/metric_fu/io.rb +132 -0
  84. data/lib/metric_fu/loader.rb +105 -0
  85. data/lib/metric_fu/logger.rb +62 -0
  86. data/lib/metric_fu/logging/mf_debugger.rb +23 -0
  87. data/lib/metric_fu/metric.rb +143 -0
  88. data/lib/metric_fu/metrics/cane/generator.rb +95 -0
  89. data/lib/metric_fu/metrics/cane/grapher.rb +37 -0
  90. data/lib/metric_fu/metrics/cane/metric.rb +34 -0
  91. data/lib/metric_fu/metrics/cane/report.html.erb +87 -0
  92. data/lib/metric_fu/metrics/cane/violations.rb +46 -0
  93. data/lib/metric_fu/metrics/churn/generator.rb +37 -0
  94. data/lib/metric_fu/metrics/churn/hotspot.rb +43 -0
  95. data/lib/metric_fu/metrics/churn/metric.rb +29 -0
  96. data/lib/metric_fu/metrics/churn/report.html.erb +58 -0
  97. data/lib/metric_fu/metrics/flay/generator.rb +51 -0
  98. data/lib/metric_fu/metrics/flay/grapher.rb +37 -0
  99. data/lib/metric_fu/metrics/flay/hotspot.rb +52 -0
  100. data/lib/metric_fu/metrics/flay/metric.rb +28 -0
  101. data/lib/metric_fu/metrics/flay/report.html.erb +29 -0
  102. data/lib/metric_fu/metrics/flog/generator.rb +113 -0
  103. data/lib/metric_fu/metrics/flog/grapher.rb +77 -0
  104. data/lib/metric_fu/metrics/flog/hotspot.rb +46 -0
  105. data/lib/metric_fu/metrics/flog/metric.rb +29 -0
  106. data/lib/metric_fu/metrics/flog/report.html.erb +50 -0
  107. data/lib/metric_fu/metrics/hotspots/analysis/analyzed_problems.rb +34 -0
  108. data/lib/metric_fu/metrics/hotspots/analysis/analyzer_tables.rb +114 -0
  109. data/lib/metric_fu/metrics/hotspots/analysis/grouping.rb +23 -0
  110. data/lib/metric_fu/metrics/hotspots/analysis/groupings.rb +12 -0
  111. data/lib/metric_fu/metrics/hotspots/analysis/problems.rb +20 -0
  112. data/lib/metric_fu/metrics/hotspots/analysis/ranked_problem_location.rb +70 -0
  113. data/lib/metric_fu/metrics/hotspots/analysis/ranking.rb +29 -0
  114. data/lib/metric_fu/metrics/hotspots/analysis/rankings.rb +91 -0
  115. data/lib/metric_fu/metrics/hotspots/analysis/record.rb +32 -0
  116. data/lib/metric_fu/metrics/hotspots/analysis/scoring_strategies.rb +24 -0
  117. data/lib/metric_fu/metrics/hotspots/analysis/table.rb +67 -0
  118. data/lib/metric_fu/metrics/hotspots/generator.rb +40 -0
  119. data/lib/metric_fu/metrics/hotspots/hotspot.rb +87 -0
  120. data/lib/metric_fu/metrics/hotspots/hotspot_analyzer.rb +61 -0
  121. data/lib/metric_fu/metrics/hotspots/metric.rb +20 -0
  122. data/lib/metric_fu/metrics/hotspots/report.html.erb +60 -0
  123. data/lib/metric_fu/metrics/rails_best_practices/generator.rb +47 -0
  124. data/lib/metric_fu/metrics/rails_best_practices/grapher.rb +38 -0
  125. data/lib/metric_fu/metrics/rails_best_practices/metric.rb +31 -0
  126. data/lib/metric_fu/metrics/rails_best_practices/report.html.erb +22 -0
  127. data/lib/metric_fu/metrics/rcov/external_client.rb +22 -0
  128. data/lib/metric_fu/metrics/rcov/generator.rb +75 -0
  129. data/lib/metric_fu/metrics/rcov/grapher.rb +37 -0
  130. data/lib/metric_fu/metrics/rcov/hotspot.rb +46 -0
  131. data/lib/metric_fu/metrics/rcov/metric.rb +61 -0
  132. data/lib/metric_fu/metrics/rcov/rcov_format_coverage.rb +149 -0
  133. data/lib/metric_fu/metrics/rcov/rcov_line.rb +48 -0
  134. data/lib/metric_fu/metrics/rcov/report.html.erb +40 -0
  135. data/lib/metric_fu/metrics/rcov/simplecov_formatter.rb +74 -0
  136. data/lib/metric_fu/metrics/reek/generator.rb +94 -0
  137. data/lib/metric_fu/metrics/reek/grapher.rb +55 -0
  138. data/lib/metric_fu/metrics/reek/hotspot.rb +95 -0
  139. data/lib/metric_fu/metrics/reek/metric.rb +26 -0
  140. data/lib/metric_fu/metrics/reek/report.html.erb +35 -0
  141. data/lib/metric_fu/metrics/roodi/generator.rb +40 -0
  142. data/lib/metric_fu/metrics/roodi/grapher.rb +37 -0
  143. data/lib/metric_fu/metrics/roodi/hotspot.rb +39 -0
  144. data/lib/metric_fu/metrics/roodi/metric.rb +24 -0
  145. data/lib/metric_fu/metrics/roodi/report.html.erb +22 -0
  146. data/lib/metric_fu/metrics/saikuro/generator.rb +145 -0
  147. data/lib/metric_fu/metrics/saikuro/hotspot.rb +51 -0
  148. data/lib/metric_fu/metrics/saikuro/metric.rb +31 -0
  149. data/lib/metric_fu/metrics/saikuro/parsing_element.rb +37 -0
  150. data/lib/metric_fu/metrics/saikuro/report.html.erb +71 -0
  151. data/lib/metric_fu/metrics/saikuro/scratch_file.rb +108 -0
  152. data/lib/metric_fu/metrics/stats/generator.rb +82 -0
  153. data/lib/metric_fu/metrics/stats/grapher.rb +40 -0
  154. data/lib/metric_fu/metrics/stats/hotspot.rb +35 -0
  155. data/lib/metric_fu/metrics/stats/metric.rb +28 -0
  156. data/lib/metric_fu/metrics/stats/report.html.erb +44 -0
  157. data/lib/metric_fu/reporter.rb +37 -0
  158. data/lib/metric_fu/reporting/graphs/graph.rb +69 -0
  159. data/lib/metric_fu/reporting/graphs/grapher.rb +66 -0
  160. data/lib/metric_fu/reporting/result.rb +59 -0
  161. data/lib/metric_fu/run.rb +82 -0
  162. data/lib/metric_fu/tasks/metric_fu.rake +54 -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 +10 -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 +37 -0
  183. data/lib/metric_fu/templates/metrics_template.rb +80 -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 +244 -0
  187. data/lib/metric_fu/utility.rb +79 -0
  188. data/lib/metric_fu/version.rb +9 -0
  189. data/metric_fu.gemspec +71 -0
  190. data/spec/capture_warnings.rb +55 -0
  191. data/spec/cli/helper_spec.rb +165 -0
  192. data/spec/dummy/.gitignore +1 -0
  193. data/spec/dummy/.gitkeep +0 -0
  194. data/spec/dummy/lib/.gitkeep +0 -0
  195. data/spec/dummy/lib/bad_encoding.rb +6 -0
  196. data/spec/dummy/spec/.gitkeep +0 -0
  197. data/spec/fixtures/20090630.yml +7922 -0
  198. data/spec/fixtures/coverage-153.rb +11 -0
  199. data/spec/fixtures/coverage.rb +13 -0
  200. data/spec/fixtures/exit0.sh +3 -0
  201. data/spec/fixtures/exit1.sh +3 -0
  202. data/spec/fixtures/hotspots/flog.yml +86 -0
  203. data/spec/fixtures/hotspots/generator.yml +47 -0
  204. data/spec/fixtures/hotspots/generator_analysis.yml +53 -0
  205. data/spec/fixtures/hotspots/reek.yml +14 -0
  206. data/spec/fixtures/hotspots/roodi.yml +13 -0
  207. data/spec/fixtures/hotspots/saikuro.yml +27 -0
  208. data/spec/fixtures/hotspots/several_metrics.yml +47 -0
  209. data/spec/fixtures/hotspots/stats.yml +4 -0
  210. data/spec/fixtures/hotspots/three_metrics_on_same_file.yml +36 -0
  211. data/spec/fixtures/line_numbers/foo.rb +33 -0
  212. data/spec/fixtures/line_numbers/module.rb +11 -0
  213. data/spec/fixtures/line_numbers/module_surrounds_class.rb +15 -0
  214. data/spec/fixtures/line_numbers/two_classes.rb +11 -0
  215. data/spec/fixtures/metric_missing.yml +1 -0
  216. data/spec/fixtures/rcov_output.txt +135 -0
  217. data/spec/fixtures/saikuro/app/controllers/sessions_controller.rb_cyclo.html +10 -0
  218. data/spec/fixtures/saikuro/app/controllers/users_controller.rb_cyclo.html +16 -0
  219. data/spec/fixtures/saikuro/index_cyclo.html +155 -0
  220. data/spec/fixtures/saikuro_sfiles/thing.rb_cyclo.html +11 -0
  221. data/spec/metric_fu/calculate_spec.rb +21 -0
  222. data/spec/metric_fu/configuration_spec.rb +90 -0
  223. data/spec/metric_fu/data_structures/line_numbers_spec.rb +63 -0
  224. data/spec/metric_fu/data_structures/location_spec.rb +110 -0
  225. data/spec/metric_fu/formatter/configuration_spec.rb +44 -0
  226. data/spec/metric_fu/formatter/html_spec.rb +138 -0
  227. data/spec/metric_fu/formatter/yaml_spec.rb +61 -0
  228. data/spec/metric_fu/formatter_spec.rb +49 -0
  229. data/spec/metric_fu/gem_version_spec.rb +12 -0
  230. data/spec/metric_fu/generator_spec.rb +130 -0
  231. data/spec/metric_fu/loader_spec.rb +13 -0
  232. data/spec/metric_fu/metric_spec.rb +46 -0
  233. data/spec/metric_fu/metrics/cane/configuration_spec.rb +22 -0
  234. data/spec/metric_fu/metrics/cane/generator_spec.rb +184 -0
  235. data/spec/metric_fu/metrics/churn/configuration_spec.rb +13 -0
  236. data/spec/metric_fu/metrics/churn/generator_spec.rb +64 -0
  237. data/spec/metric_fu/metrics/flay/configuration_spec.rb +13 -0
  238. data/spec/metric_fu/metrics/flay/generator_spec.rb +105 -0
  239. data/spec/metric_fu/metrics/flay/grapher_spec.rb +57 -0
  240. data/spec/metric_fu/metrics/flog/configuration_spec.rb +18 -0
  241. data/spec/metric_fu/metrics/flog/generator_spec.rb +77 -0
  242. data/spec/metric_fu/metrics/flog/grapher_spec.rb +107 -0
  243. data/spec/metric_fu/metrics/hotspots/analysis/analyzed_problems_spec.rb +104 -0
  244. data/spec/metric_fu/metrics/hotspots/analysis/analyzer_tables_spec.rb +71 -0
  245. data/spec/metric_fu/metrics/hotspots/analysis/ranking_spec.rb +30 -0
  246. data/spec/metric_fu/metrics/hotspots/analysis/rankings_spec.rb +97 -0
  247. data/spec/metric_fu/metrics/hotspots/analysis/table_spec.rb +6 -0
  248. data/spec/metric_fu/metrics/hotspots/generator_spec.rb +46 -0
  249. data/spec/metric_fu/metrics/hotspots/hotspot_analyzer_spec.rb +10 -0
  250. data/spec/metric_fu/metrics/hotspots/hotspot_spec.rb +16 -0
  251. data/spec/metric_fu/metrics/rails_best_practices/configuration_spec.rb +55 -0
  252. data/spec/metric_fu/metrics/rails_best_practices/generator_spec.rb +33 -0
  253. data/spec/metric_fu/metrics/rails_best_practices/grapher_spec.rb +62 -0
  254. data/spec/metric_fu/metrics/rcov/configuration_spec.rb +28 -0
  255. data/spec/metric_fu/metrics/rcov/generator_spec.rb +22 -0
  256. data/spec/metric_fu/metrics/rcov/grapher_spec.rb +57 -0
  257. data/spec/metric_fu/metrics/rcov/hotspot_spec.rb +20 -0
  258. data/spec/metric_fu/metrics/rcov/rcov_line_spec.rb +89 -0
  259. data/spec/metric_fu/metrics/rcov/simplecov_formatter_spec.rb +67 -0
  260. data/spec/metric_fu/metrics/reek/configuration_spec.rb +13 -0
  261. data/spec/metric_fu/metrics/reek/generator_spec.rb +203 -0
  262. data/spec/metric_fu/metrics/reek/grapher_spec.rb +66 -0
  263. data/spec/metric_fu/metrics/roodi/configuration_spec.rb +14 -0
  264. data/spec/metric_fu/metrics/roodi/generator_spec.rb +82 -0
  265. data/spec/metric_fu/metrics/roodi/grapher_spec.rb +57 -0
  266. data/spec/metric_fu/metrics/saikuro/configuration_spec.rb +25 -0
  267. data/spec/metric_fu/metrics/saikuro/generator_spec.rb +71 -0
  268. data/spec/metric_fu/metrics/stats/generator_spec.rb +96 -0
  269. data/spec/metric_fu/metrics/stats/grapher_spec.rb +69 -0
  270. data/spec/metric_fu/reporter_spec.rb +41 -0
  271. data/spec/metric_fu/reporting/graphs/graph_spec.rb +44 -0
  272. data/spec/metric_fu/reporting/graphs/grapher_spec.rb +24 -0
  273. data/spec/metric_fu/reporting/result_spec.rb +50 -0
  274. data/spec/metric_fu/run_spec.rb +197 -0
  275. data/spec/metric_fu/templates/configuration_spec.rb +51 -0
  276. data/spec/metric_fu/templates/metrics_template_spec.rb +11 -0
  277. data/spec/metric_fu/templates/report_spec.rb +15 -0
  278. data/spec/metric_fu/templates/template_spec.rb +233 -0
  279. data/spec/metric_fu/utility_spec.rb +12 -0
  280. data/spec/metric_fu_spec.rb +52 -0
  281. data/spec/quality_spec.rb +114 -0
  282. data/spec/shared/configured.rb +45 -0
  283. data/spec/shared/test_coverage.rb +95 -0
  284. data/spec/spec_helper.rb +46 -0
  285. data/spec/support/.metrics +4 -0
  286. data/spec/support/deferred_garbaged_collection.rb +33 -0
  287. data/spec/support/helper_methods.rb +32 -0
  288. data/spec/support/matcher_create_file.rb +37 -0
  289. data/spec/support/matcher_create_files.rb +43 -0
  290. data/spec/support/samples/reek/alfa.rb +1 -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 +735 -0
@@ -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
@@ -0,0 +1,46 @@
1
+ class MetricFu::FlogHotspot < MetricFu::Hotspot
2
+ COLUMNS = %w{score}
3
+
4
+ def columns
5
+ COLUMNS
6
+ end
7
+
8
+ def name
9
+ :flog
10
+ end
11
+
12
+ def map_strategy
13
+ :score
14
+ end
15
+
16
+ def reduce_strategy
17
+ :average
18
+ end
19
+
20
+ def score_strategy
21
+ :identity
22
+ end
23
+
24
+ def generate_records(data, table)
25
+ return if data == nil
26
+ Array(data[:method_containers]).each do |method_container|
27
+ Array(method_container[:methods]).each do |entry|
28
+ file_path = entry[1][:path].sub(%r{^/}, "") if entry[1][:path]
29
+ location = MetricFu::Location.for(entry.first)
30
+ table << {
31
+ "metric" => name,
32
+ "score" => entry[1][:score],
33
+ "file_path" => file_path,
34
+ "class_name" => location.class_name,
35
+ "method_name" => location.method_name
36
+ }
37
+ end
38
+ end
39
+ end
40
+
41
+ def present_group(group)
42
+ occurences = group.size
43
+ complexity = get_mean(group.column("score"))
44
+ "#{'average ' if occurences > 1}complexity is %.1f" % complexity
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ module MetricFu
2
+ class MetricFlog < Metric
3
+ def name
4
+ :flog
5
+ end
6
+
7
+ def default_run_options
8
+ { dirs_to_flog: MetricFu::Io::FileSystem.directory("code_dirs"), continue: true, all: true, quiet: true }
9
+ end
10
+
11
+ def has_graph?
12
+ true
13
+ end
14
+
15
+ def enable
16
+ if MetricFu.configuration.mri?
17
+ super
18
+ else
19
+ MetricFu.logger.debug("Flog is only available in MRI due to flog tasks")
20
+ end
21
+ end
22
+
23
+ def activate
24
+ activate_library "flog"
25
+ activate_library "flog_cli"
26
+ super
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,50 @@
1
+ <h3>Flog Results</h3>
2
+ <p><a href='http://ruby.sadi.st/Flog.html'>Flog</a> measures code complexity.</p>
3
+
4
+ <%= render_partial 'graph', {:graph_name => 'flog'} %>
5
+
6
+ <h2>Total Flog score for all methods: <%= round_to_tenths @flog[:total]%></h2>
7
+ <h2>Average Flog score for all methods: <%= round_to_tenths @flog[:average]%></h2>
8
+
9
+ <table>
10
+ <tr>
11
+ <th>File</th>
12
+ <th>Total score</th>
13
+ <th>Methods</th>
14
+ <th>Average score</th>
15
+ <th>Highest score</th>
16
+ </tr>
17
+ <% @flog[:method_containers].each do |method_container| %>
18
+ <tr>
19
+ <td><a href="#<%= method_container[:path].gsub(/[^a-z]+/, '_') %>"><%= method_container[:path] %></a></td>
20
+ <td><%= round_to_tenths method_container[:total_score] %></td>
21
+ <td><%= method_container[:methods].size %></td>
22
+ <td><%= round_to_tenths method_container[:average_score] %></td>
23
+ <td><%= round_to_tenths method_container[:highest_score] %></td>
24
+ </tr>
25
+ <% end %>
26
+ </table>
27
+
28
+ <% @flog[:method_containers].each do |method_container| %>
29
+ <h2 id="<%= method_container[:path].gsub(/[^a-z]+/, '_') %>"><%= link_to_filename(method_container[:path]) %></h2>
30
+
31
+ <% method_container[:methods].each do |full_method_name, method_info| %>
32
+ <% path, line = method_info[:path].split(":") if method_info[:path] %>
33
+ <p><%= link_to_filename(path, line, full_method_name) %></p>
34
+ <p>Total Score: <%= round_to_tenths method_info[:score]%></p>
35
+ <table>
36
+ <tr>
37
+ <th>Score</th>
38
+ <th>Operator</th>
39
+ </tr>
40
+ <% method_info[:operators].each do |operator, score| %>
41
+ <tr>
42
+ <td><%= round_to_tenths score %></td>
43
+ <td><%= operator %></td>
44
+ </tr>
45
+ <% end %>
46
+ </table>
47
+ <% end %>
48
+ <% end %>
49
+
50
+ <%= render_partial 'report_footer' %>
@@ -0,0 +1,34 @@
1
+ module MetricFu
2
+ class HotspotAnalyzedProblems
3
+ MetricFu.metrics_require { "hotspots/analysis/ranked_problem_location" }
4
+
5
+ def initialize(hotspot_rankings, analyzer_tables)
6
+ @hotspot_rankings = hotspot_rankings
7
+ @analyzer_tables = analyzer_tables
8
+ end
9
+
10
+ def worst_items
11
+ worst_items = {}
12
+ worst_items[:files] = worst(@hotspot_rankings.worst_files, :file)
13
+ worst_items[:classes] = worst(@hotspot_rankings.worst_classes, :class)
14
+ worst_items[:methods] = worst(@hotspot_rankings.worst_methods, :method)
15
+ worst_items
16
+ end
17
+
18
+ private
19
+
20
+ # @param rankings [Array<MetricFu::HotspotRankings>]
21
+ # @param granularity [Symbol] one of :class, :method, :file
22
+ def worst(rankings, granularity)
23
+ rankings.map do |ranked_item_name|
24
+ sub_table = get_sub_table(granularity, ranked_item_name)
25
+ MetricFu::HotspotRankedProblemLocation.new(sub_table, granularity)
26
+ end
27
+ end
28
+
29
+ def get_sub_table(granularity, ranked_item_name)
30
+ tables = @analyzer_tables.tables_for(granularity)
31
+ tables[ranked_item_name]
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,114 @@
1
+ module MetricFu
2
+ class AnalyzerTables
3
+ %w(table).each do |path|
4
+ MetricFu.metrics_require { "hotspots/analysis/#{path}" }
5
+ end
6
+
7
+ def initialize(analyzer_columns)
8
+ @columns = analyzer_columns
9
+ end
10
+
11
+ def generate_records
12
+ build_lookups!
13
+ process_rows!
14
+ end
15
+
16
+ def tool_tables
17
+ @tool_tables ||= make_table_hash(@columns)
18
+ end
19
+
20
+ def table
21
+ @table ||= make_table(@columns)
22
+ end
23
+
24
+ def tables_for(item)
25
+ {
26
+ class: @class_tables,
27
+ method: @method_tables,
28
+ file: @file_tables,
29
+ tool: @tool_tables
30
+ }.fetch(item) do
31
+ raise ArgumentError, "Item must be :class, :method, or :file, but was #{item}"
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def make_table(columns)
38
+ MetricFu::Table.new(column_names: columns)
39
+ end
40
+
41
+ def make_table_hash(columns)
42
+ Hash.new { |hash, key|
43
+ hash[key] = make_table(columns)
44
+ }
45
+ end
46
+
47
+ # COLLECT AND PROCESS RAW HOTSPOT METRICS
48
+ def build_lookups!
49
+ @class_and_method_to_file ||= {}
50
+ # Build a mapping from [class,method] => filename
51
+ # (and make sure the mapping is unique)
52
+ table.each do |row|
53
+ # We know that Saikuro provides the wrong data
54
+ # TODO inject Saikuro reference
55
+ next if row["metric"] == :saikuro
56
+ key = [row["class_name"], row["method_name"]]
57
+ file_path = row["file_path"]
58
+ @class_and_method_to_file[key] ||= file_path
59
+ end
60
+ end
61
+
62
+ # COLLECT AND PROCESS RAW HOTSPOT METRICS
63
+ def process_rows!
64
+ # Correct incorrect rows in the table
65
+ table.each do |row|
66
+ row_metric = row["metric"] # perf optimization
67
+ # TODO inject Saikuro reference
68
+ if row_metric == :saikuro
69
+ fix_row_file_path!(row)
70
+ end
71
+ tool_tables[row_metric] << row
72
+ file_tables[row["file_path"]] << row
73
+ class_tables[row["class_name"]] << row
74
+ method_tables[row["method_name"]] << row
75
+ end
76
+ end
77
+
78
+ # COLLECT AND PROCESS RAW HOTSPOT METRICS
79
+ def fix_row_file_path!(row)
80
+ # We know that Saikuro rows are broken
81
+ # next unless row['metric'] == :saikuro
82
+ key = [row["class_name"], row["method_name"]]
83
+ current_file_path = row["file_path"].to_s
84
+ correct_file_path = @class_and_method_to_file[key]
85
+ if !correct_file_path.nil? && correct_file_path.include?(current_file_path)
86
+ row["file_path"] = correct_file_path
87
+ else
88
+ # There wasn't an exact match, so we can do a substring match
89
+ matching_file_path = file_paths.detect {|file_path|
90
+ !file_path.nil? && file_path.include?(current_file_path)
91
+ }
92
+ if matching_file_path
93
+ row["file_path"] = matching_file_path
94
+ end
95
+ end
96
+ end
97
+
98
+ def file_paths
99
+ @file_paths ||= @table.column("file_path").uniq
100
+ end
101
+
102
+ def file_tables
103
+ @file_tables ||= make_table_hash(@columns)
104
+ end
105
+
106
+ def class_tables
107
+ @class_tables ||= make_table_hash(@columns)
108
+ end
109
+
110
+ def method_tables
111
+ @method_tables ||= make_table_hash(@columns)
112
+ end
113
+ end
114
+ end