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,23 @@
1
+ %w(table).each do |path|
2
+ MetricFu.metrics_require { "hotspots/analysis/#{path}" }
3
+ end
4
+ module MetricFu
5
+ class Grouping
6
+ def initialize(table, opts)
7
+ column_name = opts.fetch(:by)
8
+ hash = {}
9
+ if column_name.to_sym == :metric # special optimized case
10
+ hash = table.group_by_metric
11
+ else
12
+ raise "Unexpected column_name #{column_name}"
13
+ end
14
+ @arr = hash.to_a
15
+ end
16
+
17
+ def each
18
+ @arr.each do |value, rows|
19
+ yield value, rows
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ MetricFu.metrics_require { "hotspots/analysis/grouping" }
2
+ module MetricFu
3
+ class HotspotGroupings
4
+ def initialize(table, opts)
5
+ @table, @opts = table, opts
6
+ end
7
+
8
+ def get_grouping
9
+ MetricFu::Grouping.new(@table, @opts)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ MetricFu.metrics_require { "hotspots/analysis/groupings" }
2
+ module MetricFu
3
+ class HotspotProblems
4
+ def initialize(sub_table)
5
+ @grouping = group_by(sub_table, "metric")
6
+ end
7
+
8
+ def problems
9
+ problems = {}
10
+ @grouping.each do |metric, table|
11
+ problems[metric] = MetricFu::Hotspot.analyzer_for_metric(metric).present_group(table)
12
+ end
13
+ problems
14
+ end
15
+
16
+ def group_by(sub_table, by = "metric")
17
+ MetricFu::HotspotGroupings.new(sub_table, by: by).get_grouping
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,70 @@
1
+ MetricFu.lib_require { "errors/analysis_error" }
2
+ MetricFu.metrics_require { "hotspots/analysis/problems" }
3
+ module MetricFu
4
+ class HotspotRankedProblemLocation
5
+ MetricFu.data_structures_require { "location" }
6
+ attr_reader :sub_table, :granularity
7
+ def initialize(sub_table, granularity)
8
+ @sub_table = sub_table
9
+ @granularity = granularity
10
+ end
11
+
12
+ def to_hash
13
+ {
14
+ "location" => location.to_hash,
15
+ "details" => MetricFu::Utility.stringify_keys(problems),
16
+ }
17
+ end
18
+
19
+ # @todo redo as item,value, options = {}
20
+ # Note that the other option for 'details' is :detailed (this isn't
21
+ # at all clear from this method itself
22
+ def problems
23
+ @problems ||= MetricFu::HotspotProblems.new(sub_table).problems
24
+ end
25
+
26
+ def location
27
+ @location ||= case granularity
28
+ when :class then class_location
29
+ when :method then method_location
30
+ when :file then file_location
31
+ else raise ArgumentError, "Item must be :class, :method, or :file"
32
+ end
33
+ end
34
+
35
+ def file_path
36
+ first_row.file_path
37
+ end
38
+
39
+ def class_name
40
+ first_row.class_name
41
+ end
42
+
43
+ def method_name
44
+ first_row.method_name
45
+ end
46
+
47
+ def file_location
48
+ MetricFu::Location.get(file_path, nil, nil)
49
+ end
50
+
51
+ def method_location
52
+ MetricFu::Location.get(file_path, class_name, method_name)
53
+ end
54
+
55
+ def class_location
56
+ MetricFu::Location.get(file_path, class_name, nil)
57
+ end
58
+
59
+ def first_row
60
+ assert_sub_table_has_data
61
+ @first_row ||= sub_table[0]
62
+ end
63
+
64
+ def assert_sub_table_has_data
65
+ if (sub_table.length == 0)
66
+ raise MetricFu::AnalysisError, "The #{item} '#{value}' does not have any rows in the analysis table"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,29 @@
1
+ require "forwardable"
2
+ module MetricFu
3
+ class Ranking
4
+ extend Forwardable
5
+
6
+ def initialize
7
+ @items_to_score = {}
8
+ end
9
+
10
+ def top
11
+ sorted_items
12
+ end
13
+
14
+ def percentile(item)
15
+ index = sorted_items.index(item)
16
+ worse_item_count = (length - (index + 1))
17
+ worse_item_count.to_f / length
18
+ end
19
+
20
+ def_delegator :@items_to_score, :has_key?, :scored?
21
+ def_delegators :@items_to_score, :[], :[]=, :length, :each, :delete, :fetch
22
+
23
+ private
24
+
25
+ def sorted_items
26
+ @sorted_items ||= @items_to_score.sort_by { |_item, score| -score }.map { |item, _score| item }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,91 @@
1
+ MetricFu.metrics_require do
2
+ [
3
+ "hotspots/analysis/ranking"
4
+ ]
5
+ end
6
+ module MetricFu
7
+ class HotspotRankings
8
+ def initialize(tool_tables)
9
+ @tool_tables = tool_tables
10
+ @file_ranking = MetricFu::Ranking.new
11
+ @class_ranking = MetricFu::Ranking.new
12
+ @method_ranking = MetricFu::Ranking.new
13
+ end
14
+
15
+ def calculate_scores(tool_analyzers, granularities)
16
+ tool_analyzers.each do |analyzer|
17
+ calculate_scores_by_granularities(analyzer, granularities)
18
+ end
19
+ end
20
+
21
+ def worst_methods
22
+ @method_ranking.delete(nil)
23
+ @method_ranking.top
24
+ end
25
+
26
+ def worst_classes
27
+ @class_ranking.delete(nil)
28
+ @class_ranking.top
29
+ end
30
+
31
+ def worst_files
32
+ @file_ranking.delete(nil)
33
+ @file_ranking.top
34
+ end
35
+
36
+ private
37
+
38
+ def calculate_scores_by_granularities(analyzer, granularities)
39
+ granularities.each do |granularity|
40
+ calculate_score_for_granularity(analyzer, granularity)
41
+ end
42
+ end
43
+
44
+ def calculate_score_for_granularity(analyzer, granularity)
45
+ metric_ranking = calculate_metric_scores(granularity, analyzer)
46
+
47
+ add_to_master_ranking(
48
+ ranking(granularity),
49
+ metric_ranking,
50
+ analyzer
51
+ )
52
+ end
53
+
54
+ # CALCULATES METRIC HOTSPOT SCORES / RANKINGS PER map/reduce in HOTSPOT subclasses
55
+ def calculate_metric_scores(granularity, analyzer)
56
+ metric_ranking = MetricFu::Ranking.new
57
+ metric_violations = @tool_tables[analyzer.name]
58
+ metric_violations.each do |row|
59
+ location = row[granularity]
60
+ metric_ranking[location] ||= []
61
+ metric_ranking[location] << analyzer.map(row)
62
+ end
63
+
64
+ metric_ranking.each do |item, scores|
65
+ metric_ranking[item] = analyzer.reduce(scores)
66
+ end
67
+
68
+ metric_ranking
69
+ end
70
+
71
+ def ranking(column_name)
72
+ case column_name
73
+ when "file_path"
74
+ @file_ranking
75
+ when "class_name"
76
+ @class_ranking
77
+ when "method_name"
78
+ @method_ranking
79
+ else
80
+ raise ArgumentError, "Invalid column name #{column_name}"
81
+ end
82
+ end
83
+
84
+ def add_to_master_ranking(master_ranking, metric_ranking, analyzer)
85
+ metric_ranking.each do |item, _|
86
+ master_ranking[item] ||= 0
87
+ master_ranking[item] += analyzer.score(metric_ranking, item) # scaling? Do we just add in the raw score?
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,32 @@
1
+ module MetricFu
2
+ class Record
3
+ attr_reader :data
4
+
5
+ def initialize(data, _columns)
6
+ @data = data
7
+ end
8
+
9
+ def method_missing(name, *args, &block)
10
+ key = name.to_s
11
+ if key == "fetch"
12
+ @data.send(name, *args, &block)
13
+ elsif @data.has_key?(key)
14
+ @data[key]
15
+ else
16
+ super(name, *args, &block)
17
+ end
18
+ end
19
+
20
+ def []=(key, value)
21
+ @data[key] = value
22
+ end
23
+
24
+ def [](key)
25
+ @data[key]
26
+ end
27
+
28
+ def has_key?(key)
29
+ @data.has_key?(key)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,24 @@
1
+ module MetricFu
2
+ module HotspotScoringStrategies
3
+ module_function
4
+
5
+ # per project score percentile
6
+ def percentile(ranking, item)
7
+ ranking.percentile(item)
8
+ end
9
+
10
+ # Use the score you got
11
+ # (ex flog score of 20 is not bad even if it is the top one in project)
12
+ def identity(ranking, item)
13
+ ranking.fetch(item)
14
+ end
15
+
16
+ def sum(scores)
17
+ scores.inject(&:+)
18
+ end
19
+
20
+ def average(scores)
21
+ sum(scores).to_f / scores.size.to_f
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,67 @@
1
+ %w(record).each do |path|
2
+ MetricFu.metrics_require { "hotspots/analysis/#{path}" }
3
+ end
4
+
5
+ module MetricFu
6
+ class Table
7
+ include Enumerable
8
+
9
+ def initialize(opts = {})
10
+ @rows = []
11
+ @columns = opts.fetch(:column_names)
12
+
13
+ @make_index = opts.fetch(:make_index) { true }
14
+ @metric_index = {}
15
+ end
16
+
17
+ def <<(row)
18
+ record = nil
19
+ if row.is_a?(MetricFu::Record)
20
+ record = row
21
+ else
22
+ record = MetricFu::Record.new(row, @columns)
23
+ end
24
+ @rows << record
25
+ updated_key_index(record) if @make_index
26
+ end
27
+
28
+ def each
29
+ @rows.each do |row|
30
+ yield row
31
+ end
32
+ end
33
+
34
+ def size
35
+ length
36
+ end
37
+
38
+ def length
39
+ @rows.length
40
+ end
41
+
42
+ def [](index)
43
+ @rows[index]
44
+ end
45
+
46
+ def column(column_name)
47
+ arr = []
48
+ @rows.each do |row|
49
+ arr << row[column_name]
50
+ end
51
+ arr
52
+ end
53
+
54
+ def group_by_metric
55
+ @metric_index.to_a
56
+ end
57
+
58
+ private
59
+
60
+ def updated_key_index(record)
61
+ if record.has_key?("metric")
62
+ @metric_index[record.metric] ||= MetricFu::Table.new(column_names: @columns, make_index: false)
63
+ @metric_index[record.metric] << record
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,40 @@
1
+ MetricFu.metrics_require { "hotspots/hotspot_analyzer" }
2
+ module MetricFu
3
+ class HotspotsGenerator < Generator
4
+ def self.metric
5
+ :hotspots
6
+ end
7
+
8
+ def initialize(options = {})
9
+ MetricFu::Metric.enabled_metrics.each do |metric|
10
+ require_hotspot(metric.name)
11
+ end
12
+ super
13
+ end
14
+
15
+ def emit
16
+ # no-op
17
+ end
18
+
19
+ def analyze
20
+ analyzer = MetricFu::HotspotAnalyzer.new(MetricFu.result.result_hash)
21
+ @hotspots = analyzer.hotspots
22
+ end
23
+
24
+ def to_h
25
+ result = { hotspots: {} }
26
+ @hotspots.each do |granularity, hotspots|
27
+ result[:hotspots][granularity.to_s] = hotspots.map(&:to_hash)
28
+ end
29
+ result
30
+ end
31
+
32
+ private
33
+
34
+ def require_hotspot(metric_name)
35
+ require "metric_fu/metrics/#{metric_name}/hotspot"
36
+ rescue LoadError
37
+ mf_debug "*** No hotspot for #{metric_name}"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,87 @@
1
+ MetricFu.lib_require { "errors/analysis_error" }
2
+ MetricFu.metrics_require { "hotspots/analysis/scoring_strategies" }
3
+
4
+ module MetricFu
5
+ class Hotspot
6
+ def self.metric
7
+ name.split("::")[-1].split("Hotspot")[0].downcase.to_sym
8
+ end
9
+ @analyzers = {}
10
+ def self.analyzers
11
+ @analyzers.values
12
+ end
13
+ def self.analyzer_for_metric(metric)
14
+ @analyzers.fetch(metric.to_sym) do
15
+ message = "Unknown metric #{metric}. We only know #{@analyzers.keys.inspect}"
16
+ fail MetricFu::AnalysisError, message
17
+ end
18
+ end
19
+ def self.inherited(subclass)
20
+ mf_debug "Adding #{subclass} to #{@analyzers.inspect}"
21
+ @analyzers[subclass.metric] = subclass.new
22
+ end
23
+
24
+ def get_mean(collection)
25
+ MetricFu::HotspotScoringStrategies.average(collection)
26
+ end
27
+
28
+ def map(row)
29
+ mapping_strategies.fetch(map_strategy) { row.public_send(map_strategy) }
30
+ end
31
+
32
+ def mapping_strategies
33
+ {
34
+ present: 1,
35
+ absent: 0,
36
+ }
37
+ end
38
+
39
+ def map_strategy
40
+ not_implemented
41
+ end
42
+
43
+ def reduce(scores)
44
+ {
45
+ average: MetricFu::HotspotScoringStrategies.average(scores),
46
+ sum: MetricFu::HotspotScoringStrategies.sum(scores),
47
+ absent: 0,
48
+ }.fetch(reduce_strategy) do
49
+ fail "#{reduce_strategy} not a known reduce strategy"
50
+ end
51
+ end
52
+
53
+ def reduce_strategy
54
+ not_implemented
55
+ end
56
+
57
+ # @return [Integer]
58
+ def score(metric_ranking, item)
59
+ {
60
+ identity: MetricFu::HotspotScoringStrategies.identity(metric_ranking, item),
61
+ percentile: MetricFu::HotspotScoringStrategies.percentile(metric_ranking, item),
62
+ absent: 0,
63
+ }.fetch(score_strategy) { method(score_strategy).call(metric_ranking, item) }
64
+ end
65
+
66
+ def score_strategy
67
+ not_implemented
68
+ end
69
+
70
+ # Transforms the data param, if non-nil, into a hash with keys:
71
+ # 'metric', etc.
72
+ # and appends the hash to the table param
73
+ # Has no return value
74
+ def generate_records(_data, _table)
75
+ not_implemented
76
+ end
77
+
78
+ # @return [String] description result
79
+ def present_group(_group)
80
+ not_implemented
81
+ end
82
+
83
+ def not_implemented
84
+ raise "#{caller[0]} not implemented"
85
+ end
86
+ end
87
+ end