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.
Files changed (90) hide show
  1. data/.metrics +19 -1
  2. data/.travis.yml +2 -2
  3. data/Gemfile +2 -1
  4. data/HISTORY.md +24 -0
  5. data/README.md +60 -1
  6. data/TODO.md +1 -0
  7. data/bin/mf-saikuro +8 -0
  8. data/checksum/metric_fu-4.3.0.gem.sha512 +1 -0
  9. data/gemfiles/Gemfile.travis +9 -0
  10. data/lib/metric_fu.rb +1 -1
  11. data/lib/metric_fu/cli/client.rb +2 -2
  12. data/lib/metric_fu/cli/helper.rb +3 -3
  13. data/lib/metric_fu/cli/parser.rb +37 -16
  14. data/lib/metric_fu/configuration.rb +9 -1
  15. data/lib/metric_fu/constantize.rb +57 -0
  16. data/lib/metric_fu/data_structures/line_numbers.rb +19 -3
  17. data/lib/metric_fu/data_structures/location.rb +8 -3
  18. data/lib/metric_fu/formatter.rb +24 -0
  19. data/lib/metric_fu/formatter/html.rb +91 -0
  20. data/lib/metric_fu/formatter/yaml.rb +18 -0
  21. data/lib/metric_fu/initial_requires.rb +0 -1
  22. data/lib/metric_fu/io.rb +69 -0
  23. data/lib/metric_fu/load_files.rb +5 -2
  24. data/lib/metric_fu/logging/mf_debugger.rb +23 -0
  25. data/lib/metric_fu/metrics/base_template.rb +10 -4
  26. data/lib/metric_fu/metrics/cane/cane.rb +2 -1
  27. data/lib/metric_fu/metrics/cane/cane_bluff_grapher.rb +10 -9
  28. data/lib/metric_fu/metrics/cane/cane_gchart_grapher.rb +25 -0
  29. data/lib/metric_fu/metrics/flay/flay_bluff_grapher.rb +10 -9
  30. data/lib/metric_fu/metrics/flay/flay_gchart_grapher.rb +14 -11
  31. data/lib/metric_fu/metrics/flog/flog_bluff_grapher.rb +11 -10
  32. data/lib/metric_fu/metrics/flog/flog_gchart_grapher.rb +22 -15
  33. data/lib/metric_fu/metrics/generator.rb +10 -10
  34. data/lib/metric_fu/metrics/graph.rb +2 -2
  35. data/lib/metric_fu/metrics/hotspots/analysis/scoring_strategies.rb +3 -3
  36. data/lib/metric_fu/metrics/hotspots/hotspot.rb +4 -3
  37. data/lib/metric_fu/metrics/hotspots/hotspot_analyzer.rb +19 -10
  38. data/lib/metric_fu/metrics/hotspots/hotspots.rb +1 -1
  39. data/lib/metric_fu/metrics/hotspots/template_awesome/hotspots.html.erb +45 -45
  40. data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_bluff_grapher.rb +10 -9
  41. data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices_gchart_grapher.rb +21 -15
  42. data/lib/metric_fu/metrics/rcov/rcov.rb +1 -1
  43. data/lib/metric_fu/metrics/rcov/rcov_bluff_grapher.rb +10 -9
  44. data/lib/metric_fu/metrics/rcov/rcov_gchart_grapher.rb +13 -8
  45. data/lib/metric_fu/metrics/reek/reek_bluff_grapher.rb +9 -13
  46. data/lib/metric_fu/metrics/reek/reek_gchart_grapher.rb +22 -17
  47. data/lib/metric_fu/metrics/roodi/roodi_bluff_grapher.rb +10 -9
  48. data/lib/metric_fu/metrics/roodi/roodi_gchart_grapher.rb +14 -11
  49. data/lib/metric_fu/metrics/saikuro/saikuro.rb +5 -34
  50. data/lib/metric_fu/metrics/stats/stats.rb +2 -1
  51. data/lib/metric_fu/metrics/stats/stats_bluff_grapher.rb +11 -10
  52. data/lib/metric_fu/metrics/stats/stats_gchart_grapher.rb +21 -14
  53. data/lib/metric_fu/reporter.rb +37 -0
  54. data/lib/metric_fu/reporting/graphs/engines/bluff.rb +20 -0
  55. data/lib/metric_fu/reporting/graphs/engines/gchart.rb +41 -3
  56. data/lib/metric_fu/reporting/graphs/grapher.rb +9 -2
  57. data/lib/metric_fu/reporting/result.rb +51 -0
  58. data/lib/metric_fu/reporting/templates/awesome/awesome_template.rb +8 -8
  59. data/lib/metric_fu/run.rb +34 -39
  60. data/lib/metric_fu/version.rb +1 -1
  61. data/lib/metric_fu_requires.rb +50 -33
  62. data/metric_fu.gemspec +30 -39
  63. data/spec/cli/helper_spec.rb +15 -0
  64. data/spec/metric_fu/configuration_spec.rb +40 -2
  65. data/spec/metric_fu/formatter/html_spec.rb +134 -0
  66. data/spec/metric_fu/formatter/yaml_spec.rb +59 -0
  67. data/spec/metric_fu/formatter_spec.rb +49 -0
  68. data/spec/metric_fu/metrics/base_template_spec.rb +23 -23
  69. data/spec/metric_fu/metrics/cane/cane_spec.rb +2 -2
  70. data/spec/metric_fu/metrics/churn/churn_spec.rb +1 -1
  71. data/spec/metric_fu/metrics/flay/flay_spec.rb +4 -4
  72. data/spec/metric_fu/metrics/flog/flog_spec.rb +7 -7
  73. data/spec/metric_fu/metrics/generator_spec.rb +21 -21
  74. data/spec/metric_fu/metrics/graph_spec.rb +9 -9
  75. data/spec/metric_fu/metrics/hotspots/hotspots_spec.rb +1 -1
  76. data/spec/metric_fu/metrics/rcov/rcov_spec.rb +8 -8
  77. data/spec/metric_fu/metrics/reek/reek_spec.rb +1 -1
  78. data/spec/metric_fu/metrics/saikuro/saikuro_spec.rb +5 -5
  79. data/spec/metric_fu/metrics/stats/stats_spec.rb +4 -4
  80. data/spec/metric_fu/reporter_spec.rb +41 -0
  81. data/spec/metric_fu/reporting/graphs/engines/gchart_spec.rb +7 -7
  82. data/spec/metric_fu/reporting/result_spec.rb +51 -0
  83. data/spec/run_spec.rb +167 -27
  84. data/spec/spec_helper.rb +1 -0
  85. data/spec/support/matcher_create_file.rb +7 -2
  86. data/spec/support/matcher_create_files.rb +41 -0
  87. data/spec/support/suite.rb +32 -0
  88. metadata +27 -6
  89. data/lib/metric_fu/reporting/report.rb +0 -111
  90. 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
- mf_debug "Metrics config loaded"
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'
@@ -1,8 +1,8 @@
1
1
  language: ruby
2
2
  bundler_args: --without development
3
3
  script: bundle exec rspec
4
- # gemfile:
5
- # - gemfiles/Gemfile.ci
4
+ gemfile:
5
+ - gemfiles/Gemfile.travis
6
6
  # before_install: some_command
7
7
  # env:
8
8
  # - "rack=1.3.4"
data/Gemfile CHANGED
@@ -14,5 +14,6 @@ group :test do
14
14
  # https://github.com/kina/simplecov-rcov-text
15
15
  gem 'simplecov-rcov-text'
16
16
  end
17
+ gem "fakefs", :require => "fakefs/safe"
17
18
  end
18
- gemspec
19
+ gemspec :path => File.expand_path('..', __FILE__)
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) [![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)
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:
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby_noexec_wrapper
2
+ require 'rubygems'
3
+
4
+ require 'metric_fu_requires'
5
+
6
+ version = MetricFu::MetricVersion.saikuro
7
+ gem 'metric_fu-Saikuro', version
8
+ load Gem.bin_path('metric_fu-Saikuro', 'saikuro', version)
@@ -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__)
@@ -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
@@ -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)
@@ -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=ARGV.dup)
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 => false
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
@@ -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 |sexp|
57
- process_class(sexp, module_name)
58
- hide_methods_from_next_round(sexp)
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