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,39 @@
1
+ class MetricFu::RoodiHotspot < MetricFu::Hotspot
2
+ COLUMNS = %w{problems}
3
+
4
+ def columns
5
+ COLUMNS
6
+ end
7
+
8
+ def name
9
+ :roodi
10
+ end
11
+
12
+ def map_strategy
13
+ :present
14
+ end
15
+
16
+ def reduce_strategy
17
+ :sum
18
+ end
19
+
20
+ def score_strategy
21
+ :percentile
22
+ end
23
+
24
+ def generate_records(data, table)
25
+ return if data == nil
26
+ Array(data[:problems]).each do |problem|
27
+ table << {
28
+ "metric" => name,
29
+ "problems" => problem[:problem],
30
+ "file_path" => problem[:file]
31
+ }
32
+ end
33
+ end
34
+
35
+ def present_group(group)
36
+ occurences = group.size
37
+ "found #{occurences} design problems"
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ module MetricFu
2
+ class MetricRoodi < Metric
3
+ def name
4
+ :roodi
5
+ end
6
+
7
+ def default_run_options
8
+ { dirs_to_roodi: MetricFu::Io::FileSystem.directory("code_dirs"),
9
+ roodi_config: "#{MetricFu::Io::FileSystem.directory('root_directory')}/config/roodi_config.yml" }
10
+ end
11
+
12
+ def has_graph?
13
+ true
14
+ end
15
+
16
+ def enable
17
+ super
18
+ end
19
+
20
+ def activate
21
+ super
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ <h3>Roodi Results</h3>
2
+
3
+ <p><a href="http://roodi.rubyforge.org/">Roodi</a> parses your Ruby code and warns you about design issues you have based on the checks that is has configured.</p>
4
+
5
+ <%= render_partial 'graph', {:graph_name => 'roodi'} %>
6
+
7
+ <table>
8
+ <tr>
9
+ <th>File Path</th>
10
+ <th>Warning</th>
11
+ </tr>
12
+ <% count = 0 %>
13
+ <% @roodi[:problems].each do |problem| %>
14
+ <tr class='<%= cycle("light", "dark", count) %>'>
15
+ <td><%= link_to_filename(problem[:file], problem[:line]) %></td>
16
+ <td><%= problem[:problem] %></td>
17
+ </tr>
18
+ <% count += 1 %>
19
+ <% end %>
20
+ </table>
21
+
22
+ <%= render_partial 'report_footer' %>
@@ -0,0 +1,145 @@
1
+ # encoding: utf-8
2
+ MetricFu.lib_require { "utility" }
3
+ MetricFu.metrics_require { "saikuro/scratch_file" }
4
+ MetricFu.metrics_require { "saikuro/parsing_element" }
5
+ MetricFu.data_structures_require { "line_numbers" }
6
+ module MetricFu
7
+ class SaikuroGenerator < MetricFu::Generator
8
+ def self.metric
9
+ :saikuro
10
+ end
11
+
12
+ def emit
13
+ options_string = options.inject("") do |options, option|
14
+ option[0] == :input_directory ? options : options + "--#{option.join(' ')} "
15
+ end
16
+
17
+ options[:input_directory].each do |input_dir|
18
+ options_string += "--input_directory #{input_dir} "
19
+ end
20
+
21
+ @output = run!(options_string)
22
+ end
23
+
24
+ def analyze
25
+ @files = sort_files(assemble_files)
26
+ @classes = sort_classes(assemble_classes(@files))
27
+ @meths = sort_methods(assemble_methods(@files))
28
+ end
29
+
30
+ def to_h
31
+ @saikuro_data = {
32
+ files: files_with_relative_paths(@files),
33
+ classes: @classes.map(&:to_h),
34
+ methods: @meths.map(&:to_h),
35
+ }
36
+ clear_scratch_files!
37
+ { saikuro: @saikuro_data }
38
+ end
39
+
40
+ def per_file_info(out)
41
+ @saikuro_data[:files].each do |file_data|
42
+ filename = file_data[:filename]
43
+ next if erb_file?(filename) || file_not_exists?(filename)
44
+ next unless line_numbers = line_numbers_from_file(filename)
45
+
46
+ build_output_from_line_numbers(out, line_numbers, file_data)
47
+ end
48
+ end
49
+
50
+ def build_output_from_line_numbers(out, line_numbers, file_data)
51
+ filename = file_data[:filename]
52
+ output = out[filename]
53
+ method_data_for_file_data(file_data) do |method_data|
54
+ line = line_numbers.start_line_for_method(method_data[:name]).to_s
55
+ result = {
56
+ type: :saikuro,
57
+ description: "Complexity #{method_data[:complexity]}"
58
+ }
59
+ output[line] << result
60
+ end
61
+ out
62
+ end
63
+
64
+ def line_numbers_from_file(filename)
65
+ MetricFu::LineNumbers.new(File.read(filename))
66
+ rescue StandardError => e
67
+ raise e unless e.message =~ /you shouldn't be able to get here/
68
+ mf_log "ruby_parser blew up while trying to parse #{file_path}. You won't have method level Saikuro information for this file."
69
+ end
70
+
71
+ def method_data_for_file_data(file_data, &_block)
72
+ return unless block_given?
73
+ file_data[:classes].each do |class_data|
74
+ class_data[:methods].each do |method_data|
75
+ yield method_data
76
+ end
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def erb_file?(filename)
83
+ File.extname(filename) == ".erb"
84
+ end
85
+
86
+ def file_not_exists?(filename)
87
+ !File.exists?(filename)
88
+ end
89
+
90
+ def sort_methods(methods)
91
+ methods.sort_by { |method| method.complexity.to_i }.reverse
92
+ end
93
+
94
+ def assemble_methods(files)
95
+ methods = []
96
+ files.each do |file|
97
+ file.elements.each do |element|
98
+ element.defs.each do |defn|
99
+ defn.name = "#{element.name}##{defn.name}"
100
+ methods << defn
101
+ end
102
+ end
103
+ end
104
+ methods
105
+ end
106
+
107
+ def sort_classes(classes)
108
+ classes.sort_by { |k| k.complexity.to_i }.reverse
109
+ end
110
+
111
+ def assemble_classes(files)
112
+ files.map(&:elements).flatten
113
+ end
114
+
115
+ def sort_files(files)
116
+ files.sort_by do |file|
117
+ file.elements.
118
+ max { |a, b| a.complexity.to_i <=> b.complexity.to_i }.
119
+ complexity.to_i
120
+ end.reverse
121
+ end
122
+
123
+ def assemble_files
124
+ SaikuroScratchFile.assemble_files(Dir.glob("#{metric_directory}/**/*.html"))
125
+ end
126
+
127
+ def files_with_relative_paths(files)
128
+ files.map do |file|
129
+ file_hash = file.to_h
130
+ file_hash[:filename] = file_relative_path(file)
131
+ file_hash
132
+ end.to_a
133
+ end
134
+
135
+ def file_relative_path(file)
136
+ filepath = file.filepath
137
+ path = filepath.gsub(/^#{metric_directory}\//, "")
138
+ "#{path}/#{file.filename}"
139
+ end
140
+
141
+ def clear_scratch_files!
142
+ MetricFu::Utility.rm_rf(metric_directory)
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,51 @@
1
+ class MetricFu::SaikuroHotspot < MetricFu::Hotspot
2
+ COLUMNS = %w{lines complexity}
3
+
4
+ def columns
5
+ COLUMNS
6
+ end
7
+
8
+ def name
9
+ :saikuro
10
+ end
11
+
12
+ def map_strategy
13
+ :complexity
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[:files].each do |file|
27
+ file_name = file[:filename]
28
+ file[:classes].each do |klass|
29
+ location = MetricFu::Location.for(klass[:class_name])
30
+ offending_class = location.class_name
31
+ klass[:methods].each do |match|
32
+ offending_method = MetricFu::Location.for(match[:name]).method_name
33
+ table << {
34
+ "metric" => name,
35
+ "lines" => match[:lines],
36
+ "complexity" => match[:complexity],
37
+ "class_name" => offending_class,
38
+ "method_name" => offending_method,
39
+ "file_path" => file_name,
40
+ }
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ def present_group(group)
47
+ occurences = group.size
48
+ complexity = get_mean(group.column("complexity"))
49
+ "#{'average ' if occurences > 1}complexity is %.1f" % complexity
50
+ end
51
+ end
@@ -0,0 +1,31 @@
1
+ module MetricFu
2
+ class MetricSaikuro < Metric
3
+ def name
4
+ :saikuro
5
+ end
6
+
7
+ def default_run_options
8
+ {
9
+ output_directory: MetricFu::Io::FileSystem.scratch_directory(name),
10
+ input_directory: MetricFu::Io::FileSystem.directory("code_dirs"),
11
+ cyclo: "",
12
+ filter_cyclo: "0",
13
+ warn_cyclo: "5",
14
+ error_cyclo: "7",
15
+ formater: "text",
16
+ }
17
+ end
18
+
19
+ def has_graph?
20
+ false
21
+ end
22
+
23
+ def enable
24
+ super
25
+ end
26
+
27
+ def activate
28
+ super
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,37 @@
1
+ module MetricFu
2
+ class SaikuroParsingElement
3
+ TYPE_REGEX = /Type:(.*) Name/
4
+ NAME_REGEX = /Name:(.*) Complexity/
5
+ COMPLEXITY_REGEX = /Complexity:(.*) Lines/
6
+ LINES_REGEX = /Lines:(.*)/
7
+
8
+ attr_reader :complexity, :lines, :defs, :element_type
9
+ attr_accessor :name
10
+
11
+ def initialize(line)
12
+ @line = line
13
+ @element_type = line.match(TYPE_REGEX)[1].strip
14
+ @name = line.match(NAME_REGEX)[1].strip
15
+ @complexity = line.match(COMPLEXITY_REGEX)[1].strip
16
+ @lines = line.match(LINES_REGEX)[1].strip
17
+ @defs = []
18
+ end
19
+
20
+ def <<(line)
21
+ @defs << MetricFu::SaikuroParsingElement.new(line)
22
+ end
23
+
24
+ def to_h
25
+ base = { name: @name, complexity: @complexity.to_i, lines: @lines.to_i }
26
+ unless @defs.empty?
27
+ defs = @defs.map do |my_def|
28
+ my_def = my_def.to_h
29
+ my_def.delete(:defs)
30
+ my_def
31
+ end
32
+ base[:defs] = defs
33
+ end
34
+ base
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,71 @@
1
+ <h3>Saikuro Results</h3>
2
+ <p><a href='http://saikuro.rubyforge.org/'>Saikuro</a> analyzes ruby code for cyclomatic complexity.</p>
3
+
4
+ <h2>Analyzed Methods</h2>
5
+ <table>
6
+ <tr>
7
+ <th>Method Name</th>
8
+ <th>Complexity</th>
9
+ <th># Lines</th>
10
+ </tr>
11
+ <% @saikuro[:methods].each do |method| %>
12
+ <tr>
13
+ <td><%= method[:name] %></td>
14
+ <td><%= method[:complexity] %></td>
15
+ <td><%= method[:lines] %></td>
16
+ </tr>
17
+ <% end %>
18
+ </table>
19
+
20
+
21
+
22
+ <h2>Analyzed Classes</h2>
23
+ <table>
24
+ <tr>
25
+ <th>Class Name</th>
26
+ <th>Complexity</th>
27
+ <th># Lines</th>
28
+ </tr>
29
+ <% @saikuro[:classes].each do |klass| %>
30
+ <tr>
31
+ <td><%= klass[:name] %></td>
32
+ <td><%= klass[:complexity] %></td>
33
+ <td><%= klass[:lines] %></td>
34
+ </tr>
35
+ <% end %>
36
+ </table>
37
+
38
+
39
+ <h2>Analyzed Files</h2>
40
+ <% @saikuro[:files].each do |file| %>
41
+ <% file[:classes].each do |klass| %>
42
+ <% if !klass[:methods].empty? %>
43
+ <h3><%=link_to_filename(file[:filename])%></h3>
44
+ <h4>Class : <%= klass[:class_name] %></h4>
45
+ <h5>Total complexity : <%= klass[:complexity] %></h5>
46
+ <h5>Total lines : <%= klass[:lines] %></h5>
47
+ <table>
48
+ <tr>
49
+ <th>Method</th>
50
+ <th>Complexity</th>
51
+ <th># Lines</th>
52
+ </tr>
53
+ <% klass[:methods].each do |method| %>
54
+ <tr>
55
+ <td>
56
+ <%= method[:name] %>
57
+ </td>
58
+ <td>
59
+ <%= method[:complexity] %>
60
+ </td>
61
+ <td>
62
+ <%= method[:lines] %>
63
+ </td>
64
+ </tr>
65
+ <% end %>
66
+ </table>
67
+ <% end %>
68
+ <% end %>
69
+ <% end %>
70
+
71
+ <%= render_partial 'report_footer' %>
@@ -0,0 +1,108 @@
1
+ MetricFu.metrics_require { "saikuro/parsing_element" }
2
+ module MetricFu
3
+ class SaikuroScratchFile
4
+ def self.assemble_files(glob)
5
+ files = []
6
+ glob.each do |path|
7
+ if is_valid_text_file?(path)
8
+ file = new(path)
9
+ if file
10
+ files << file
11
+ end
12
+ end
13
+ end
14
+ files
15
+ end
16
+
17
+ attr_reader :elements
18
+
19
+ def initialize(path)
20
+ @path = path
21
+ @elements = []
22
+ File.open(@path, "rb") do |file|
23
+ get_elements(file)
24
+ end
25
+ end
26
+
27
+ def self.is_valid_text_file?(path)
28
+ File.open(path, "rb") do |file|
29
+ if file.eof? || !file.readline.match(/--/)
30
+ return false
31
+ else
32
+ return true
33
+ end
34
+ end
35
+ end
36
+
37
+ def filename
38
+ File.basename(@path, "_cyclo.html")
39
+ end
40
+
41
+ def filepath
42
+ File.dirname(@path)
43
+ end
44
+
45
+ def to_h
46
+ merge_classes
47
+ { classes: @elements }
48
+ end
49
+
50
+ def get_elements(io)
51
+ while (line = io.readline)
52
+ return [] if line.nil? || line !~ /\S/
53
+ element ||= nil
54
+ if line.match(/START/)
55
+ unless element.nil?
56
+ @elements << element
57
+ element = nil
58
+ end
59
+ line = io.readline
60
+ element = MetricFu::SaikuroParsingElement.new(line)
61
+ elsif line.match(/END/)
62
+ @elements << element if element
63
+ element = nil
64
+ else
65
+ element << line if element
66
+ end
67
+ end
68
+ rescue EOFError
69
+ nil
70
+ end
71
+
72
+ def merge_classes
73
+ new_elements = []
74
+ get_class_names.each do |target_class|
75
+ elements = @elements.find_all { |el| el.name == target_class }
76
+ complexity = 0
77
+ lines = 0
78
+ defns = []
79
+ elements.each do |el|
80
+ complexity += el.complexity.to_i
81
+ lines += el.lines.to_i
82
+ defns << el.defs
83
+ end
84
+
85
+ new_element = { class_name: target_class,
86
+ complexity: complexity,
87
+ lines: lines,
88
+ methods: defns.flatten.map(&:to_h) }
89
+ new_element[:methods] = new_element[:methods].
90
+ sort_by { |x| x[:complexity] }.
91
+ reverse
92
+
93
+ new_elements << new_element
94
+ end
95
+ @elements = new_elements if new_elements
96
+ end
97
+
98
+ def get_class_names
99
+ class_names = []
100
+ @elements.each do |element|
101
+ unless class_names.include?(element.name)
102
+ class_names << element.name
103
+ end
104
+ end
105
+ class_names
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,82 @@
1
+ module MetricFu
2
+ class StatsGenerator < Generator
3
+ def self.metric
4
+ :stats
5
+ end
6
+
7
+ def emit
8
+ require "code_metrics/statistics"
9
+ @output = MetricFu::Utility.capture_output do
10
+ CodeMetrics::Statistics.new(*dirs).to_s
11
+ end
12
+ end
13
+
14
+ def analyze
15
+ lines = remove_noise(@output).compact
16
+
17
+ @stats = {}
18
+
19
+ set_global_stats(lines.pop)
20
+ set_granular_stats(lines)
21
+
22
+ @stats
23
+ end
24
+
25
+ def to_h
26
+ { stats: @stats }
27
+ end
28
+
29
+ private
30
+
31
+ def remove_noise(output)
32
+ lines = output.split("\n")
33
+ lines = lines.find_all { |line| line =~ /^\s*[C|]/ }
34
+ lines.shift
35
+ lines
36
+ end
37
+
38
+ def set_global_stats(totals)
39
+ return if totals.nil?
40
+ parsed_totals = totals.split(" ").find_all { |el| !el.empty? }
41
+ @stats[:codeLOC] = parsed_totals.shift.match(/\d.*/)[0].to_i
42
+ @stats[:testLOC] = parsed_totals.shift.match(/\d.*/)[0].to_i
43
+ matched_numbers = Array(parsed_totals.shift.match(/1\:(\d.*)/))
44
+ if matched_numbers.size == 2
45
+ @stats[:code_to_test_ratio] = matched_numbers[1].to_f
46
+ else
47
+ mf_log "Unexpected code to test ratio #{matched_numbers.inspect} over directories #{dirs.inspect}"
48
+ @stats[:code_to_test_ratio] = 0.0
49
+ end
50
+ end
51
+
52
+ def set_granular_stats(lines)
53
+ @stats[:lines] = lines.map do |line|
54
+ elements = line.split("|")
55
+ elements.map!(&:strip)
56
+ elements = elements.find_all { |el| !el.empty? }
57
+ info_line = {}
58
+ info_line[:name] = elements.shift
59
+ elements.map!(&:to_i)
60
+ [:lines, :loc, :classes, :methods,
61
+ :methods_per_class, :loc_per_method].each do |sym|
62
+ info_line[sym] = elements.shift
63
+ end
64
+ info_line
65
+ end
66
+ end
67
+
68
+ # @return [Array<[ 'Acceptance specs', 'spec/acceptance' ]>]
69
+ def dirs
70
+ require "code_metrics/stats_directories"
71
+ require "code_metrics/statistics"
72
+ stats_dirs = CodeMetrics::StatsDirectories.new
73
+ options.fetch(:additional_test_directories).each do |option|
74
+ stats_dirs.add_test_directories(option.fetch(:glob_pattern), option.fetch(:file_pattern))
75
+ end
76
+ options.fetch(:additional_app_directories).each do |option|
77
+ stats_dirs.add_directories(option.fetch(:glob_pattern), option.fetch(:file_pattern))
78
+ end
79
+ stats_dirs.directories
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,40 @@
1
+ MetricFu.reporting_require { "graphs/grapher" }
2
+ module MetricFu
3
+ class StatsGrapher < Grapher
4
+ attr_accessor :loc_counts, :lot_counts, :labels
5
+
6
+ def self.metric
7
+ :stats
8
+ end
9
+
10
+ def initialize
11
+ super
12
+ self.loc_counts = []
13
+ self.lot_counts = []
14
+ self.labels = {}
15
+ end
16
+
17
+ def get_metrics(metrics, date)
18
+ if metrics && metrics[:stats]
19
+ loc_counts.push(metrics[:stats][:codeLOC].to_i)
20
+ lot_counts.push(metrics[:stats][:testLOC].to_i)
21
+ labels.update(labels.size => date)
22
+ end
23
+ end
24
+
25
+ def title
26
+ "Stats: LOC & LOT"
27
+ end
28
+
29
+ def data
30
+ [
31
+ ["LOC", @loc_counts.join(",")],
32
+ ["LOT", @lot_counts.join(",")],
33
+ ]
34
+ end
35
+
36
+ def output_filename
37
+ "stats.js"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ class MetricFu::StatsHotspot < MetricFu::Hotspot
2
+ COLUMNS = %w{stat_name stat_value}
3
+
4
+ def columns
5
+ COLUMNS
6
+ end
7
+
8
+ def name
9
+ :stats
10
+ end
11
+
12
+ def map_strategy
13
+ :absent
14
+ end
15
+
16
+ def reduce_strategy
17
+ :absent
18
+ end
19
+
20
+ def score_strategy
21
+ :absent
22
+ end
23
+
24
+ def generate_records(data, table)
25
+ return if data == nil
26
+ data.each do |key, value|
27
+ next if value.is_a?(Array)
28
+ table << {
29
+ "metric" => name,
30
+ "stat_name" => key,
31
+ "stat_value" => value
32
+ }
33
+ end
34
+ end
35
+ end