metric_fu 4.2.1 → 4.3.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.
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