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
+ 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
@@ -0,0 +1,61 @@
1
+ require "yaml"
2
+ MetricFu.metrics_require do
3
+ [
4
+ "hotspots/hotspot",
5
+ "hotspots/analysis/analyzer_tables",
6
+ "hotspots/analysis/analyzed_problems",
7
+ "hotspots/analysis/rankings"
8
+ ]
9
+ end
10
+
11
+ module MetricFu
12
+ class HotspotAnalyzer
13
+ COMMON_COLUMNS = %w{metric}
14
+ GRANULARITIES = %w{file_path class_name method_name}
15
+
16
+ def tool_analyzers
17
+ MetricFu::Hotspot.analyzers
18
+ end
19
+
20
+ def initialize(result_hash)
21
+ # we can't depend on the result
22
+ # returning a parsed yaml file as a hash?
23
+ result_hash = YAML::load(result_hash) if result_hash.is_a?(String)
24
+ setup(result_hash)
25
+ end
26
+
27
+ def hotspots
28
+ analyzed_problems.worst_items
29
+ end
30
+
31
+ def analyzed_problems
32
+ @analyzed_problems = MetricFu::HotspotAnalyzedProblems.new(@rankings, @analyzer_tables)
33
+ end
34
+
35
+ private
36
+
37
+ # TODO clarify each of these steps in setup
38
+ # extract into its own method
39
+ # remove unnecessary constants,
40
+ # turn into methods
41
+ def setup(result_hash)
42
+ # TODO There is likely a clash that will happen between
43
+ # column names eventually. We should probably auto-prefix
44
+ # them (e.g. "roodi_problem")
45
+ analyzer_columns = COMMON_COLUMNS + GRANULARITIES + tool_analyzers.map(&:columns).flatten
46
+ # though the tool_analyzers aren't returned, they are processed in
47
+ # various places here, then by the analyzer tables
48
+ # then by the rankings
49
+ # to ultimately generate the hotspots
50
+ @analyzer_tables = MetricFu::AnalyzerTables.new(analyzer_columns)
51
+ tool_analyzers.each do |analyzer|
52
+ analyzer.generate_records(result_hash[analyzer.name], @analyzer_tables.table)
53
+ end
54
+ @analyzer_tables.generate_records
55
+ @rankings = MetricFu::HotspotRankings.new(@analyzer_tables.tool_tables)
56
+ @rankings.calculate_scores(tool_analyzers, GRANULARITIES)
57
+ # TODO does it not need to return something here?
58
+ analyzed_problems
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,20 @@
1
+ module MetricFu
2
+ class MetricHotspots < Metric
3
+ def name
4
+ :hotspots
5
+ end
6
+
7
+ # TODO remove explicit Churn dependency
8
+ def default_run_options
9
+ { start_date: "1 year ago", minimum_churn_count: 10 }
10
+ end
11
+
12
+ def has_graph?
13
+ false
14
+ end
15
+
16
+ def enable
17
+ super
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,60 @@
1
+ <h3>Hotspot Results</h3>
2
+ <p>Meta analysis of your metrics to find hotspots in your code.</p>
3
+ <br/>
4
+
5
+ <% if @hotspots.nil? || @hotspots.size.zero? %>
6
+ No Hotspots were found.
7
+ <% else %>
8
+
9
+ <% granularities = %w[files classes methods] %>
10
+ <table>
11
+ <tr valign="top">
12
+ <% granularities.each do |granularity| %>
13
+ <th width='33%'>
14
+ <%= granularity.to_s.capitalize %></th>
15
+ <% end %>
16
+ </tr>
17
+
18
+ <% hotspots = [] %>
19
+ <% granularities.each_index do |index| %>
20
+ <% granularity = granularities[index] %>
21
+ <% hotspots << @hotspots[granularity] %>
22
+ <% end %>
23
+
24
+ <% hotspots_length = 0 %>
25
+ <% columns = [0, 1, 2] %>
26
+ <% while (hotspots_length < hotspots[0].length || hotspots_length < hotspots[1].length || hotspots_length < hotspots[2].length) do %>
27
+ <tr valign="top">
28
+ <% columns.each do |column| %>
29
+ <% item = hotspots[column].length >= hotspots_length ? hotspots[column][hotspots_length] : nil %>
30
+ <% if item %>
31
+ <% location = item.fetch('location') %>
32
+ <% file, line = location.fetch('file_name'), location.fetch('line_number') %>
33
+ <td>
34
+ <b>
35
+ <%= display_location(location) %>
36
+ </b>
37
+ <% unless per_file_data[file].empty? %>
38
+ <small>&laquo;
39
+ <b><a href="<%= html_filename(file) %><%= (line.nil? ? '' : "#line#{line}") %>">annotate</a></b>
40
+ &raquo;</small>
41
+ <% end %>
42
+ <br/><br/>
43
+ <!-- TODO HOTSPOTS for metric fu nice metric_link method -->
44
+ <% item.fetch('details').each do |metric, info| %>
45
+ <%#= metric_link(@stat, metric, h(metric.to_s.capitalize)) + ": " + h(info)%><br/>
46
+ <%= "#{metric.to_s.capitalize}: #{info}" %><br/>
47
+ <% end %>
48
+ </td>
49
+ <% else %>
50
+ <td> &nbsp; </td>
51
+ <% end %>
52
+ <% end %>
53
+ <% hotspots_length += 1 %>
54
+ </tr>
55
+ <% end %>
56
+
57
+ </table>
58
+ <% end %>
59
+
60
+ <%= render_partial 'report_footer' %>
@@ -0,0 +1,47 @@
1
+ module MetricFu
2
+ class RailsBestPracticesGenerator < Generator
3
+ def self.metric
4
+ :rails_best_practices
5
+ end
6
+
7
+ def initialize(options = {})
8
+ super(MetricFu::Utility.stringify_keys(options))
9
+ end
10
+
11
+ def emit
12
+ mf_debug "** Rails Best Practices"
13
+ path = "."
14
+ analyzer = ::RailsBestPractices::Analyzer.new(path, options)
15
+ analyzer.analyze
16
+ @output = analyzer.errors
17
+ end
18
+
19
+ def analyze
20
+ @problems = @output.collect do |problem|
21
+ {
22
+ file: problem.short_filename,
23
+ line: problem.line_number,
24
+ problem: problem.message,
25
+ url: problem.url
26
+ }
27
+ end
28
+ total = ["Found #{@problems.count} errors."]
29
+ @rails_best_practices_results = { total: total, problems: @problems }
30
+ end
31
+
32
+ def to_h
33
+ { rails_best_practices: @rails_best_practices_results }
34
+ end
35
+
36
+ def per_file_info(out)
37
+ @rails_best_practices_results[:problems].each do |problem|
38
+ next if problem[:file] == "" || problem[:problem].nil?
39
+
40
+ lines = problem[:line].split(/\s*,\s*/)
41
+ lines.each do |line|
42
+ out[problem[:file]][line] << { type: :rails_best_practices, description: problem[:problem] }
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,38 @@
1
+ MetricFu.reporting_require { "graphs/grapher" }
2
+ module MetricFu
3
+ class RailsBestPracticesGrapher < Grapher
4
+ attr_accessor :rails_best_practices_count, :labels
5
+
6
+ def self.metric
7
+ :rails_best_practices
8
+ end
9
+
10
+ def initialize
11
+ super
12
+ @rails_best_practices_count = []
13
+ @labels = {}
14
+ end
15
+
16
+ def get_metrics(metrics, date)
17
+ if metrics && metrics[:rails_best_practices]
18
+ size = (metrics[:rails_best_practices][:problems] || []).size
19
+ @rails_best_practices_count.push(size)
20
+ @labels.update(@labels.size => date)
21
+ end
22
+ end
23
+
24
+ def title
25
+ "Rails Best Practices: design problems"
26
+ end
27
+
28
+ def data
29
+ [
30
+ ["rails_best_practices", @rails_best_practices_count.join(",")]
31
+ ]
32
+ end
33
+
34
+ def output_filename
35
+ "rails_best_practices.js"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ module MetricFu
2
+ class MetricRailsBestPractices < Metric
3
+ def name
4
+ :rails_best_practices
5
+ end
6
+
7
+ def default_run_options
8
+ {
9
+ silent: true,
10
+ exclude: []
11
+ }
12
+ end
13
+
14
+ def has_graph?
15
+ true
16
+ end
17
+
18
+ def enable
19
+ if MetricFu.configuration.supports_ripper?
20
+ super if MetricFu.configuration.rails?
21
+ else
22
+ MetricFu.logger.debug("Rails Best Practices is only available in MRI 1.9. It requires ripper")
23
+ end
24
+ end
25
+
26
+ def activate
27
+ activate_library("rails_best_practices")
28
+ super
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ <h3>Rails Best Practices Results</h3>
2
+
3
+ <p><a href="http://github.com/railsbp/rails_best_practices">rails_best_practices</a> is a code metric tool for rails projects.</p>
4
+
5
+ <%= render_partial 'graph', {:graph_name => 'rails_best_practices'} %>
6
+
7
+ <table>
8
+ <tr>
9
+ <th>File Path</th>
10
+ <th>Warning</th>
11
+ </tr>
12
+ <% count = 0 %>
13
+ <% @rails_best_practices[:problems].each do |problem| %>
14
+ <tr class='<%= cycle("light", "dark", count) %>'>
15
+ <td><%= link_to_filename(problem[:file], problem[:line]) %></td>
16
+ <td><a href =<%= problem[:url] %>><%= problem[:problem] %></a></td>
17
+ </tr>
18
+ <% count += 1 %>
19
+ <% end %>
20
+ </table>
21
+
22
+ <%= render_partial 'report_footer' %>
@@ -0,0 +1,22 @@
1
+ # Reads and writes external coverage files as BINARY
2
+ module MetricFu
3
+ class RCovTestCoverageClient
4
+ def initialize(coverage_file)
5
+ @file_path = Pathname(coverage_file)
6
+ @file_path.dirname.mkpath
7
+ end
8
+
9
+ def post_results(payload)
10
+ mf_log "Saving coverage payload to #{@file_path}"
11
+ dump(payload)
12
+ end
13
+
14
+ def load
15
+ File.binread(@file_path)
16
+ end
17
+
18
+ def dump(payload)
19
+ File.open(@file_path, "wb") { |file| file.write(payload) }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,75 @@
1
+ MetricFu.lib_require { "utility" }
2
+ MetricFu.lib_require { "calculate" }
3
+ MetricFu.data_structures_require { "line_numbers" }
4
+ require_relative "rcov_format_coverage"
5
+ require_relative "rcov_line"
6
+ require_relative "external_client"
7
+
8
+ module MetricFu
9
+ class RcovGenerator < MetricFu::Generator
10
+ def self.metric
11
+ :rcov
12
+ end
13
+
14
+ def emit
15
+ if run_rcov?
16
+ mf_debug "** Running the specs/tests in the [#{options[:environment]}] environment"
17
+ mf_debug "** #{command}"
18
+ `#{command}`
19
+ end
20
+ end
21
+
22
+ def command
23
+ @command ||= default_command
24
+ end
25
+
26
+ def command=(command)
27
+ @command = command
28
+ end
29
+
30
+ def reset_output_location
31
+ MetricFu::Utility.rm_rf(metric_directory, verbose: false)
32
+ MetricFu::Utility.mkdir_p(metric_directory)
33
+ end
34
+
35
+ def default_command
36
+ require "rake"
37
+ reset_output_location
38
+ test_files = FileList[*options[:test_files]].join(" ")
39
+ rcov_opts = options[:rcov_opts].join(" ")
40
+ %(RAILS_ENV=#{options[:environment]} rcov #{test_files} #{rcov_opts} >> #{default_output_file})
41
+ end
42
+
43
+ def analyze
44
+ rcov_text = load_output
45
+ formatter = MetricFu::RCovFormatCoverage.new(rcov_text)
46
+ @rcov = formatter.to_h
47
+ end
48
+
49
+ def to_h
50
+ {
51
+ rcov: @rcov
52
+ }
53
+ end
54
+
55
+ private
56
+
57
+ # We never run rcov anymore
58
+ def run_rcov?
59
+ false
60
+ end
61
+
62
+ def load_output
63
+ MetricFu::RCovTestCoverageClient.new(output_file).load
64
+ end
65
+
66
+ def output_file
67
+ options.fetch(:external)
68
+ end
69
+
70
+ # Only used if run_rcov? is true
71
+ def default_output_file
72
+ output_file || File.join(metric_directory, "rcov.txt")
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,37 @@
1
+ MetricFu.reporting_require { "graphs/grapher" }
2
+ module MetricFu
3
+ class RcovGrapher < Grapher
4
+ attr_accessor :rcov_percent, :labels
5
+
6
+ def self.metric
7
+ :rcov
8
+ end
9
+
10
+ def initialize
11
+ super
12
+ self.rcov_percent = []
13
+ self.labels = {}
14
+ end
15
+
16
+ def get_metrics(metrics, date)
17
+ if metrics && metrics[:rcov]
18
+ rcov_percent.push(metrics[:rcov][:global_percent_run])
19
+ labels.update(labels.size => date)
20
+ end
21
+ end
22
+
23
+ def title
24
+ "Rcov: code coverage"
25
+ end
26
+
27
+ def data
28
+ [
29
+ ["rcov", @rcov_percent.join(",")]
30
+ ]
31
+ end
32
+
33
+ def output_filename
34
+ "rcov.js"
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,46 @@
1
+ class MetricFu::RcovHotspot < MetricFu::Hotspot
2
+ COLUMNS = %w{percentage_uncovered}
3
+
4
+ def columns
5
+ COLUMNS
6
+ end
7
+
8
+ def name
9
+ :rcov
10
+ end
11
+
12
+ def map_strategy
13
+ :percentage_uncovered
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
+ data.each do |file_name, info|
27
+ next if (file_name == :global_percent_run) || (info[:methods].nil?)
28
+ info[:methods].each do |method_name, percentage_uncovered|
29
+ location = MetricFu::Location.for(method_name)
30
+ table << {
31
+ "metric" => :rcov,
32
+ "file_path" => file_name,
33
+ "class_name" => location.class_name,
34
+ "method_name" => location.method_name,
35
+ "percentage_uncovered" => percentage_uncovered
36
+ }
37
+ end
38
+ end
39
+ end
40
+
41
+ def present_group(group)
42
+ occurences = group.size
43
+ average_code_uncoverage = get_mean(group.column("percentage_uncovered"))
44
+ "#{'average ' if occurences > 1}uncovered code is %.1f%" % average_code_uncoverage
45
+ end
46
+ end
@@ -0,0 +1,61 @@
1
+ module MetricFu
2
+ class MetricRcov < Metric
3
+ def name
4
+ :rcov
5
+ end
6
+
7
+ def default_run_options
8
+ {
9
+ environment: "test",
10
+ test_files: Dir["{spec,test}/**/*_{spec,test}.rb"],
11
+ rcov_opts: rcov_opts,
12
+ external: nil,
13
+ }
14
+ end
15
+
16
+ def coverage_file=(coverage_file)
17
+ configured_run_options.update(external: coverage_file)
18
+ end
19
+
20
+ def has_graph?
21
+ true
22
+ end
23
+
24
+ def enable
25
+ if external_coverage_file?
26
+ super
27
+ else
28
+ mf_debug("RCov is not available. See README")
29
+ end
30
+ end
31
+
32
+ def activate
33
+ super
34
+ end
35
+
36
+ def external_coverage_file?
37
+ if coverage_file = run_options[:external]
38
+ File.exist?(coverage_file) ||
39
+ mf_log("Configured RCov file #{coverage_file.inspect} does not exist")
40
+ else
41
+ false
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def rcov_opts
48
+ rcov_opts = [
49
+ "--sort coverage",
50
+ "--no-html",
51
+ "--text-coverage",
52
+ "--no-color",
53
+ "--profile",
54
+ "--exclude-only '.*'",
55
+ '--include-file "\Aapp,\Alib"'
56
+ ]
57
+ rcov_opts << "-Ispec" if File.exist?("spec")
58
+ rcov_opts
59
+ end
60
+ end
61
+ end