code_metric_fu 4.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +28 -0
- data/.metrics +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +15 -0
- data/.rubocop_todo.yml +69 -0
- data/.simplecov +74 -0
- data/.travis.yml +22 -0
- data/.yardopts +4 -0
- data/AUTHORS +12 -0
- data/CONTRIBUTING.md +47 -0
- data/CONTRIBUTORS +76 -0
- data/DEV.md +76 -0
- data/Gemfile +74 -0
- data/Guardfile +30 -0
- data/HISTORY.md +705 -0
- data/MIT-LICENSE +22 -0
- data/README.md +299 -0
- data/Rakefile +27 -0
- data/TODO.md +118 -0
- data/appveyor.yml +31 -0
- data/bin/metric_fu +9 -0
- data/bin/mf-cane +10 -0
- data/bin/mf-churn +10 -0
- data/bin/mf-flay +10 -0
- data/bin/mf-reek +10 -0
- data/bin/mf-roodi +10 -0
- data/bin/mf-saikuro +10 -0
- data/certs/bf4.pem +22 -0
- data/checksum/.gitkeep +0 -0
- data/checksum/metric_fu-4.10.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.11.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.11.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.11.2.gem.sha512 +1 -0
- data/checksum/metric_fu-4.11.3.gem.sha512 +1 -0
- data/checksum/metric_fu-4.11.4.gem.sha512 +1 -0
- data/checksum/metric_fu-4.12.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.2.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.2.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.3.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.3.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.4.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.4.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.4.2.gem.sha512 +1 -0
- data/checksum/metric_fu-4.4.3.gem.sha512 +1 -0
- data/checksum/metric_fu-4.4.4.gem.sha512 +1 -0
- data/checksum/metric_fu-4.5.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.5.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.5.2.gem.sha512 +1 -0
- data/checksum/metric_fu-4.6.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.7.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.7.1.gem.sha512 +1 -0
- data/checksum/metric_fu-4.7.2.gem.sha512 +1 -0
- data/checksum/metric_fu-4.7.3.gem.sha512 +1 -0
- data/checksum/metric_fu-4.7.4.gem.sha512 +1 -0
- data/checksum/metric_fu-4.8.0.gem.sha512 +1 -0
- data/checksum/metric_fu-4.9.0.gem.sha512 +1 -0
- data/config/roodi_config.yml +22 -0
- data/config/rubocop.yml +269 -0
- data/gem_tasks/build.rake +197 -0
- data/gem_tasks/rubocop.rake +10 -0
- data/gem_tasks/usage_test.rake +19 -0
- data/gem_tasks/yard.rake +24 -0
- data/lib/metric_fu/calculate.rb +10 -0
- data/lib/metric_fu/cli/client.rb +26 -0
- data/lib/metric_fu/cli/helper.rb +80 -0
- data/lib/metric_fu/cli/parser.rb +138 -0
- data/lib/metric_fu/configuration.rb +150 -0
- data/lib/metric_fu/constantize.rb +57 -0
- data/lib/metric_fu/data_structures/line_numbers.rb +112 -0
- data/lib/metric_fu/data_structures/location.rb +110 -0
- data/lib/metric_fu/data_structures/sexp_node.rb +107 -0
- data/lib/metric_fu/environment.rb +129 -0
- data/lib/metric_fu/errors/analysis_error.rb +4 -0
- data/lib/metric_fu/formatter/html.rb +96 -0
- data/lib/metric_fu/formatter/syntax.rb +45 -0
- data/lib/metric_fu/formatter/yaml.rb +18 -0
- data/lib/metric_fu/formatter.rb +40 -0
- data/lib/metric_fu/gem_run.rb +70 -0
- data/lib/metric_fu/gem_version.rb +92 -0
- data/lib/metric_fu/generator.rb +135 -0
- data/lib/metric_fu/io.rb +132 -0
- data/lib/metric_fu/loader.rb +105 -0
- data/lib/metric_fu/logger.rb +62 -0
- data/lib/metric_fu/logging/mf_debugger.rb +23 -0
- data/lib/metric_fu/metric.rb +143 -0
- data/lib/metric_fu/metrics/cane/generator.rb +95 -0
- data/lib/metric_fu/metrics/cane/grapher.rb +37 -0
- data/lib/metric_fu/metrics/cane/metric.rb +34 -0
- data/lib/metric_fu/metrics/cane/report.html.erb +87 -0
- data/lib/metric_fu/metrics/cane/violations.rb +46 -0
- data/lib/metric_fu/metrics/churn/generator.rb +37 -0
- data/lib/metric_fu/metrics/churn/hotspot.rb +43 -0
- data/lib/metric_fu/metrics/churn/metric.rb +29 -0
- data/lib/metric_fu/metrics/churn/report.html.erb +58 -0
- data/lib/metric_fu/metrics/flay/generator.rb +51 -0
- data/lib/metric_fu/metrics/flay/grapher.rb +37 -0
- data/lib/metric_fu/metrics/flay/hotspot.rb +52 -0
- data/lib/metric_fu/metrics/flay/metric.rb +28 -0
- data/lib/metric_fu/metrics/flay/report.html.erb +29 -0
- data/lib/metric_fu/metrics/flog/generator.rb +113 -0
- data/lib/metric_fu/metrics/flog/grapher.rb +77 -0
- data/lib/metric_fu/metrics/flog/hotspot.rb +46 -0
- data/lib/metric_fu/metrics/flog/metric.rb +29 -0
- data/lib/metric_fu/metrics/flog/report.html.erb +50 -0
- data/lib/metric_fu/metrics/hotspots/analysis/analyzed_problems.rb +34 -0
- data/lib/metric_fu/metrics/hotspots/analysis/analyzer_tables.rb +114 -0
- data/lib/metric_fu/metrics/hotspots/analysis/grouping.rb +23 -0
- data/lib/metric_fu/metrics/hotspots/analysis/groupings.rb +12 -0
- data/lib/metric_fu/metrics/hotspots/analysis/problems.rb +20 -0
- data/lib/metric_fu/metrics/hotspots/analysis/ranked_problem_location.rb +70 -0
- data/lib/metric_fu/metrics/hotspots/analysis/ranking.rb +29 -0
- data/lib/metric_fu/metrics/hotspots/analysis/rankings.rb +91 -0
- data/lib/metric_fu/metrics/hotspots/analysis/record.rb +32 -0
- data/lib/metric_fu/metrics/hotspots/analysis/scoring_strategies.rb +24 -0
- data/lib/metric_fu/metrics/hotspots/analysis/table.rb +67 -0
- data/lib/metric_fu/metrics/hotspots/generator.rb +40 -0
- data/lib/metric_fu/metrics/hotspots/hotspot.rb +87 -0
- data/lib/metric_fu/metrics/hotspots/hotspot_analyzer.rb +61 -0
- data/lib/metric_fu/metrics/hotspots/metric.rb +20 -0
- data/lib/metric_fu/metrics/hotspots/report.html.erb +60 -0
- data/lib/metric_fu/metrics/rails_best_practices/generator.rb +47 -0
- data/lib/metric_fu/metrics/rails_best_practices/grapher.rb +38 -0
- data/lib/metric_fu/metrics/rails_best_practices/metric.rb +31 -0
- data/lib/metric_fu/metrics/rails_best_practices/report.html.erb +22 -0
- data/lib/metric_fu/metrics/rcov/external_client.rb +22 -0
- data/lib/metric_fu/metrics/rcov/generator.rb +75 -0
- data/lib/metric_fu/metrics/rcov/grapher.rb +37 -0
- data/lib/metric_fu/metrics/rcov/hotspot.rb +46 -0
- data/lib/metric_fu/metrics/rcov/metric.rb +61 -0
- data/lib/metric_fu/metrics/rcov/rcov_format_coverage.rb +149 -0
- data/lib/metric_fu/metrics/rcov/rcov_line.rb +48 -0
- data/lib/metric_fu/metrics/rcov/report.html.erb +40 -0
- data/lib/metric_fu/metrics/rcov/simplecov_formatter.rb +74 -0
- data/lib/metric_fu/metrics/reek/generator.rb +97 -0
- data/lib/metric_fu/metrics/reek/grapher.rb +55 -0
- data/lib/metric_fu/metrics/reek/hotspot.rb +95 -0
- data/lib/metric_fu/metrics/reek/metric.rb +26 -0
- data/lib/metric_fu/metrics/reek/report.html.erb +35 -0
- data/lib/metric_fu/metrics/roodi/generator.rb +41 -0
- data/lib/metric_fu/metrics/roodi/grapher.rb +37 -0
- data/lib/metric_fu/metrics/roodi/hotspot.rb +39 -0
- data/lib/metric_fu/metrics/roodi/metric.rb +24 -0
- data/lib/metric_fu/metrics/roodi/report.html.erb +22 -0
- data/lib/metric_fu/metrics/saikuro/generator.rb +145 -0
- data/lib/metric_fu/metrics/saikuro/hotspot.rb +51 -0
- data/lib/metric_fu/metrics/saikuro/metric.rb +31 -0
- data/lib/metric_fu/metrics/saikuro/parsing_element.rb +37 -0
- data/lib/metric_fu/metrics/saikuro/report.html.erb +71 -0
- data/lib/metric_fu/metrics/saikuro/scratch_file.rb +108 -0
- data/lib/metric_fu/metrics/stats/generator.rb +82 -0
- data/lib/metric_fu/metrics/stats/grapher.rb +40 -0
- data/lib/metric_fu/metrics/stats/hotspot.rb +35 -0
- data/lib/metric_fu/metrics/stats/metric.rb +28 -0
- data/lib/metric_fu/metrics/stats/report.html.erb +44 -0
- data/lib/metric_fu/reporter.rb +37 -0
- data/lib/metric_fu/reporting/graphs/graph.rb +69 -0
- data/lib/metric_fu/reporting/graphs/grapher.rb +66 -0
- data/lib/metric_fu/reporting/result.rb +59 -0
- data/lib/metric_fu/run.rb +82 -0
- data/lib/metric_fu/tasks/metric_fu.rake +54 -0
- data/lib/metric_fu/templates/_gem_info.html.erb +8 -0
- data/lib/metric_fu/templates/_graph.html.erb +2 -0
- data/lib/metric_fu/templates/_report_footer.html.erb +1 -0
- data/lib/metric_fu/templates/configuration.rb +25 -0
- data/lib/metric_fu/templates/css/bluff.css +15 -0
- data/lib/metric_fu/templates/css/buttons.css +82 -0
- data/lib/metric_fu/templates/css/default.css +43 -0
- data/lib/metric_fu/templates/css/integrity.css +337 -0
- data/lib/metric_fu/templates/css/rcov.css +32 -0
- data/lib/metric_fu/templates/css/reset.css +7 -0
- data/lib/metric_fu/templates/css/syntax.css +19 -0
- data/lib/metric_fu/templates/index.html.erb +13 -0
- data/lib/metric_fu/templates/javascripts/bluff-min.js +1 -0
- data/lib/metric_fu/templates/javascripts/bluff_graph.js +15 -0
- data/lib/metric_fu/templates/javascripts/excanvas.js +35 -0
- data/lib/metric_fu/templates/javascripts/highcharts.js +294 -0
- data/lib/metric_fu/templates/javascripts/highcharts_graph.js +38 -0
- data/lib/metric_fu/templates/javascripts/js-class.js +1 -0
- data/lib/metric_fu/templates/javascripts/standalone-framework.js +17 -0
- data/lib/metric_fu/templates/javascripts/utils.js +9 -0
- data/lib/metric_fu/templates/layout.html.erb +41 -0
- data/lib/metric_fu/templates/metrics_template.rb +86 -0
- data/lib/metric_fu/templates/report.html.erb +31 -0
- data/lib/metric_fu/templates/report.rb +41 -0
- data/lib/metric_fu/templates/template.rb +247 -0
- data/lib/metric_fu/utility.rb +79 -0
- data/lib/metric_fu/version.rb +9 -0
- data/lib/metric_fu.rb +143 -0
- data/metric_fu.gemspec +72 -0
- data/spec/capture_warnings.rb +55 -0
- data/spec/cli/helper_spec.rb +165 -0
- data/spec/dummy/.gitignore +1 -0
- data/spec/dummy/.gitkeep +0 -0
- data/spec/dummy/.metrics +4 -0
- data/spec/dummy/lib/.gitkeep +0 -0
- data/spec/dummy/lib/bad_encoding.rb +6 -0
- data/spec/dummy/spec/.gitkeep +0 -0
- data/spec/fixtures/20090630.yml +7922 -0
- data/spec/fixtures/coverage-153.rb +11 -0
- data/spec/fixtures/coverage.rb +13 -0
- data/spec/fixtures/exit0.sh +3 -0
- data/spec/fixtures/exit1.sh +3 -0
- data/spec/fixtures/hotspots/flog.yml +86 -0
- data/spec/fixtures/hotspots/generator.yml +47 -0
- data/spec/fixtures/hotspots/generator_analysis.yml +53 -0
- data/spec/fixtures/hotspots/reek.yml +14 -0
- data/spec/fixtures/hotspots/roodi.yml +13 -0
- data/spec/fixtures/hotspots/saikuro.yml +27 -0
- data/spec/fixtures/hotspots/several_metrics.yml +47 -0
- data/spec/fixtures/hotspots/stats.yml +4 -0
- data/spec/fixtures/hotspots/three_metrics_on_same_file.yml +36 -0
- data/spec/fixtures/line_numbers/foo.rb +33 -0
- data/spec/fixtures/line_numbers/module.rb +11 -0
- data/spec/fixtures/line_numbers/module_surrounds_class.rb +15 -0
- data/spec/fixtures/line_numbers/two_classes.rb +11 -0
- data/spec/fixtures/metric_missing.yml +1 -0
- data/spec/fixtures/rcov_output.txt +135 -0
- data/spec/fixtures/saikuro/app/controllers/sessions_controller.rb_cyclo.html +10 -0
- data/spec/fixtures/saikuro/app/controllers/users_controller.rb_cyclo.html +16 -0
- data/spec/fixtures/saikuro/index_cyclo.html +155 -0
- data/spec/fixtures/saikuro_sfiles/thing.rb_cyclo.html +11 -0
- data/spec/metric_fu/calculate_spec.rb +21 -0
- data/spec/metric_fu/configuration_spec.rb +90 -0
- data/spec/metric_fu/data_structures/line_numbers_spec.rb +63 -0
- data/spec/metric_fu/data_structures/location_spec.rb +110 -0
- data/spec/metric_fu/formatter/configuration_spec.rb +44 -0
- data/spec/metric_fu/formatter/html_spec.rb +138 -0
- data/spec/metric_fu/formatter/yaml_spec.rb +61 -0
- data/spec/metric_fu/formatter_spec.rb +49 -0
- data/spec/metric_fu/gem_version_spec.rb +12 -0
- data/spec/metric_fu/generator_spec.rb +130 -0
- data/spec/metric_fu/loader_spec.rb +10 -0
- data/spec/metric_fu/metric_spec.rb +46 -0
- data/spec/metric_fu/metrics/cane/configuration_spec.rb +22 -0
- data/spec/metric_fu/metrics/cane/generator_spec.rb +184 -0
- data/spec/metric_fu/metrics/churn/configuration_spec.rb +13 -0
- data/spec/metric_fu/metrics/churn/generator_spec.rb +64 -0
- data/spec/metric_fu/metrics/flay/configuration_spec.rb +13 -0
- data/spec/metric_fu/metrics/flay/generator_spec.rb +105 -0
- data/spec/metric_fu/metrics/flay/grapher_spec.rb +57 -0
- data/spec/metric_fu/metrics/flog/configuration_spec.rb +18 -0
- data/spec/metric_fu/metrics/flog/generator_spec.rb +77 -0
- data/spec/metric_fu/metrics/flog/grapher_spec.rb +107 -0
- data/spec/metric_fu/metrics/hotspots/analysis/analyzed_problems_spec.rb +104 -0
- data/spec/metric_fu/metrics/hotspots/analysis/analyzer_tables_spec.rb +71 -0
- data/spec/metric_fu/metrics/hotspots/analysis/ranking_spec.rb +30 -0
- data/spec/metric_fu/metrics/hotspots/analysis/rankings_spec.rb +97 -0
- data/spec/metric_fu/metrics/hotspots/analysis/table_spec.rb +6 -0
- data/spec/metric_fu/metrics/hotspots/generator_spec.rb +46 -0
- data/spec/metric_fu/metrics/hotspots/hotspot_analyzer_spec.rb +10 -0
- data/spec/metric_fu/metrics/hotspots/hotspot_spec.rb +16 -0
- data/spec/metric_fu/metrics/rails_best_practices/configuration_spec.rb +55 -0
- data/spec/metric_fu/metrics/rails_best_practices/generator_spec.rb +33 -0
- data/spec/metric_fu/metrics/rails_best_practices/grapher_spec.rb +62 -0
- data/spec/metric_fu/metrics/rcov/configuration_spec.rb +28 -0
- data/spec/metric_fu/metrics/rcov/generator_spec.rb +22 -0
- data/spec/metric_fu/metrics/rcov/grapher_spec.rb +57 -0
- data/spec/metric_fu/metrics/rcov/hotspot_spec.rb +20 -0
- data/spec/metric_fu/metrics/rcov/rcov_line_spec.rb +89 -0
- data/spec/metric_fu/metrics/rcov/simplecov_formatter_spec.rb +67 -0
- data/spec/metric_fu/metrics/reek/configuration_spec.rb +13 -0
- data/spec/metric_fu/metrics/reek/generator_spec.rb +169 -0
- data/spec/metric_fu/metrics/reek/grapher_spec.rb +66 -0
- data/spec/metric_fu/metrics/roodi/configuration_spec.rb +14 -0
- data/spec/metric_fu/metrics/roodi/generator_spec.rb +82 -0
- data/spec/metric_fu/metrics/roodi/grapher_spec.rb +57 -0
- data/spec/metric_fu/metrics/saikuro/configuration_spec.rb +25 -0
- data/spec/metric_fu/metrics/saikuro/generator_spec.rb +71 -0
- data/spec/metric_fu/metrics/stats/generator_spec.rb +96 -0
- data/spec/metric_fu/metrics/stats/grapher_spec.rb +69 -0
- data/spec/metric_fu/reporter_spec.rb +41 -0
- data/spec/metric_fu/reporting/graphs/graph_spec.rb +44 -0
- data/spec/metric_fu/reporting/graphs/grapher_spec.rb +24 -0
- data/spec/metric_fu/reporting/result_spec.rb +50 -0
- data/spec/metric_fu/run_spec.rb +197 -0
- data/spec/metric_fu/templates/configuration_spec.rb +51 -0
- data/spec/metric_fu/templates/metrics_template_spec.rb +11 -0
- data/spec/metric_fu/templates/report_spec.rb +15 -0
- data/spec/metric_fu/templates/template_spec.rb +233 -0
- data/spec/metric_fu/utility_spec.rb +12 -0
- data/spec/metric_fu_spec.rb +33 -0
- data/spec/quality_spec.rb +114 -0
- data/spec/shared/configured.rb +45 -0
- data/spec/shared/test_coverage.rb +95 -0
- data/spec/spec_helper.rb +54 -0
- data/spec/support/deferred_garbaged_collection.rb +33 -0
- data/spec/support/helper_methods.rb +32 -0
- data/spec/support/matcher_create_file.rb +37 -0
- data/spec/support/matcher_create_files.rb +43 -0
- data/spec/support/suite.rb +26 -0
- data/spec/support/test_fixtures.rb +37 -0
- data/spec/support/timeout.rb +7 -0
- data/spec/support/usage_test.rb +150 -0
- data/spec/usage_test_spec.rb +93 -0
- 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]} » #{problem[:type]}" %></li>
|
18
|
+
<% end %>
|
19
|
+
</ul>
|
20
|
+
<% else %>
|
21
|
+
|
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
|