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