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,105 @@
1
+ module MetricFu
2
+ class Loader
3
+ # TODO: This class mostly serves to clean up the base MetricFu module,
4
+ # but needs further work
5
+
6
+ attr_reader :loaded_files
7
+ def initialize(lib_root)
8
+ @lib_root = lib_root
9
+ @loaded_files = []
10
+ end
11
+
12
+ def lib_require(base = "", &_block)
13
+ paths = []
14
+ base_path = File.join(@lib_root, base)
15
+ Array((yield paths, base_path)).each do |path|
16
+ file = File.join(base_path, *Array(path))
17
+ require file
18
+ if @loaded_files.include?(file)
19
+ puts "!!!\tAlready loaded #{file}" if !!(ENV["MF_DEBUG"] =~ /true/i)
20
+ else
21
+ @loaded_files << file
22
+ end
23
+ end
24
+ end
25
+
26
+ # TODO: Reduce duplication of directory logic
27
+ # Adds methods x_dir and _x_require for the directory x,
28
+ # relative to the metric_fu lib, to the given klass
29
+ # @param klass [Class] the klass to add methods for the specified directories
30
+ # @yieldreturn [Array<String>] Takes a list of directories and adds readers for each
31
+ # @example For the directory 'metrics', which is relative to the metric_fu lib directory,
32
+ # creates on the klass two methods:
33
+ # ::metrics_dir which returns the full path
34
+ # ::metrics_require which takes a block of files to require relative to the metrics_dir
35
+ def create_dirs(klass)
36
+ class << klass
37
+ Array(yield).each do |dir|
38
+ define_method("#{dir}_dir") do
39
+ File.join(lib_dir, dir)
40
+ end
41
+ module_eval(%(def #{dir}_require(&block); lib_require('#{dir}', &block); end), __FILE__, __LINE__)
42
+ end
43
+ end
44
+ end
45
+
46
+ # Adds method x_dir relative to the metric_fu artifact directory to the given klass
47
+ # And strips any leading non-alphanumerical character from the directory name
48
+ # @param klass [Class] the klass to add methods for the specified artifact sub-directories
49
+ # @yieldreturn [Array<String>] Takes a list of directories and adds readers for each
50
+ # @example For the artifact sub-directory '_scratch', creates on the klass one method:
51
+ # ::scratch_dir (which notably has the leading underscore removed)
52
+ def create_artifact_subdirs(klass)
53
+ class << klass
54
+ Array(yield).each do |dir|
55
+ define_method("#{dir.gsub(/[^A-Za-z0-9]/, '')}_dir") do
56
+ File.join(artifact_dir, dir)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def setup
63
+ MetricFu.lib_require { "logger" }
64
+ MetricFu.logger.debug_on = !!(ENV["MF_DEBUG"] =~ /true/i)
65
+
66
+ load_metric_configuration
67
+
68
+ MetricFu.lib_require { "reporter" }
69
+ MetricFu.reporting_require { "result" }
70
+
71
+ MetricFu.load_tasks("metric_fu.rake", task_name: "metrics:all")
72
+ end
73
+
74
+ def load_metric_configuration
75
+ MetricFu.lib_require { "configuration" }
76
+ load_installed_metrics
77
+ MetricFu.configuration.configure_metrics
78
+ load_user_configuration
79
+ end
80
+
81
+ def load_installed_metrics
82
+ MetricFu.lib_require { "metric" }
83
+ Dir.glob(File.join(MetricFu.metrics_dir, "**/metric.rb")).each do |metric_config|
84
+ require metric_config
85
+ end
86
+ end
87
+
88
+ def load_user_configuration
89
+ file = File.join(MetricFu.run_dir, ".metrics")
90
+ load file if File.exist?(file)
91
+ end
92
+
93
+ # Load specified task task only once
94
+ # if and only if rake is required and the task is not yet defined
95
+ # to prevent the task from being loaded multiple times
96
+ # @param tasks_relative_path [String] 'metric_fu.rake' by default
97
+ # @param options [Hash] optional task_name to check if loaded
98
+ # @option options [String] :task_name The task_name to load, if not yet loaded
99
+ def load_tasks(tasks_relative_path, options = { task_name: "" })
100
+ if defined?(Rake::Task) and not Rake::Task.task_defined?(options[:task_name])
101
+ load File.join(@lib_root, "tasks", *Array(tasks_relative_path))
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,62 @@
1
+ require "logger"
2
+ require "forwardable"
3
+ module MetricFu
4
+ def self.logger
5
+ @logger ||= ::MetricFu::Logger.new($stdout)
6
+ end
7
+
8
+ class Logger
9
+ extend Forwardable
10
+ MfLogger = ::Logger
11
+
12
+ def initialize(stdout)
13
+ @logger = MfLogger.new(stdout)
14
+ self.debug_on = false
15
+ self.formatter = ->(_severity, _time, _progname, msg) { "#{msg}\n" }
16
+ self.level = "info"
17
+ end
18
+
19
+ def debug_on=(bool)
20
+ self.level = bool ? "debug" : "info"
21
+ end
22
+
23
+ def debug_on
24
+ @logger.level == MfLogger::DEBUG
25
+ end
26
+
27
+ def_delegators :@logger, :info, :warn, :error, :fatal, :unknown
28
+
29
+ LEVELS = {
30
+ "debug" => MfLogger::DEBUG,
31
+ "info" => MfLogger::INFO,
32
+ "warn" => MfLogger::WARN,
33
+ "error" => MfLogger::ERROR,
34
+ "fatal" => MfLogger::FATAL,
35
+ "unknown" => MfLogger::UNKNOWN,
36
+ }
37
+
38
+ def level=(level)
39
+ @logger.level = LEVELS.fetch(level.to_s.downcase) { level }
40
+ end
41
+
42
+ def formatter=(formatter)
43
+ @logger.formatter = formatter
44
+ end
45
+
46
+ def log(msg)
47
+ @logger.info "*" * 5 + msg.to_s
48
+ end
49
+
50
+ def debug(msg)
51
+ @logger.debug "*" * 5 + msg.to_s
52
+ end
53
+ end
54
+ end
55
+ # For backward compatibility
56
+ def mf_debug(msg, &block)
57
+ MetricFu.logger.debug(msg, &block)
58
+ end
59
+
60
+ def mf_log(msg, &block)
61
+ MetricFu.logger.log(msg, &block)
62
+ end
@@ -0,0 +1,23 @@
1
+ warn "MfDebugger if deprecated. Please use MetricFu.logger"
2
+ MetricFu.lib_require { "logger" }
3
+ module MfDebugger
4
+ extend self
5
+ class Logger
6
+ def self.debug_on
7
+ warn "MfDebugger if deprecated. Please use MetricFu.logger"
8
+ MetricFu.logger.debug_on
9
+ end
10
+ def self.debug_on=(bool)
11
+ warn "MfDebugger if deprecated. Please use MetricFu.logger"
12
+ MetricFu.logger.level = bool ? "debug" : "info"
13
+ end
14
+ def self.log(msg, &_block)
15
+ warn "MfDebugger if deprecated. Please use MetricFu.logger"
16
+ MetricFu.logger.info msg
17
+ end
18
+ def self.debug(msg, &_block)
19
+ warn "MfDebugger if deprecated. Please use MetricFu.logger"
20
+ MetricFu.logger.debug msg
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,143 @@
1
+ require "set"
2
+ MetricFu.lib_require { "gem_run" }
3
+ MetricFu.lib_require { "generator" }
4
+ # Encapsulates the configuration options for each metric
5
+ module MetricFu
6
+ class Metric
7
+ attr_accessor :enabled, :activated
8
+
9
+ def initialize
10
+ self.enabled = false
11
+ @libraries = Set.new
12
+ @configured_run_options = {}
13
+ end
14
+
15
+ def enable
16
+ self.enabled = true
17
+ end
18
+
19
+ # TODO: Confirm this catches load errors from requires in subclasses, such as for flog
20
+ def activate
21
+ MetricFu.metrics_require { default_metric_library_paths }
22
+ @libraries.each { |library| require(library) }
23
+ self.activated = true
24
+ rescue LoadError => e
25
+ mf_log "#{name} metric not activated, #{e.message}"
26
+ end
27
+
28
+ # @return metric name [Symbol]
29
+ def name
30
+ not_implemented
31
+ end
32
+
33
+ def gem_name
34
+ name
35
+ end
36
+
37
+ # @return metric run options [Hash]
38
+ def run_options
39
+ default_run_options.merge(configured_run_options)
40
+ end
41
+
42
+ def default_run_args
43
+ run_options.map { |k, v| "--#{k} #{v}" }.join(" ")
44
+ end
45
+
46
+ def run
47
+ not_implemented
48
+ end
49
+
50
+ def run_external(args = default_run_args)
51
+ runner = GemRun.new(
52
+ gem_name: gem_name.to_s,
53
+ metric_name: name.to_s,
54
+ # version: ,
55
+ args: args,
56
+ )
57
+ stdout, stderr, status = runner.run
58
+ # TODO: do something with the stderr
59
+ # for now, just acknowledge we got it
60
+ unless stderr.empty?
61
+ STDERR.puts "STDERR from #{gem_name}:\n#{stderr}"
62
+ end
63
+ # TODO: status.success? is not reliable for distinguishing
64
+ # between a successful run of the metric and problems
65
+ # found by the metric. Talk to other metrics about this.
66
+ MetricFu.logger.debug "#{gem_name} ran with #{status.success? ? 'success' : 'failure'} code #{status.exitstatus}"
67
+ stdout
68
+ end
69
+
70
+ def configured_run_options
71
+ @configured_run_options
72
+ end
73
+
74
+ # @return [Hash] default metric run options
75
+ def default_run_options
76
+ not_implemented
77
+ end
78
+
79
+ # @return [Hash] metric_options
80
+ def has_graph?
81
+ not_implemented
82
+ end
83
+
84
+ @metrics = []
85
+ # @return all subclassed metrics [Array<MetricFu::Metric>]
86
+ # ensure :hotspots runs last
87
+ def self.metrics
88
+ @metrics
89
+ end
90
+
91
+ def self.enabled_metrics
92
+ metrics.select { |metric| metric.enabled && metric.activated }.sort_by { |metric| metric.name == :hotspots ? 1 : 0 }
93
+ end
94
+
95
+ def self.get_metric(name)
96
+ metrics.find { |metric|metric.name.to_s == name.to_s }
97
+ end
98
+
99
+ def self.inherited(subclass)
100
+ @metrics << subclass.new
101
+ end
102
+
103
+ protected
104
+
105
+ # Enable using a syntax such as metric.foo = 'foo'
106
+ # by catching the missing method here,
107
+ # checking if :foo is a key in the default_run_options, and
108
+ # setting the key/value in the @configured_run_options hash
109
+ # TODO: See if we can do this without a method_missing
110
+ def method_missing(method, *args)
111
+ key = method_to_attr(method)
112
+ if default_run_options.has_key?(key)
113
+ configured_run_options[key] = args.first
114
+ else
115
+ raise "#{key} is not a valid configuration option"
116
+ end
117
+ end
118
+
119
+ # Used above to identify the stem of a setter method
120
+ def method_to_attr(method)
121
+ method.to_s.sub(/=$/, "").to_sym
122
+ end
123
+
124
+ private
125
+
126
+ def not_implemented
127
+ raise "Required method #{caller[0]} not implemented in #{__FILE__}"
128
+ end
129
+
130
+ def activate_library(file)
131
+ @libraries << file.strip
132
+ end
133
+
134
+ def default_metric_library_paths
135
+ paths = []
136
+ paths << generator_path = "#{name}/generator"
137
+ if has_graph?
138
+ paths << grapher_path = "#{name}/grapher"
139
+ end
140
+ paths
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,95 @@
1
+ MetricFu.metrics_require { "cane/violations" }
2
+ module MetricFu
3
+ class CaneGenerator < Generator
4
+ attr_reader :violations, :total_violations
5
+
6
+ def self.metric
7
+ :cane
8
+ end
9
+
10
+ def emit
11
+ args = [
12
+ abc_max_param,
13
+ style_measure_param,
14
+ no_doc_param,
15
+ no_readme_param
16
+ ].join
17
+ @output = run!(args)
18
+ end
19
+
20
+ def analyze
21
+ @violations = violations_by_category
22
+ extract_total_violations
23
+ end
24
+
25
+ def to_h
26
+ { cane: { total_violations: @total_violations, violations: @violations } }
27
+ end
28
+
29
+ private
30
+
31
+ def abc_max_param
32
+ options[:abc_max] ? " --abc-max #{options[:abc_max]}" : ""
33
+ end
34
+
35
+ def style_measure_param
36
+ options[:line_length] ? " --style-measure #{options[:line_length]}" : ""
37
+ end
38
+
39
+ def no_doc_param
40
+ options[:no_doc] == "y" ? " --no-doc" : ""
41
+ end
42
+
43
+ def no_readme_param
44
+ options[:no_readme] == "y" ? " --no-readme" : ""
45
+ end
46
+
47
+ def violations_by_category
48
+ violations_output = @output.scan(/(.*?)\n\n(.*?)\n\n/m)
49
+ violations_output.each_with_object({}) do |(category_desc, violation_list), violations|
50
+ category = category_from(category_desc) || :others
51
+ violations[category] ||= []
52
+ violations[category] += violations_for(category, violation_list)
53
+ end
54
+ end
55
+
56
+ def category_from(description)
57
+ category_descriptions = {
58
+ abc_complexity: /ABC complexity/,
59
+ line_style: /style requirements/,
60
+ comment: /comment/,
61
+ documentation: /documentation/
62
+ }
63
+ category, desc_matcher = category_descriptions.find { |_k, v| description =~ v }
64
+ mf_debug desc_matcher.inspect
65
+ category
66
+ end
67
+
68
+ def violations_for(category, violation_list)
69
+ violation_type_for(category).parse(violation_list)
70
+ end
71
+
72
+ def violation_type_for(category)
73
+ case category
74
+ when :abc_complexity
75
+ CaneViolations::AbcComplexity
76
+ when :line_style
77
+ CaneViolations::LineStyle
78
+ when :comment
79
+ CaneViolations::Comment
80
+ when :documentation
81
+ CaneViolations::Documentation
82
+ else
83
+ CaneViolations::Others
84
+ end
85
+ end
86
+
87
+ def extract_total_violations
88
+ if @output =~ /Total Violations: (\d+)/
89
+ @total_violations = $1.to_i
90
+ else
91
+ @total_violations = 0
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,37 @@
1
+ MetricFu.reporting_require { "graphs/grapher" }
2
+ module MetricFu
3
+ class CaneGrapher < Grapher
4
+ attr_accessor :cane_violations, :labels
5
+
6
+ def self.metric
7
+ :cane
8
+ end
9
+
10
+ def initialize
11
+ super
12
+ @cane_violations = []
13
+ @labels = {}
14
+ end
15
+
16
+ def get_metrics(metrics, date)
17
+ if metrics && metrics[:cane]
18
+ @cane_violations.push(metrics[:cane][:total_violations].to_i)
19
+ @labels.update(@labels.size => date)
20
+ end
21
+ end
22
+
23
+ def title
24
+ "Cane: code quality threshold violations"
25
+ end
26
+
27
+ def data
28
+ [
29
+ ["cane", @cane_violations.join(",")]
30
+ ]
31
+ end
32
+
33
+ def output_filename
34
+ "cane.js"
35
+ end
36
+ end
37
+ end