code_metric_fu 4.14.0

Sign up to get free protection for your applications and to get access to all the features.
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