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,38 @@
1
+ createGraphElement("div");
2
+
3
+ if(document.getElementById('graph')) {
4
+ var chart = new Highcharts.Chart({
5
+ chart: {
6
+ animation: false,
7
+ renderTo: 'graph'
8
+ },
9
+ legend: {
10
+ align: 'center',
11
+ verticalAlign: 'top',
12
+ y: 25
13
+ },
14
+ plotOptions: {
15
+ line: {
16
+ animation: false,
17
+ lineWidth: 3,
18
+ marker: {
19
+ radius: 6
20
+ },
21
+ pointPlacement: 'on'
22
+ }
23
+ },
24
+ title: {
25
+ text: graph_title
26
+ },
27
+ xAxis: {
28
+ categories: graph_labels,
29
+ tickmarkPlacement: 'on'
30
+ },
31
+ yAxis: {
32
+ maxPadding: 0,
33
+ min: 0,
34
+ minPadding: 0
35
+ },
36
+ series: graph_series
37
+ });
38
+ }
@@ -0,0 +1 @@
1
+ JS={extend:function(a,b){b=b||{};for(var c in b){if(a[c]===b[c])continue;a[c]=b[c]}return a},makeFunction:function(){return function(){return this.initialize?(this.initialize.apply(this,arguments)||this):this}},makeBridge:function(a){var b=function(){};b.prototype=a.prototype;return new b},bind:function(){var a=JS.array(arguments),b=a.shift(),c=a.shift()||null;return function(){return b.apply(c,a.concat(JS.array(arguments)))}},callsSuper:function(a){return a.SUPER===undefined?a.SUPER=/\bcallSuper\b/.test(a.toString()):a.SUPER},mask:function(a){var b=a.toString().replace(/callSuper/g,'super');a.toString=function(){return b};return a},array:function(a){if(!a)return[];if(a.toArray)return a.toArray();var b=a.length,c=[];while(b--)c[b]=a[b];return c},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},isFn:function(a){return a instanceof Function},isType:function(a,b){if(!a||!b)return false;return(b instanceof Function&&a instanceof b)||(typeof b==='string'&&typeof a===b)||(a.isA&&a.isA(b))},ignore:function(a,b){return/^(include|extend)$/.test(a)&&typeof b==='object'}};JS.Module=JS.makeFunction();JS.extend(JS.Module.prototype,{END_WITHOUT_DOT:/([^\.])$/,initialize:function(a,b,c){this.__mod__=this;this.__inc__=[];this.__fns__={};this.__dep__=[];this.__mct__={};if(typeof a==='string'){this.__nom__=this.displayName=a}else{this.__nom__=this.displayName='';c=b;b=a}c=c||{};this.__res__=c._1||null;if(b)this.include(b,false);if(JS.Module.__chainq__)JS.Module.__chainq__.push(this)},setName:function(a){this.__nom__=this.displayName=a||'';for(var b in this.__mod__.__fns__)this.__name__(b);if(a&&this.__meta__)this.__meta__.setName(a+'.')},__name__:function(a){if(!this.__nom__)return;var b=this.__mod__.__fns__[a]||{};a=this.__nom__.replace(this.END_WITHOUT_DOT,'$1#')+a;if(JS.isFn(b.setName))return b.setName(a);if(JS.isFn(b))b.displayName=a},define:function(a,b,c,d){var f=(d||{})._0||this;this.__fns__[a]=b;this.__name__(a);if(JS.Module._0&&f&&JS.isFn(b))JS.Module._0(a,f);if(c!==false)this.resolve()},instanceMethod:function(a){var b=this.lookup(a).pop();return JS.isFn(b)?b:null},instanceMethods:function(a,b){var c=this.__mod__,b=b||[],d=c.ancestors(),f=d.length,e;for(e in c.__fns__){if(c.__fns__.hasOwnProperty(e)&&JS.isFn(c.__fns__[e])&&JS.indexOf(b,e)===-1)b.push(e)}if(a===false)return b;while(f--)d[f].instanceMethods(false,b);return b},include:function(a,b,c){b=(b!==false);if(!a)return b?this.resolve():this.uncache();c=c||{};if(a.__mod__)a=a.__mod__;var d=a.include,f=a.extend,e=c._4||this,g,h,i,j;if(a.__inc__&&a.__fns__){this.__inc__.push(a);a.__dep__.push(this);if(c._2)a.extended&&a.extended(c._2);else a.included&&a.included(e)}else{if(c._5){for(h in a){if(JS.ignore(h,a[h]))continue;this.define(h,a[h],false,{_0:e||c._2||this})}}else{if(typeof d==='object'||JS.isType(d,JS.Module)){g=[].concat(d);for(i=0,j=g.length;i<j;i++)e.include(g[i],b,c)}if(typeof f==='object'||JS.isType(f,JS.Module)){g=[].concat(f);for(i=0,j=g.length;i<j;i++)e.extend(g[i],false);e.extend()}c._5=true;return e.include(a,b,c)}}b?this.resolve():this.uncache()},includes:function(a){var b=this.__mod__,c=b.__inc__.length;if(Object===a||b===a||b.__res__===a.prototype)return true;while(c--){if(b.__inc__[c].includes(a))return true}return false},match:function(a){return a.isA&&a.isA(this)},ancestors:function(a){var b=this.__mod__,c=(a===undefined),d=(b.__res__||{}).klass,f=(d&&b.__res__===d.prototype)?d:b,e,g;if(c&&b.__anc__)return b.__anc__.slice();a=a||[];for(e=0,g=b.__inc__.length;e<g;e++)b.__inc__[e].ancestors(a);if(JS.indexOf(a,f)===-1)a.push(f);if(c)b.__anc__=a.slice();return a},lookup:function(a){var b=this.__mod__,c=b.__mct__;if(c[a])return c[a].slice();var d=b.ancestors(),f=[],e,g,h;for(e=0,g=d.length;e<g;e++){h=d[e].__mod__.__fns__[a];if(h)f.push(h)}c[a]=f.slice();return f},make:function(a,b){if(!JS.isFn(b)||!JS.callsSuper(b))return b;var c=this;return function(){return c.chain(this,a,arguments)}},chain:JS.mask(function(c,d,f){var e=this.lookup(d),g=e.length-1,h=c.callSuper,i=JS.array(f),j;c.callSuper=function(){var a=arguments.length;while(a--)i[a]=arguments[a];g-=1;var b=e[g].apply(c,i);g+=1;return b};j=e.pop().apply(c,i);h?c.callSuper=h:delete c.callSuper;return j}),resolve:function(a){var b=this.__mod__,a=a||b,c=a.__res__,d,f,e,g;if(a===b){b.uncache(false);d=b.__dep__.length;while(d--)b.__dep__[d].resolve()}if(!c)return;for(d=0,f=b.__inc__.length;d<f;d++)b.__inc__[d].resolve(a);for(e in b.__fns__){g=a.make(e,b.__fns__[e]);if(c[e]!==g)c[e]=g}},uncache:function(a){var b=this.__mod__,c=b.__dep__.length;b.__anc__=null;b.__mct__={};if(a===false)return;while(c--)b.__dep__[c].uncache()}});JS.Class=JS.makeFunction();JS.extend(JS.Class.prototype=JS.makeBridge(JS.Module),{initialize:function(a,b,c){if(typeof a==='string'){this.__nom__=this.displayName=a}else{this.__nom__=this.displayName='';c=b;b=a}var d=JS.extend(JS.makeFunction(),this);d.klass=d.constructor=this.klass;if(!JS.isFn(b)){c=b;b=Object}d.inherit(b);d.include(c,false);d.resolve();do{b.inherited&&b.inherited(d)}while(b=b.superclass);return d},inherit:function(a){this.superclass=a;if(this.__eigen__&&a.__eigen__)this.extend(a.__eigen__(),true);this.subclasses=[];(a.subclasses||[]).push(this);var b=this.prototype=JS.makeBridge(a);b.klass=b.constructor=this;this.__mod__=new JS.Module(this.__nom__,{},{_1:this.prototype});this.include(JS.Kernel,false);if(a!==Object)this.include(a.__mod__||new JS.Module(a.prototype,{_1:a.prototype}),false)},include:function(a,b,c){if(!a)return;var d=this.__mod__,c=c||{};c._4=this;return d.include(a,b,c)},define:function(a,b,c,d){var f=this.__mod__;d=d||{};d._0=this;f.define(a,b,c,d)}});JS.Module=new JS.Class('Module',JS.Module.prototype);JS.Class=new JS.Class('Class',JS.Module,JS.Class.prototype);JS.Module.klass=JS.Module.constructor=JS.Class.klass=JS.Class.constructor=JS.Class;JS.extend(JS.Module,{_3:[],__chainq__:[],methodAdded:function(a,b){this._3.push([a,b])},_0:function(a,b){var c=this._3,d=c.length;while(d--)c[d][0].call(c[d][1]||null,a,b)}});JS.Kernel=JS.extend(new JS.Module('Kernel',{__eigen__:function(){if(this.__meta__)return this.__meta__;var a=this.__nom__,b=this.klass.__nom__,c=a||(b?'#<'+b+'>':''),d=this.__meta__=new JS.Module(c?c+'.':'',{},{_1:this});d.include(this.klass.__mod__,false);return d},equals:function(a){return this===a},extend:function(a,b){return this.__eigen__().include(a,b,{_2:this})},hash:function(){return this.__hashcode__=this.__hashcode__||JS.Kernel.getHashCode()},isA:function(a){return this.__eigen__().includes(a)},method:function(a){var b=this,c=b.__mcache__=b.__mcache__||{};if((c[a]||{}).fn===b[a])return c[a].bd;return(c[a]={fn:b[a],bd:JS.bind(b[a],b)}).bd},methods:function(){return this.__eigen__().instanceMethods(true)},tap:function(a,b){a.call(b||null,this);return this}}),{__hashIndex__:0,getHashCode:function(){this.__hashIndex__+=1;return(Math.floor(new Date().getTime()/1000)+this.__hashIndex__).toString(16)}});JS.Module.include(JS.Kernel);JS.extend(JS.Module,JS.Kernel.__fns__);JS.Class.include(JS.Kernel);JS.extend(JS.Class,JS.Kernel.__fns__);JS.Interface=new JS.Class({initialize:function(d){this.test=function(a,b){var c=d.length;while(c--){if(!JS.isFn(a[d[c]]))return b?d[c]:false}return true}},extend:{ensure:function(){var a=JS.array(arguments),b=a.shift(),c,d;while(c=a.shift()){d=c.test(b,true);if(d!==true)throw new Error('object does not implement '+d+'()');}}}});JS.Singleton=new JS.Class({initialize:function(a,b,c){return new(new JS.Class(a,b,c))}});
@@ -0,0 +1,17 @@
1
+ /*
2
+ Highcharts JS v3.0.9 (2014-01-15)
3
+
4
+ Standalone Highcharts Framework
5
+
6
+ License: MIT License
7
+ */
8
+ var HighchartsAdapter=function(){function o(c){function b(b,a,d){b.removeEventListener(a,d,!1)}function d(b,a,d){d=b.HCProxiedMethods[d.toString()];b.detachEvent("on"+a,d)}function a(a,c){var f=a.HCEvents,i,g,k,j;if(a.removeEventListener)i=b;else if(a.attachEvent)i=d;else return;c?(g={},g[c]=!0):g=f;for(j in g)if(f[j])for(k=f[j].length;k--;)i(a,j,f[j][k])}c.HCExtended||Highcharts.extend(c,{HCExtended:!0,HCEvents:{},bind:function(a,b){var d=this,c=this.HCEvents,g;if(d.addEventListener)d.addEventListener(a,
9
+ b,!1);else if(d.attachEvent){g=function(a){b.call(d,a)};if(!d.HCProxiedMethods)d.HCProxiedMethods={};d.HCProxiedMethods[b.toString()]=g;d.attachEvent("on"+a,g)}c[a]===r&&(c[a]=[]);c[a].push(b)},unbind:function(c,h){var f,i;c?(f=this.HCEvents[c]||[],h?(i=HighchartsAdapter.inArray(h,f),i>-1&&(f.splice(i,1),this.HCEvents[c]=f),this.removeEventListener?b(this,c,h):this.attachEvent&&d(this,c,h)):(a(this,c),this.HCEvents[c]=[])):(a(this),this.HCEvents={})},trigger:function(a,b){var d=this.HCEvents[a]||
10
+ [],c=d.length,g,k,j;k=function(){b.defaultPrevented=!0};for(g=0;g<c;g++){j=d[g];if(b.stopped)break;b.preventDefault=k;b.target=this;if(!b.type)b.type=a;j.call(this,b)===!1&&b.preventDefault()}}});return c}var r,l=document,p=[],m=[],q,n;Math.easeInOutSine=function(c,b,d,a){return-d/2*(Math.cos(Math.PI*c/a)-1)+b};return{init:function(c){if(!l.defaultView)this._getStyle=function(b,d){var a;return b.style[d]?b.style[d]:(d==="opacity"&&(d="filter"),a=b.currentStyle[d.replace(/\-(\w)/g,function(b,a){return a.toUpperCase()})],
11
+ d==="filter"&&(a=a.replace(/alpha\(opacity=([0-9]+)\)/,function(b,a){return a/100})),a===""?1:a)},this.adapterRun=function(b,d){var a={width:"clientWidth",height:"clientHeight"}[d];if(a)return b.style.zoom=1,b[a]-2*parseInt(HighchartsAdapter._getStyle(b,"padding"),10)};if(!Array.prototype.forEach)this.each=function(b,d){for(var a=0,c=b.length;a<c;a++)if(d.call(b[a],b[a],a,b)===!1)return a};if(!Array.prototype.indexOf)this.inArray=function(b,d){var a,c=0;if(d)for(a=d.length;c<a;c++)if(d[c]===b)return c;
12
+ return-1};if(!Array.prototype.filter)this.grep=function(b,d){for(var a=[],c=0,h=b.length;c<h;c++)d(b[c],c)&&a.push(b[c]);return a};n=function(b,c,a){this.options=c;this.elem=b;this.prop=a};n.prototype={update:function(){var b;b=this.paths;var d=this.elem,a=d.element;b&&a?d.attr("d",c.step(b[0],b[1],this.now,this.toD)):d.attr?a&&d.attr(this.prop,this.now):(b={},b[d]=this.now+this.unit,Highcharts.css(d,b));this.options.step&&this.options.step.call(this.elem,this.now,this)},custom:function(b,c,a){var e=
13
+ this,h=function(a){return e.step(a)},f;this.startTime=+new Date;this.start=b;this.end=c;this.unit=a;this.now=this.start;this.pos=this.state=0;h.elem=this.elem;h()&&m.push(h)===1&&(q=setInterval(function(){for(f=0;f<m.length;f++)m[f]()||m.splice(f--,1);m.length||clearInterval(q)},13))},step:function(b){var c=+new Date,a;a=this.options;var e;if(this.elem.stopAnimation)a=!1;else if(b||c>=a.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();b=this.options.curAnim[this.prop]=
14
+ !0;for(e in a.curAnim)a.curAnim[e]!==!0&&(b=!1);b&&a.complete&&a.complete.call(this.elem);a=!1}else e=c-this.startTime,this.state=e/a.duration,this.pos=a.easing(e,0,1,a.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update(),a=!0;return a}};this.animate=function(b,d,a){var e,h="",f,i,g;b.stopAnimation=!1;if(typeof a!=="object"||a===null)e=arguments,a={duration:e[2],easing:e[3],complete:e[4]};if(typeof a.duration!=="number")a.duration=400;a.easing=Math[a.easing]||Math.easeInOutSine;
15
+ a.curAnim=Highcharts.extend({},d);for(g in d)i=new n(b,a,g),f=null,g==="d"?(i.paths=c.init(b,b.d,d.d),i.toD=d.d,e=0,f=1):b.attr?e=b.attr(g):(e=parseFloat(HighchartsAdapter._getStyle(b,g))||0,g!=="opacity"&&(h="px")),f||(f=parseFloat(d[g])),i.custom(e,f,h)}},_getStyle:function(c,b){return window.getComputedStyle(c).getPropertyValue(b)},getScript:function(c,b){var d=l.getElementsByTagName("head")[0],a=l.createElement("script");a.type="text/javascript";a.src=c;a.onload=b;d.appendChild(a)},inArray:function(c,
16
+ b){return b.indexOf?b.indexOf(c):p.indexOf.call(b,c)},adapterRun:function(c,b){return parseInt(HighchartsAdapter._getStyle(c,b),10)},grep:function(c,b){return p.filter.call(c,b)},map:function(c,b){for(var d=[],a=0,e=c.length;a<e;a++)d[a]=b.call(c[a],c[a],a,c);return d},offset:function(c){for(var b=0,d=0;c;)b+=c.offsetLeft,d+=c.offsetTop,c=c.offsetParent;return{left:b,top:d}},addEvent:function(c,b,d){o(c).bind(b,d)},removeEvent:function(c,b,d){o(c).unbind(b,d)},fireEvent:function(c,b,d,a){var e;l.createEvent&&
17
+ (c.dispatchEvent||c.fireEvent)?(e=l.createEvent("Events"),e.initEvent(b,!0,!0),e.target=c,Highcharts.extend(e,d),c.dispatchEvent?c.dispatchEvent(e):c.fireEvent(b,e)):c.HCExtended===!0&&(d=d||{},c.trigger(b,d));d&&d.defaultPrevented&&(a=null);a&&a(d)},washMouseEvent:function(c){return c},stop:function(c){c.stopAnimation=!0},each:function(c,b){return Array.prototype.forEach.call(c,b)}}}();
@@ -0,0 +1,9 @@
1
+ function createGraphElement(elementType) {
2
+ var graphContainer = document.getElementById("graph_container");
3
+
4
+ if(graphContainer) {
5
+ var graphElement = document.createElement(elementType);
6
+ graphElement.setAttribute("id", "graph");
7
+ graphContainer.appendChild(graphElement);
8
+ }
9
+ }
@@ -0,0 +1,41 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
3
+ <head>
4
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
5
+ <meta content='en' http-equiv='Content-Language' />
6
+ <title>metrics</title>
7
+ <style>
8
+ <%= inline_css("css/reset.css") %>
9
+ <%= inline_css("css/buttons.css") %>
10
+ <%= inline_css("css/integrity.css") %>
11
+ <%= inline_css("css/default.css") %>
12
+ <%= inline_css("css/bluff.css") %>
13
+ </style>
14
+ <link REL="SHORTCUT ICON" HREF="/favicon.ico">
15
+ <% if not @disable_js %>
16
+ <script language="javascript" src="../javascripts/utils.js" type="text/javascript"></script>
17
+ <script language="javascript" src="../javascripts/js-class.js" type="text/javascript"></script>
18
+ <script language="javascript" src="../javascripts/bluff-min.js" type="text/javascript"></script>
19
+ <script language="javascript" src="../javascripts/excanvas.js" type="text/javascript"></script>
20
+ <script language="javascript" src="../javascripts/standalone-framework.js" type="text/javascript"></script>
21
+ <script language="javascript" src="../javascripts/highcharts.js" type="text/javascript"></script>
22
+ <% end %>
23
+ </head>
24
+ <body>
25
+ <div id='header'>
26
+ <h1><a href="/">metrics</a> | <a href="index.html"><%= @name %></a></h1>
27
+ <address class='watermark'>
28
+ built with
29
+ <a href='<%= MetricFu.metric_url %>'><%= MetricFu.metric_name %></a>
30
+ </address>
31
+ </div>
32
+ <div id='content'>
33
+ <%= @html %>
34
+ </div>
35
+
36
+ <% if not @disable_js %>
37
+ <% graph_engine = MetricFu.configuration.graph_engine.to_s %>
38
+ <script language="javascript" src="../javascripts/<%= graph_engine %>_graph.js" type="text/javascript"></script>
39
+ <% end %>
40
+ </body>
41
+ </html>
@@ -0,0 +1,86 @@
1
+ require "fileutils"
2
+ MetricFu.lib_require { "templates/template" }
3
+ MetricFu.lib_require { "templates/report" }
4
+
5
+ # The MetricsTemplate class is the included template used by the HTML formatter.
6
+ # The only requirement for a template class is that it provides a #write method
7
+ # to actually write out the template.
8
+ module MetricFu
9
+ class Templates::MetricsTemplate < MetricFu::Template
10
+ attr_accessor :result, :per_file_data, :formatter, :metrics, :name, :html
11
+
12
+ def write
13
+ self.name = MetricFu.report_name
14
+ self.metrics = {}
15
+
16
+ copy_javascripts
17
+
18
+ result.each_pair do |section, contents|
19
+ write_section(section, contents)
20
+ end
21
+
22
+ write_index
23
+ write_file_data
24
+ end
25
+
26
+ def html_filename(file)
27
+ file = Digest::SHA1.hexdigest(file)[0..29]
28
+ "#{file.gsub(%r{/}, '_')}.html"
29
+ end
30
+
31
+ private
32
+
33
+ def copy_javascripts
34
+ FileUtils.mkdir_p(File.join(output_directory, "javascripts"))
35
+ Dir[File.join(template_directory, "javascripts", "*")].each do |f|
36
+ FileUtils.cp(f, File.join(output_directory, "javascripts", File.basename(f)))
37
+ end
38
+ end
39
+
40
+ def write_section(section, contents)
41
+ if template_exists?(section)
42
+ create_instance_var(section, contents)
43
+ metrics[section] = contents
44
+ create_instance_var(:per_file_data, per_file_data)
45
+ mf_debug "Generating html for section #{section} with #{template(section)} for result #{result.class}"
46
+ self.html = erbify(section)
47
+ layout = erbify("layout")
48
+ dir = "results"
49
+ FileUtils.mkdir_p(File.join(output_directory, dir))
50
+ fn = output_filename(section)
51
+ formatter.write_template(layout, "#{dir}/#{fn}")
52
+ else
53
+ mf_debug "no template for section #{section} with #{template(section)} for result #{result.class}"
54
+ end
55
+ end
56
+
57
+ def write_index
58
+ # Instance variables we need should already be created from above
59
+ if template_exists?("index")
60
+ self.html = erbify("index")
61
+ layout = erbify("layout")
62
+ fn = output_filename("index")
63
+ formatter.write_template(layout, fn)
64
+ else
65
+ mf_debug "no template for section index for result #{result.class}"
66
+ end
67
+ end
68
+
69
+ def write_file_data
70
+ per_file_data.each_pair do |file, lines|
71
+ next if file.to_s.empty?
72
+ next unless File.file?(file)
73
+ report = MetricFu::Templates::Report.new(file, lines).render
74
+
75
+ dir = "codes/" + File.dirname(file)
76
+ FileUtils.mkdir_p(File.join(output_directory, dir))
77
+ fn = File.basename(file) + ".html"
78
+ formatter.write_template(report, "#{dir}/#{fn}")
79
+ end
80
+ end
81
+
82
+ def template_directory
83
+ File.dirname(__FILE__)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,31 @@
1
+ <html>
2
+ <head>
3
+ <style>
4
+ <%= inline_css('css/syntax.css') %>
5
+ </style>
6
+ <title>Analyzed File Report</title>
7
+ </head>
8
+ <body>
9
+ <table cellpadding='0' cellspacing='0' class='ruby'>
10
+ <% @data.each_with_index do |line, idx| %>
11
+ <% line_number = (idx + 1).to_s %>
12
+ <tr>
13
+ <td valign='top'>
14
+ <% if @lines.has_key?(line_number) %>
15
+ <ul>
16
+ <% @lines[line_number].each do |problem| %>
17
+ <li><%= "#{problem[:description]} &raquo; #{problem[:type]}" %></li>
18
+ <% end %>
19
+ </ul>
20
+ <% else %>
21
+ &nbsp;
22
+ <% end %>
23
+ </td>
24
+ <td valign='top'>
25
+ <%= line_for_display(line, line_number) %>
26
+ </td>
27
+ </tr>
28
+ <% end %>
29
+ </table>
30
+ </body>
31
+ </html>
@@ -0,0 +1,41 @@
1
+ MetricFu.lib_require { "formatter/syntax" }
2
+ MetricFu.lib_require { "templates/template" }
3
+
4
+ # Creates an HTML document for a given analyzed file,
5
+ # with scored metrics annotating the relevant line.
6
+ module MetricFu
7
+ module Templates
8
+ class Report < MetricFu::Template
9
+ # @param file [String] the analyzed file to annotate
10
+ # @param lines [Hash] of line number [String] keyed to an list [[Array] of metrics for that line. Each metric in the list is a hash containing the keys :type => metric_name, :descrption => metric_score
11
+ # @example file and lines
12
+ # file: "lib/metric_fu/gem_version.rb
13
+ # lines: {"30"=>[{:type=>:flog, :description=>"Score of 22.43"}], "42"=>[{:type=>:flog, :description=>"Score of 8.64"}]}
14
+ def initialize(file, lines)
15
+ @file = file
16
+ @lines = lines
17
+ @data = File.open(file, "rb") { |f| f.readlines }
18
+ end
19
+
20
+ def render
21
+ erbify("report")
22
+ end
23
+
24
+ def convert_ruby_to_html(ruby_text, line_number)
25
+ MetricFu::Formatter::Syntax.new.highlight(ruby_text, line_number)
26
+ end
27
+
28
+ def line_for_display(line, line_number)
29
+ if MetricFu::Formatter::Templates.option("syntax_highlighting")
30
+ line_for_display = convert_ruby_to_html(line, line_number)
31
+ else
32
+ "<a name='n#{line_number}' href='n#{line_number}'>#{line_number}</a>#{line}"
33
+ end
34
+ end
35
+
36
+ def template_directory
37
+ File.dirname(__FILE__)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,247 @@
1
+ require "erb"
2
+ module MetricFu
3
+ class Template
4
+ attr_accessor :output_directory
5
+
6
+ def output_directory
7
+ @output_directory || MetricFu::Io::FileSystem.directory("output_directory")
8
+ end
9
+
10
+ # Renders a partial and add optional instance variables to the template
11
+ # @param name <String> name of partial, omitting leading underscore (_)
12
+ # @param instance_variables <Hash> of instance variable
13
+ # names and values to set
14
+ def render_partial(name, instance_variables = {})
15
+ create_instance_vars(instance_variables)
16
+ erbify("_#{name}")
17
+ end
18
+
19
+ private
20
+
21
+ # Creates a new erb evaluated result from the passed in section.
22
+ #
23
+ # @param section String
24
+ # The section name of
25
+ #
26
+ # @return String
27
+ # The erb evaluated string
28
+ def erbify(section)
29
+ template_file = template(section)
30
+ erb = erb_template_source(template_file)
31
+ erb.result(binding)
32
+ rescue => e
33
+ message = "Error: #{e.class}; message #{e.message}. "
34
+ message << "Failed evaluating erb template "
35
+ message << "for section #{section} and template #{template_file}."
36
+ raise message
37
+ end
38
+
39
+ def erb_template_source(template_file)
40
+ erb_doc = File.read(template_file)
41
+ erb = ERB.new(erb_doc)
42
+ erb.filename = template_file
43
+ erb
44
+ end
45
+
46
+ # Copies an instance variable mimicing the name of the section
47
+ # we are trying to render, with a value equal to the passed in
48
+ # constant. Allows the concrete template classes to refer to
49
+ # that instance variable from their ERB rendering
50
+ #
51
+ # @param section String
52
+ # The name of the instance variable to create
53
+ #
54
+ # @param contents Object
55
+ # The value to set as the value of the created instance
56
+ # variable
57
+ def create_instance_var(section, contents)
58
+ instance_variable_set("@#{section}", contents)
59
+ end
60
+
61
+ def create_instance_vars(variables)
62
+ variables.each { |variable| create_instance_var(*variable) }
63
+ end
64
+
65
+ # Generates the filename of the template file to load and
66
+ # evaluate. In this case, the path to the template directory +
67
+ # the section name + .html.erb
68
+ #
69
+ # @param section String
70
+ # A section of the template to render
71
+ #
72
+ # @return String
73
+ # A file path
74
+ def template(section)
75
+ # TODO: each MetricFu::Metric should know about its templates
76
+ # This class knows too much about the filesystem structure
77
+ if MetricFu::Metric.enabled_metrics.map(&:name).include?(section) # expects a symbol
78
+ metric_template_path(section.to_s)
79
+ else
80
+ File.join(template_directory, section.to_s + ".html.erb")
81
+ end
82
+ end
83
+
84
+ def metric_template_path(metric)
85
+ File.join(MetricFu.metrics_dir, metric, "report.html.erb")
86
+ end
87
+
88
+ # Determines whether a template file exists for a given section
89
+ # of the full template.
90
+ #
91
+ # @param section String
92
+ # The section of the template to check against
93
+ #
94
+ # @return Boolean
95
+ # Does a template file exist for this section or not?
96
+ def template_exists?(section)
97
+ File.exist?(template(section))
98
+ end
99
+
100
+ # Returns the filename that the template will render into for
101
+ # a given section. In this case, the section name + '.html'
102
+ #
103
+ # @param section String
104
+ # A section of the template to render
105
+ #
106
+ # @return String
107
+ # The output filename
108
+ def output_filename(section)
109
+ section.to_s + ".html"
110
+ end
111
+
112
+ # Returns the contents of a given css file in order to
113
+ # render it inline into a template.
114
+ #
115
+ # @param css String
116
+ # The name of a css file to open
117
+ #
118
+ # @return String
119
+ # The contents of the css file
120
+ def inline_css(css)
121
+ css_file = File.join(MetricFu.lib_dir, "templates", css)
122
+ MetricFu::Utility.binread(css_file)
123
+ end
124
+
125
+ # Provides a link to open a file through the textmate protocol
126
+ # on Darwin, or otherwise, a simple file link.
127
+ #
128
+ # @param name String
129
+ #
130
+ # @param line Integer
131
+ # The line number to link to, if textmate is available. Defaults
132
+ # to nil
133
+ #
134
+ # @return String
135
+ # An anchor link to a textmate reference or a file reference
136
+ def link_to_filename(name, line = nil, link_content = nil)
137
+ # href = file_url(name, line)
138
+ href = "../codes/#{name}.html"
139
+ href += "#n#{line}" if line
140
+ link_text = link_content(name, line, link_content)
141
+ "<a href='#{href}'>#{link_text}</a>"
142
+ end
143
+
144
+ def round_to_tenths(decimal)
145
+ decimal = 0.0 if decimal.to_s.eql?("NaN")
146
+ (decimal * 10).round / 10.0
147
+ end
148
+
149
+ def link_content(name, line = nil, link_content = nil) # :nodoc:
150
+ if link_content
151
+ link_content
152
+ elsif line
153
+ "#{name}:#{line}"
154
+ else
155
+ name
156
+ end
157
+ end
158
+
159
+ def display_location(location)
160
+ class_name, method_name = location.fetch("class_name"), location.fetch("method_name")
161
+ str = ""
162
+ str += link_to_filename(location.fetch("file_name"), location.fetch("line_number"))
163
+ str += " : " if method_name || class_name
164
+ if method_name
165
+ str += "#{method_name}"
166
+ else
167
+ # TODO HOTSPOTS BUG ONLY exists on move over to metric_fu
168
+ if class_name.is_a?(String)
169
+ str += "#{class_name}"
170
+ end
171
+ end
172
+ str
173
+ end
174
+
175
+ def file_url(name, line) # :nodoc:
176
+ return "" unless name
177
+ filename = complete_file_path(name)
178
+
179
+ if render_as_txmt_protocol?
180
+ "txmt://open/?url=file://#{filename}" << (line ? "&line=#{line}" : "")
181
+ else
182
+ link_prefix = MetricFu.configuration.templates_option("link_prefix")
183
+ if link_prefix == MetricFu::Templates::Configuration::FILE_PREFIX
184
+ path = filename
185
+ else
186
+ path = name.gsub(/:.*$/, "")
187
+ end
188
+ "#{link_prefix}/#{path}"
189
+ end
190
+ end
191
+
192
+ def complete_file_path(filename)
193
+ File.expand_path(filename)
194
+ end
195
+
196
+ def render_as_txmt_protocol? # :nodoc:
197
+ if MetricFu.configuration.osx?
198
+ !MetricFu.configuration.templates_option("darwin_txmt_protocol_no_thanks")
199
+ else
200
+ false
201
+ end
202
+ end
203
+
204
+ # Provides a brain dead way to cycle between two values during
205
+ # an iteration of some sort. Pass in the first_value, the second_value,
206
+ # and the cardinality of the iteration.
207
+ #
208
+ # @param first_value Object
209
+ #
210
+ # @param second_value Object
211
+ #
212
+ # @param iteration Integer
213
+ # The number of times through the iteration.
214
+ #
215
+ # @return Object
216
+ # The first_value if iteration is even. The second_value if
217
+ # iteration is odd.
218
+ def cycle(first_value, second_value, iteration)
219
+ return first_value if iteration % 2 == 0
220
+ second_value
221
+ end
222
+
223
+ # available in the erb template
224
+ # as it's processed in the context of
225
+ # the binding of this class
226
+ def metric_links
227
+ @metrics.keys.map { |metric| metric_link(metric.to_s) }
228
+ end
229
+
230
+ def metric_link(metric)
231
+ metric_summary = Gem.loaded_specs[metric.to_s]&.summary
232
+ <<-LINK
233
+ <a href="results/#{metric}.html" title="#{metric_summary}">
234
+ #{snake_case_to_title_case(metric)}
235
+ </a>
236
+ LINK
237
+ end
238
+
239
+ def snake_case_to_title_case(string)
240
+ string.split("_").collect { |word| word[0] = word[0..0].upcase; word }.join(" ")
241
+ end
242
+
243
+ def template_directory
244
+ fail "subclasses must specify template_directory. Usually File.dirname(__FILE__)"
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,79 @@
1
+ require "yaml"
2
+ require "fileutils"
3
+ module MetricFu
4
+ module Utility
5
+ module_function
6
+
7
+ ESCAPE_CODES_PATTERN = Regexp.new('\e\[(?:\d;)?\d{1,2}m')
8
+
9
+ # Removes non-ASCII characters
10
+ def clean_ascii_text(text)
11
+ if text.respond_to?(:encode)
12
+ # avoids invalid multi-byte escape error
13
+ ascii_text = text.encode("ASCII", invalid: :replace, undef: :replace, replace: "")
14
+ # see http://www.ruby-forum.com/topic/183413
15
+ pattern = Regexp.new('[\x80-\xff]', nil, "n")
16
+ ascii_text.gsub(pattern, "")
17
+ else
18
+ text
19
+ end
20
+ end
21
+
22
+ def stringify_keys(hash)
23
+ result = {}
24
+ hash.each do |key, value|
25
+ result[key.to_s] = value
26
+ end
27
+ result
28
+ end
29
+
30
+ def strip_escape_codes(text)
31
+ text.gsub(ESCAPE_CODES_PATTERN, "")
32
+ end
33
+
34
+ def rm_rf(*args)
35
+ FileUtils.rm_rf(*args)
36
+ end
37
+
38
+ def mkdir_p(*args)
39
+ FileUtils.mkdir_p(*args)
40
+ end
41
+
42
+ def glob(*args)
43
+ Dir.glob(*args)
44
+ end
45
+
46
+ def load_yaml(file)
47
+ YAML.load_file(file)
48
+ end
49
+
50
+ def binread(file)
51
+ File.binread(file)
52
+ end
53
+
54
+ # From episode 029 of Ruby Tapas by Avdi
55
+ # https://rubytapas.dpdcart.com/subscriber/post?id=88
56
+ def capture_output(stream = STDOUT, &_block)
57
+ old_stdout = stream.clone
58
+ pipe_r, pipe_w = IO.pipe
59
+ pipe_r.sync = true
60
+ output = ""
61
+ reader = Thread.new do
62
+ begin
63
+ loop do
64
+ output << pipe_r.readpartial(1024)
65
+ end
66
+ rescue EOFError
67
+ end
68
+ end
69
+ stream.reopen(pipe_w)
70
+ yield
71
+ ensure
72
+ stream.reopen(old_stdout)
73
+ pipe_w.close
74
+ reader.join
75
+ pipe_r.close
76
+ return output
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,9 @@
1
+ module MetricFu
2
+ class Version
3
+ MAJOR = "4"
4
+ MINOR = "14"
5
+ PATCH = "0"
6
+ PRE = ""
7
+ end
8
+ VERSION = [Version::MAJOR, Version::MINOR, Version::PATCH].join(".")
9
+ end