metric_fu 4.2.1 → 4.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.metrics +19 -1
- data/.travis.yml +2 -2
- data/Gemfile +2 -1
- data/HISTORY.md +24 -0
- data/README.md +60 -1
- data/TODO.md +1 -0
- data/bin/mf-saikuro +8 -0
- data/checksum/metric_fu-4.3.0.gem.sha512 +1 -0
- data/gemfiles/Gemfile.travis +9 -0
- data/lib/metric_fu.rb +1 -1
- data/lib/metric_fu/cli/client.rb +2 -2
- data/lib/metric_fu/cli/helper.rb +3 -3
- data/lib/metric_fu/cli/parser.rb +37 -16
- data/lib/metric_fu/configuration.rb +9 -1
- data/lib/metric_fu/constantize.rb +57 -0
- data/lib/metric_fu/data_structures/line_numbers.rb +19 -3
- data/lib/metric_fu/data_structures/location.rb +8 -3
- data/lib/metric_fu/formatter.rb +24 -0
- data/lib/metric_fu/formatter/html.rb +91 -0
- data/lib/metric_fu/formatter/yaml.rb +18 -0
- data/lib/metric_fu/initial_requires.rb +0 -1
- data/lib/metric_fu/io.rb +69 -0
- data/lib/metric_fu/load_files.rb +5 -2
- data/lib/metric_fu/logging/mf_debugger.rb +23 -0
- data/lib/metric_fu/metrics/base_template.rb +10 -4
- data/lib/metric_fu/metrics/cane/cane.rb +2 -1
- data/lib/metric_fu/metrics/cane/cane_bluff_grapher.rb +10 -9
- data/lib/metric_fu/metrics/cane/cane_gchart_grapher.rb +25 -0
- data/lib/metric_fu/metrics/flay/flay_bluff_grapher.rb +10 -9
- data/lib/metric_fu/metrics/flay/flay_gchart_grapher.rb +14 -11
- data/lib/metric_fu/metrics/flog/flog_bluff_grapher.rb +11 -10
- data/lib/metric_fu/metrics/flog/flog_gchart_grapher.rb +22 -15
- data/lib/metric_fu/metrics/generator.rb +10 -10
- data/lib/metric_fu/metrics/graph.rb +2 -2
- data/lib/metric_fu/metrics/hotspots/analysis/scoring_strategies.rb +3 -3
- data/lib/metric_fu/metrics/hotspots/hotspot.rb +4 -3
- data/lib/metric_fu/metrics/hotspots/hotspot_analyzer.rb +19 -10
- data/lib/metric_fu/metrics/hotspots/hotspots.rb +1 -1
- data/lib/metric_fu/metrics/hotspots/template_awesome/hotspots.html.erb +45 -45
- data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_bluff_grapher.rb +10 -9
- data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_gchart_grapher.rb +21 -15
- data/lib/metric_fu/metrics/rcov/rcov.rb +1 -1
- data/lib/metric_fu/metrics/rcov/rcov_bluff_grapher.rb +10 -9
- data/lib/metric_fu/metrics/rcov/rcov_gchart_grapher.rb +13 -8
- data/lib/metric_fu/metrics/reek/reek_bluff_grapher.rb +9 -13
- data/lib/metric_fu/metrics/reek/reek_gchart_grapher.rb +22 -17
- data/lib/metric_fu/metrics/roodi/roodi_bluff_grapher.rb +10 -9
- data/lib/metric_fu/metrics/roodi/roodi_gchart_grapher.rb +14 -11
- data/lib/metric_fu/metrics/saikuro/saikuro.rb +5 -34
- data/lib/metric_fu/metrics/stats/stats.rb +2 -1
- data/lib/metric_fu/metrics/stats/stats_bluff_grapher.rb +11 -10
- data/lib/metric_fu/metrics/stats/stats_gchart_grapher.rb +21 -14
- data/lib/metric_fu/reporter.rb +37 -0
- data/lib/metric_fu/reporting/graphs/engines/bluff.rb +20 -0
- data/lib/metric_fu/reporting/graphs/engines/gchart.rb +41 -3
- data/lib/metric_fu/reporting/graphs/grapher.rb +9 -2
- data/lib/metric_fu/reporting/result.rb +51 -0
- data/lib/metric_fu/reporting/templates/awesome/awesome_template.rb +8 -8
- data/lib/metric_fu/run.rb +34 -39
- data/lib/metric_fu/version.rb +1 -1
- data/lib/metric_fu_requires.rb +50 -33
- data/metric_fu.gemspec +30 -39
- data/spec/cli/helper_spec.rb +15 -0
- data/spec/metric_fu/configuration_spec.rb +40 -2
- data/spec/metric_fu/formatter/html_spec.rb +134 -0
- data/spec/metric_fu/formatter/yaml_spec.rb +59 -0
- data/spec/metric_fu/formatter_spec.rb +49 -0
- data/spec/metric_fu/metrics/base_template_spec.rb +23 -23
- data/spec/metric_fu/metrics/cane/cane_spec.rb +2 -2
- data/spec/metric_fu/metrics/churn/churn_spec.rb +1 -1
- data/spec/metric_fu/metrics/flay/flay_spec.rb +4 -4
- data/spec/metric_fu/metrics/flog/flog_spec.rb +7 -7
- data/spec/metric_fu/metrics/generator_spec.rb +21 -21
- data/spec/metric_fu/metrics/graph_spec.rb +9 -9
- data/spec/metric_fu/metrics/hotspots/hotspots_spec.rb +1 -1
- data/spec/metric_fu/metrics/rcov/rcov_spec.rb +8 -8
- data/spec/metric_fu/metrics/reek/reek_spec.rb +1 -1
- data/spec/metric_fu/metrics/saikuro/saikuro_spec.rb +5 -5
- data/spec/metric_fu/metrics/stats/stats_spec.rb +4 -4
- data/spec/metric_fu/reporter_spec.rb +41 -0
- data/spec/metric_fu/reporting/graphs/engines/gchart_spec.rb +7 -7
- data/spec/metric_fu/reporting/result_spec.rb +51 -0
- data/spec/run_spec.rb +167 -27
- data/spec/spec_helper.rb +1 -0
- data/spec/support/matcher_create_file.rb +7 -2
- data/spec/support/matcher_create_files.rb +41 -0
- data/spec/support/suite.rb +32 -0
- metadata +27 -6
- data/lib/metric_fu/reporting/report.rb +0 -111
- data/spec/metric_fu/reporting/report_spec.rb +0 -148
data/.metrics
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
# For testing that this file gets loaded
|
4
|
-
|
4
|
+
$metric_file_loaded = true
|
5
|
+
|
5
6
|
# example configuration
|
6
7
|
# MetricFu::Configuration.run do |config|
|
7
8
|
# coverage_file = File.expand_path("coverage/rcov/rcov.txt", Dir.pwd)
|
@@ -16,3 +17,20 @@ mf_debug "Metrics config loaded"
|
|
16
17
|
# end
|
17
18
|
# you may enable running rcov manually with
|
18
19
|
# MetricFu.run_rcov
|
20
|
+
#
|
21
|
+
# By default, metric_fu will use the built-in html formatter
|
22
|
+
# to generate HTML reports for each metric with pretty graphs.
|
23
|
+
|
24
|
+
# To configure different formatter(s) or output ...
|
25
|
+
# MetricFu::Configuration.run do |config|
|
26
|
+
# config.add_formatter(:html)
|
27
|
+
# config.add_formatter(:yaml, "customreport.yml")
|
28
|
+
# config.add_formatter(MyCustomFormatter)
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# metric_fu will attempt to require a custom formatter by
|
32
|
+
# fully qualified name based on ruby search path,
|
33
|
+
# but you may find that you need to add a require above.
|
34
|
+
#
|
35
|
+
# For instance, to require a formatter in your app's lib directory:
|
36
|
+
# require './lib/my_custom_formatter.rb'
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/HISTORY.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
|
+
Changes are below categorized as `Features, Fixes, or Misc`.
|
2
|
+
|
3
|
+
Each change should fall into categories that would affect whether the release is major (breaking changes), minor (new behavior), or patch (bug fix). See [semver](http://semver.org/) and [pessimistic versioning](http://docs.rubygems.org/read/chapter/16#page74)
|
4
|
+
|
5
|
+
As such, a _Feature_ would map to either major or minor. A _bug fix_ to a patch. And _misc_ is either minor or patch, the difference being kind of fuzzy for the purposes of history. Adding tests would be patch level.
|
6
|
+
|
1
7
|
### Master
|
2
8
|
|
9
|
+
### MetricFu 4.3.0 / 2013-07-26
|
10
|
+
|
11
|
+
* Features
|
12
|
+
* Allow customization of reporting results using formatters (Robin Curry #94)
|
13
|
+
* Fixes
|
14
|
+
* obey --no-open option (Chris Mason)
|
15
|
+
* Don't run the hotspots metric if it has been disabled (Chris Mason)
|
16
|
+
* No longer crashes when rake stats outputs blank lines (Benjamin Fleischer #103, #24)
|
17
|
+
* Run saikuro metrics the same way as the other metrics (Martin Gotink #100)
|
18
|
+
* Add missing Cane Google Chart Grapher (Benjamin Fleischer)
|
19
|
+
* Fix wrong arguments to display_location, split off line numbers from paths (Benjamin Fleischer #88)
|
20
|
+
* Remove line numbers from direct file link so the browser can open it (Benjamin Fleischer #82)
|
21
|
+
* Make the run specs work without the need to shell out (Robin Curry)
|
22
|
+
* Misc
|
23
|
+
* metric_fu runs with the -r option by default (Chris Mason #69)
|
24
|
+
* Switch to metric_fu-Saikuro gem (Benjamin Fleischer)
|
25
|
+
* Reduce Grapher code duplication (Benjamin Fleischer #89)
|
26
|
+
|
3
27
|
### MetricFu 4.2.1 / 2013-05-23
|
4
28
|
|
5
29
|
* Fixes
|
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
# MetricFu [![Gem Version](https://badge.fury.io/rb/metric_fu.png)](http://badge.fury.io/rb/metric_fu) [![Build Status](https://travis-ci.org/metricfu/metric_fu.png?branch=master)](http://travis-ci.org/metricfu/metric_fu) [
|
1
|
+
# MetricFu [![Gem Version](https://badge.fury.io/rb/metric_fu.png)](http://badge.fury.io/rb/metric_fu) [![Build Status](https://travis-ci.org/metricfu/metric_fu.png?branch=master)](http://travis-ci.org/metricfu/metric_fu) [Rdoc](http://rdoc.info/github/metricfu/metric_fu/)
|
2
|
+
|
3
|
+
[![Code Climate](https://codeclimate.com/github/metricfu/metric_fu.png)](https://codeclimate.com/github/metricfu/metric_fu) [![Dependency Status](https://gemnasium.com/metricfu/metric_fu.png)](https://gemnasium.com/metricfu/metric_fu)
|
2
4
|
|
3
5
|
## Metrics
|
4
6
|
|
@@ -47,6 +49,63 @@ See `metric_fu --help` for more options
|
|
47
49
|
|
48
50
|
* Cane code quality threshold checking is not included in the hotspots report
|
49
51
|
|
52
|
+
## Formatters
|
53
|
+
|
54
|
+
### Built-in Formatters
|
55
|
+
|
56
|
+
By default, metric_fu will use the built-in html formatter to generate HTML reports for each metric with pretty graphs.
|
57
|
+
|
58
|
+
These reports are generated in metric_fu's output directory (```tmp/metric_fu/output```) by default. You can customize the output directory by specifying an out directory at the command line
|
59
|
+
using a relative path:
|
60
|
+
|
61
|
+
metric_fu --out custom_directory # outputs to tmp/metric_fu/custom_directory
|
62
|
+
|
63
|
+
or a full path:
|
64
|
+
|
65
|
+
metric_fu --out /home/metrics # outputs to /home/metrics
|
66
|
+
|
67
|
+
You can specify a different formatter at the command line by referencing a built-in formatter or providing the fully-qualified name of a custom formatter.
|
68
|
+
|
69
|
+
|
70
|
+
metric_fu --format yaml --out custom_report.yml
|
71
|
+
or
|
72
|
+
|
73
|
+
metric_fu --format MyCustomFormatter
|
74
|
+
|
75
|
+
### Custom Formatters
|
76
|
+
|
77
|
+
You can customize metric_fu's output format with a custom formatter.
|
78
|
+
|
79
|
+
To create a custom formatter, you simply need to create a class
|
80
|
+
that takes an options hash and responds to one or more notifications:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
class MyCustomFormatter
|
84
|
+
def initialize(opts={}); end # metric_fu will pass in an output param if provided.
|
85
|
+
|
86
|
+
# Should include one or more of...
|
87
|
+
def start; end # Sent before metric_fu starts metric measurements.
|
88
|
+
def start_metric(metric); end # Sent before individual metric is measured.
|
89
|
+
def finish_metric(metric); end # Sent after individual metric measurement is complete.
|
90
|
+
def finish; end # Sent after metric_fu has completed all measurements.
|
91
|
+
def display_results; end # Used to open results in browser, etc.
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
See [lib/metric_fu/formatter/](lib/metric_fu/formatter/) for examples.
|
96
|
+
|
97
|
+
metric_fu will attempt to require a custom formatter by
|
98
|
+
fully qualified name based on ruby search path. So if you include a custom
|
99
|
+
formatter as a gem in your Gemfile, you should be able to use it out of the box.
|
100
|
+
But you may find in certain cases that you need to add a require to
|
101
|
+
your .metrics configuration file.
|
102
|
+
|
103
|
+
For instance, to require a formatter in your app's lib directory:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
require './lib/my_custom_formatter.rb'
|
107
|
+
```
|
108
|
+
|
50
109
|
### Configuration
|
51
110
|
|
52
111
|
see the .metrics file
|
data/TODO.md
CHANGED
@@ -84,6 +84,7 @@ instance variables and accessors
|
|
84
84
|
* CLI [Flog](https://github.com/seattlerb/flog/blob/master/lib/flog_cli.rb) Plugins [Flog](https://github.com/seattlerb/flog/blob/master/lib/flog_cli.rb#L34)
|
85
85
|
* Look into adding
|
86
86
|
* https://github.com/metricfu/code_statistics [1](https://github.com/cloudability/code_statistics)
|
87
|
+
* or extract from rails into a gem [rake task](https://github.com/rails/rails/blob/master/railties/lib/rails/tasks/statistics.rake) [can be modified by rspec](https://github.com/rspec/rspec-rails/blob/master/lib/rspec/rails/tasks/rspec.rake#L38) with the [calculator](https://github.com/rails/rails/blob/master/railties/lib/rails/code_statistics_calculator.rb) and [class](https://github.com/rails/rails/blob/master/railties/lib/rails/code_statistics.rb)
|
87
88
|
* brakeman https://github.com/metricfu/brakeman
|
88
89
|
* laser https://github.com/metricfu/laser
|
89
90
|
* Other intersting libraries to consider:
|
data/bin/mf-saikuro
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
7a5e74c8b010bd9629e9cbdcf297cc1d75295338bb34a327a9ed57a742c5fc57107608bd148e31e5355263dc113841249be8719877a68fcb42271212edd71f13
|
@@ -0,0 +1,9 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
#to use, from the app root run
|
4
|
+
# export BUNDLE_GEMFILE=$PWD/gemfiles/Gemfile.travis
|
5
|
+
# when done, unset BUNDLE_GEMFILE
|
6
|
+
# for 1.9.2 support because of https://github.com/railsbp/rails_best_practices/blob/master/rails_best_practices.gemspec
|
7
|
+
gem 'activesupport', '~> 3.2'
|
8
|
+
|
9
|
+
eval_gemfile File.expand_path('../../Gemfile', __FILE__)
|
data/lib/metric_fu.rb
CHANGED
@@ -25,7 +25,7 @@ module MetricFu
|
|
25
25
|
LIB_ROOT
|
26
26
|
end
|
27
27
|
class << self
|
28
|
-
%w(metrics reporting logging errors data_structures tasks).each do |dir|
|
28
|
+
%w(metrics formatter reporting logging errors data_structures tasks).each do |dir|
|
29
29
|
define_method("#{dir}_dir") do
|
30
30
|
File.join(lib_dir,dir)
|
31
31
|
end
|
data/lib/metric_fu/cli/client.rb
CHANGED
@@ -11,8 +11,8 @@ module MetricFu
|
|
11
11
|
def shutdown
|
12
12
|
@helper.shutdown
|
13
13
|
end
|
14
|
-
def run
|
15
|
-
options = @helper.process_options
|
14
|
+
def run(argv=ARGV.dup)
|
15
|
+
options = @helper.process_options(argv)
|
16
16
|
mf_debug "Got options #{options.inspect}"
|
17
17
|
if options[:run]
|
18
18
|
@helper.run(options)
|
data/lib/metric_fu/cli/helper.rb
CHANGED
@@ -35,15 +35,15 @@ module MetricFu
|
|
35
35
|
MetricFu.configuration.metrics.sort_by(&:to_s)
|
36
36
|
end
|
37
37
|
|
38
|
-
def process_options(argv=
|
38
|
+
def process_options(argv=[])
|
39
39
|
options = MetricFu::Cli::MicroOptParse::Parser.new do |p|
|
40
40
|
p.banner = self.banner
|
41
41
|
p.version = self.version
|
42
|
-
p.option :run, "Run all metrics with defaults", :default =>
|
42
|
+
p.option :run, "Run all metrics with defaults", :default => true
|
43
43
|
metrics.each do |metric|
|
44
44
|
p.option metric.to_sym, "Enables or disables #{metric.to_s}", :default => true #, :value_in_set => [true, false]
|
45
45
|
end
|
46
|
-
p.option :open, "Open report in browser", :default => true
|
46
|
+
p.option :open, "Open report in browser (if supported by formatter)", :default => true
|
47
47
|
end.process!(argv)
|
48
48
|
options
|
49
49
|
end
|
data/lib/metric_fu/cli/parser.rb
CHANGED
@@ -24,22 +24,6 @@ module MetricFu
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def validate(options) # remove this method if you want fewer lines of code and don't need validations
|
28
|
-
options.each_pair do |key, value|
|
29
|
-
opt = @options.find_all{ |o| o[0] == key }.first
|
30
|
-
key = "--" << key.to_s.gsub("_", "-")
|
31
|
-
unless opt[2][:value_in_set].nil? || opt[2][:value_in_set].include?(value)
|
32
|
-
puts "Parameter for #{key} must be in [" << opt[2][:value_in_set].join(", ") << "]" ; exit(1)
|
33
|
-
end
|
34
|
-
unless opt[2][:value_matches].nil? || opt[2][:value_matches] =~ value
|
35
|
-
puts "Parameter for #{key} must match /" << opt[2][:value_matches].source << "/" ; exit(1)
|
36
|
-
end
|
37
|
-
unless opt[2][:value_satisfies].nil? || opt[2][:value_satisfies].call(value)
|
38
|
-
puts "Parameter for #{key} must satisfy given conditions (see description)" ; exit(1)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
27
|
def process!(arguments = ARGV)
|
44
28
|
@result = (@default_values || {}).clone # reset or new
|
45
29
|
@optionparser ||= OptionParser.new do |p| # prepare only once
|
@@ -55,6 +39,28 @@ module MetricFu
|
|
55
39
|
end
|
56
40
|
end
|
57
41
|
|
42
|
+
p.on("--format FORMAT",
|
43
|
+
"Specify the formatter to use for output.",
|
44
|
+
"This option can be specified multiple times.",
|
45
|
+
"Specify a built-in formatter from the list below,",
|
46
|
+
"or the fully-qualified class name of your own custom formatter.",
|
47
|
+
*format_descriptions) do |f|
|
48
|
+
@result[:format] ||= []
|
49
|
+
@result[:format] << [f]
|
50
|
+
end
|
51
|
+
|
52
|
+
p.on("--out FILE|DIR",
|
53
|
+
"Specify the file or directory to use for output",
|
54
|
+
"This option applies to the previously",
|
55
|
+
"specified --format, or the default format",
|
56
|
+
"if no format is specified. Paths are relative to",
|
57
|
+
"#{Pathname.pwd.join(MetricFu.base_directory)}",
|
58
|
+
"Check the specific formatter\'s docs to see",
|
59
|
+
"whether to pass a file or a dir.") do |o|
|
60
|
+
@result[:format] ||= MetricFu::Formatter::DEFAULT
|
61
|
+
@result[:format].last << o
|
62
|
+
end
|
63
|
+
|
58
64
|
p.banner = @banner unless @banner.nil?
|
59
65
|
p.on_tail("-h", "--help", "Show this message") {puts p ; exit}
|
60
66
|
short = @used_short.include?("v") ? "-V" : "-v"
|
@@ -71,6 +77,21 @@ module MetricFu
|
|
71
77
|
validate(@result) if self.respond_to?("validate")
|
72
78
|
@result
|
73
79
|
end
|
80
|
+
|
81
|
+
# Build a nicely formatted list of built-in
|
82
|
+
# formatter keys and their descriptions
|
83
|
+
# @see MetricFu::Formatter::BUILTIN_FORMATS
|
84
|
+
# @example
|
85
|
+
# format_descriptions #=> [" yaml : Generates the raw output as yaml"]
|
86
|
+
# @return [Array<String>] in the form of
|
87
|
+
# " <key> : <description>."
|
88
|
+
def format_descriptions
|
89
|
+
formats = MetricFu::Formatter::BUILTIN_FORMATS
|
90
|
+
max = formats.keys.map{|s| s.length}.max
|
91
|
+
formats.keys.sort.map do |key|
|
92
|
+
" #{key}#{' ' * (max - key.length)} : #{formats[key][1]}"
|
93
|
+
end
|
94
|
+
end
|
74
95
|
end
|
75
96
|
end
|
76
97
|
|
@@ -61,6 +61,7 @@ module MetricFu
|
|
61
61
|
set_directories
|
62
62
|
configure_template
|
63
63
|
add_promiscuous_instance_variable(:metrics, [])
|
64
|
+
add_promiscuous_instance_variable(:formatters, [])
|
64
65
|
add_promiscuous_instance_variable(:graphs, [])
|
65
66
|
add_promiscuous_instance_variable(:graph_engines, [])
|
66
67
|
add_promiscuous_method(:graph_engine)
|
@@ -90,6 +91,10 @@ module MetricFu
|
|
90
91
|
self.graphs = (graphs << metric).uniq
|
91
92
|
end
|
92
93
|
|
94
|
+
def add_formatter(format, output = nil)
|
95
|
+
@formatters << MetricFu::Formatter.class_for(format).new(output: output)
|
96
|
+
end
|
97
|
+
|
93
98
|
# e.g. :reek, {}
|
94
99
|
def configure_metric(metric, metric_configuration)
|
95
100
|
add_promiscuous_instance_variable(metric, metric_configuration)
|
@@ -126,6 +131,10 @@ module MetricFu
|
|
126
131
|
@mri ||= !!RedCard.check(:ruby)
|
127
132
|
end
|
128
133
|
|
134
|
+
def rubinius?
|
135
|
+
@rubinius ||= !!RedCard.check(:rubinius)
|
136
|
+
end
|
137
|
+
|
129
138
|
def platform #:nodoc:
|
130
139
|
# TODO, change
|
131
140
|
# RbConfig::CONFIG['ruby_install_name'].dup
|
@@ -208,6 +217,5 @@ module MetricFu
|
|
208
217
|
add_promiscuous_instance_variable(:code_dirs,['lib'])
|
209
218
|
end
|
210
219
|
end
|
211
|
-
|
212
220
|
end
|
213
221
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module MetricFu
|
2
|
+
module Constantize
|
3
|
+
# Copied from ActiveSupport and modified so as not to introduce a dependency.
|
4
|
+
# https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L220
|
5
|
+
def constantize(camel_cased_word)
|
6
|
+
tries ||= 2
|
7
|
+
names = camel_cased_word.split('::')
|
8
|
+
names.shift if names.empty? || names.first.empty?
|
9
|
+
|
10
|
+
names.inject(Object) do |constant, name|
|
11
|
+
if constant == Object
|
12
|
+
constant.const_get(name)
|
13
|
+
else
|
14
|
+
candidate = constant.const_get(name)
|
15
|
+
next candidate if constant.const_defined?(name, false)
|
16
|
+
next candidate unless Object.const_defined?(name)
|
17
|
+
|
18
|
+
# Go down the ancestors to check it it's owned
|
19
|
+
# directly before we reach Object or the end of ancestors.
|
20
|
+
constant = constant.ancestors.inject do |const, ancestor|
|
21
|
+
break const if ancestor == Object
|
22
|
+
break ancestor if ancestor.const_defined?(name, false)
|
23
|
+
const
|
24
|
+
end
|
25
|
+
|
26
|
+
# owner is in Object, so raise
|
27
|
+
constant.const_get(name, false)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
rescue NameError
|
31
|
+
# May need to attempt to require the file and try again.
|
32
|
+
begin
|
33
|
+
require underscore(camel_cased_word)
|
34
|
+
rescue LoadError => e
|
35
|
+
mf_log e.message
|
36
|
+
end
|
37
|
+
|
38
|
+
if (tries -= 1).zero?
|
39
|
+
raise
|
40
|
+
else
|
41
|
+
retry
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Copied from active_support
|
46
|
+
# https://github.com/rails/rails/blob/51cd6bb829c418c5fbf75de1dfbb177233b1b154/activesupport/lib/active_support/inflector/methods.rb#L88
|
47
|
+
def underscore(camel_cased_word)
|
48
|
+
word = camel_cased_word.to_s.dup
|
49
|
+
word.gsub!(/::/, '/')
|
50
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
51
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
52
|
+
word.tr!("-", "_")
|
53
|
+
word.downcase!
|
54
|
+
word
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,7 +1,13 @@
|
|
1
|
+
# MetricFu::LineNumber
|
2
|
+
# (see #initialize)
|
1
3
|
require 'ruby_parser'
|
2
4
|
module MetricFu
|
3
5
|
class LineNumbers
|
4
6
|
|
7
|
+
# Parses ruby code to collect line numbers for class, module, and method definitions.
|
8
|
+
# Used by metrics that don't provide line numbers for class, module, or methods problems
|
9
|
+
# @param contents [String] a string of ruby code
|
10
|
+
# @param file_path [String] the file path for the contents, defaults to empty string
|
5
11
|
def initialize(contents,file_path='')
|
6
12
|
if contents.to_s.size.zero?
|
7
13
|
mf_log "NON PARSEABLE INPUT: File is empty at path #{file_path.inspect}\n\t#{caller.join("\n\t")}"
|
@@ -27,12 +33,20 @@ module MetricFu
|
|
27
33
|
@locations
|
28
34
|
end
|
29
35
|
|
36
|
+
# @param line_number [String]
|
37
|
+
# @return [Boolean] if the given line number is in a method
|
30
38
|
def in_method? line_number
|
31
39
|
!!@locations.detect do |method_name, line_number_range|
|
32
40
|
line_number_range.include?(line_number)
|
33
41
|
end
|
34
42
|
end
|
35
43
|
|
44
|
+
# @param line_number [Integer]
|
45
|
+
# @return [String, nil] the method which includes that line number, if any
|
46
|
+
# For all collected locations, find the first location where the line_number_range
|
47
|
+
# includes the line_number
|
48
|
+
# If a location is found, return its first element
|
49
|
+
# Else return nil
|
36
50
|
def method_at_line line_number
|
37
51
|
found_method_and_range = @locations.detect do |method_name, line_number_range|
|
38
52
|
line_number_range.include?(line_number)
|
@@ -44,6 +58,8 @@ module MetricFu
|
|
44
58
|
end
|
45
59
|
end
|
46
60
|
|
61
|
+
# @param method [String] the method name being queried
|
62
|
+
# @erturn [Integer, nil] the line number at which the given method is defined
|
47
63
|
def start_line_for_method(method)
|
48
64
|
return nil unless @locations.has_key?(method)
|
49
65
|
@locations[method].first
|
@@ -53,9 +69,9 @@ module MetricFu
|
|
53
69
|
|
54
70
|
def process_module(sexp)
|
55
71
|
module_name = sexp[1]
|
56
|
-
sexp.each_of_type(:class) do |
|
57
|
-
process_class(
|
58
|
-
hide_methods_from_next_round(
|
72
|
+
sexp.each_of_type(:class) do |exp|
|
73
|
+
process_class(exp, module_name)
|
74
|
+
hide_methods_from_next_round(exp)
|
59
75
|
end
|
60
76
|
process_class(sexp)
|
61
77
|
end
|