metric_fu 4.3.1 → 4.4.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 (88) hide show
  1. checksums.yaml +7 -0
  2. data/.metrics +55 -26
  3. data/.travis.yml +4 -1
  4. data/AUTHORS +12 -0
  5. data/Gemfile +1 -0
  6. data/HISTORY.md +24 -0
  7. data/README.md +27 -22
  8. data/checksum/metric_fu-4.3.1.gem.sha512 +1 -0
  9. data/checksum/metric_fu-4.4.0.gem.sha512 +1 -0
  10. data/lib/metric_fu.rb +28 -79
  11. data/lib/metric_fu/cli/helper.rb +1 -1
  12. data/lib/metric_fu/cli/parser.rb +1 -1
  13. data/lib/metric_fu/configuration.rb +104 -150
  14. data/lib/metric_fu/environment.rb +88 -0
  15. data/lib/metric_fu/formatter.rb +23 -0
  16. data/lib/metric_fu/formatter/html.rb +12 -9
  17. data/lib/metric_fu/initial_requires.rb +1 -0
  18. data/lib/metric_fu/io.rb +60 -1
  19. data/lib/metric_fu/load_files.rb +4 -2
  20. data/lib/metric_fu/loader.rb +62 -0
  21. data/lib/metric_fu/metric.rb +102 -0
  22. data/lib/metric_fu/metrics/base_template.rb +15 -9
  23. data/lib/metric_fu/metrics/cane/cane.rb +9 -5
  24. data/lib/metric_fu/metrics/cane/init.rb +35 -13
  25. data/lib/metric_fu/metrics/churn/churn.rb +5 -1
  26. data/lib/metric_fu/metrics/churn/init.rb +24 -4
  27. data/lib/metric_fu/metrics/flay/flay.rb +7 -3
  28. data/lib/metric_fu/metrics/flay/init.rb +29 -13
  29. data/lib/metric_fu/metrics/flay/template_awesome/flay.html.erb +1 -1
  30. data/lib/metric_fu/metrics/flog/flog.rb +14 -38
  31. data/lib/metric_fu/metrics/flog/init.rb +30 -7
  32. data/lib/metric_fu/metrics/generator.rb +21 -6
  33. data/lib/metric_fu/metrics/graph.rb +2 -2
  34. data/lib/metric_fu/metrics/hotspots/hotspots.rb +5 -1
  35. data/lib/metric_fu/metrics/hotspots/init.rb +21 -5
  36. data/lib/metric_fu/metrics/rails_best_practices/init.rb +29 -5
  37. data/lib/metric_fu/metrics/rails_best_practices/rails_best_practices.rb +20 -27
  38. data/lib/metric_fu/metrics/rails_best_practices/template_awesome/rails_best_practices.html.erb +1 -1
  39. data/lib/metric_fu/metrics/rcov/init.rb +40 -15
  40. data/lib/metric_fu/metrics/rcov/rcov.rb +15 -10
  41. data/lib/metric_fu/metrics/reek/init.rb +25 -6
  42. data/lib/metric_fu/metrics/reek/reek.rb +52 -31
  43. data/lib/metric_fu/metrics/reek/template_awesome/reek.html.erb +1 -1
  44. data/lib/metric_fu/metrics/roodi/init.rb +25 -6
  45. data/lib/metric_fu/metrics/roodi/roodi.rb +7 -3
  46. data/lib/metric_fu/metrics/saikuro/init.rb +22 -6
  47. data/lib/metric_fu/metrics/saikuro/saikuro.rb +8 -3
  48. data/lib/metric_fu/metrics/stats/init.rb +28 -5
  49. data/lib/metric_fu/metrics/stats/stats.rb +24 -6
  50. data/lib/metric_fu/metrics/stats/template_awesome/stats.html.erb +2 -2
  51. data/lib/metric_fu/parser_ext.rb +15 -0
  52. data/lib/metric_fu/reporting/graphs/engines/gchart.rb +1 -1
  53. data/lib/metric_fu/reporting/graphs/engines/init.rb +18 -4
  54. data/lib/metric_fu/reporting/graphs/grapher.rb +1 -1
  55. data/lib/metric_fu/reporting/result.rb +13 -6
  56. data/lib/metric_fu/reporting/templates/awesome/awesome_template.rb +1 -1
  57. data/lib/metric_fu/run.rb +7 -10
  58. data/lib/metric_fu/sexp_ext.rb +11 -0
  59. data/lib/metric_fu/version.rb +1 -1
  60. data/metric_fu.gemspec +23 -20
  61. data/spec/cli/helper_spec.rb +5 -16
  62. data/spec/metric_fu/configuration_spec.rb +62 -88
  63. data/spec/metric_fu/formatter/html_spec.rb +26 -16
  64. data/spec/metric_fu/formatter/yaml_spec.rb +2 -2
  65. data/spec/metric_fu/metric_spec.rb +50 -0
  66. data/spec/metric_fu/metrics/base_template_spec.rb +9 -7
  67. data/spec/metric_fu/metrics/cane/cane_spec.rb +19 -24
  68. data/spec/metric_fu/metrics/churn/churn_spec.rb +8 -8
  69. data/spec/metric_fu/metrics/flay/flay_spec.rb +7 -13
  70. data/spec/metric_fu/metrics/flog/flog_spec.rb +63 -58
  71. data/spec/metric_fu/metrics/generator_spec.rb +4 -0
  72. data/spec/metric_fu/metrics/hotspots/hotspots_spec.rb +7 -7
  73. data/spec/metric_fu/metrics/rails_best_practices/rails_best_practices_spec.rb +14 -33
  74. data/spec/metric_fu/metrics/rcov/rcov_spec.rb +17 -18
  75. data/spec/metric_fu/metrics/reek/reek_spec.rb +9 -10
  76. data/spec/metric_fu/metrics/roodi/roodi_spec.rb +5 -11
  77. data/spec/metric_fu/metrics/saikuro/saikuro_spec.rb +15 -14
  78. data/spec/metric_fu/metrics/stats/stats_spec.rb +5 -6
  79. data/spec/metric_fu/reporting/graphs/engines/bluff_spec.rb +2 -3
  80. data/spec/metric_fu/reporting/graphs/engines/gchart_spec.rb +12 -9
  81. data/spec/metric_fu/reporting/result_spec.rb +3 -3
  82. data/spec/run_spec.rb +45 -29
  83. data/spec/spec_helper.rb +7 -0
  84. data/spec/support/helper_methods.rb +9 -0
  85. data/spec/support/suite.rb +17 -11
  86. metadata +59 -56
  87. data/bin/mf-rails_best_practices +0 -9
  88. data/bin/mf-stats +0 -7
@@ -1,7 +1,11 @@
1
1
  module MetricFu
2
- class Cane < Generator
2
+ class CaneGenerator < Generator
3
3
  attr_reader :violations, :total_violations
4
4
 
5
+ def self.metric
6
+ :cane
7
+ end
8
+
5
9
  def emit
6
10
  command = %Q{mf-cane#{abc_max_param}#{style_measure_param}#{no_doc_param}#{no_readme_param}}
7
11
  mf_debug "** #{command}"
@@ -19,19 +23,19 @@ module MetricFu
19
23
  private
20
24
 
21
25
  def abc_max_param
22
- MetricFu.cane[:abc_max] ? " --abc-max #{MetricFu.cane[:abc_max]}" : ""
26
+ options[:abc_max] ? " --abc-max #{options[:abc_max]}" : ""
23
27
  end
24
28
 
25
29
  def style_measure_param
26
- MetricFu.cane[:line_length] ? " --style-measure #{MetricFu.cane[:line_length]}" : ""
30
+ options[:line_length] ? " --style-measure #{options[:line_length]}" : ""
27
31
  end
28
32
 
29
33
  def no_doc_param
30
- MetricFu.cane[:no_doc] == 'y' ? " --no-doc" : ""
34
+ options[:no_doc] == 'y' ? " --no-doc" : ""
31
35
  end
32
36
 
33
37
  def no_readme_param
34
- MetricFu.cane[:no_readme] == 'y' ? " --no-readme" : ""
38
+ options[:no_readme] == 'y' ? " --no-readme" : ""
35
39
  end
36
40
 
37
41
  def violations_by_category
@@ -1,14 +1,36 @@
1
- MetricFu::Configuration.run do |config|
2
- require 'cane'
3
- config.add_metric(:cane)
4
- config.add_graph(:cane)
5
- config.configure_metric(:cane, {
6
- :dirs_to_cane => MetricFu.code_dirs,
7
- :abc_max => 15,
8
- :line_length => 80,
9
- :no_doc => 'n',
10
- :no_readme => 'n',
11
- :filetypes => ['rb']
12
- })
13
- end
1
+ module MetricFu
2
+ class MetricCane < Metric
3
+
4
+ def name
5
+ :cane
6
+ end
7
+
8
+ def default_run_options
9
+ {
10
+ :dirs_to_cane => MetricFu::Io::FileSystem.directory('code_dirs'),
11
+ :abc_max => 15,
12
+ :line_length => 80,
13
+ :no_doc => 'n',
14
+ :no_readme => 'n',
15
+ :filetypes => ['rb']
16
+ }
17
+ end
18
+
19
+ def has_graph?
20
+ true
21
+ end
14
22
 
23
+ def enable
24
+ if MetricFu.configuration.supports_ripper? && !MetricFu.configuration.ruby18?
25
+ super
26
+ else
27
+ MetricFu.configuration.mf_debug("Cane is only available in MRI. It requires ripper and 1.9 hash syntax support")
28
+ end
29
+ end
30
+
31
+ def activate
32
+ super
33
+ end
34
+
35
+ end
36
+ end
@@ -1,6 +1,10 @@
1
1
  module MetricFu
2
2
 
3
- class Churn < Generator
3
+ class ChurnGenerator < Generator
4
+
5
+ def self.metric
6
+ :churn
7
+ end
4
8
 
5
9
  def emit
6
10
  @output = generate_churn_metrics
@@ -1,5 +1,25 @@
1
- MetricFu::Configuration.run do |config|
2
- config.add_metric(:churn)
3
- config.configure_metric(:churn,
4
- { :start_date => %q("1 year ago"), :minimum_churn_count => 10})
1
+ module MetricFu
2
+ class MetricChurn < Metric
3
+
4
+ def name
5
+ :churn
6
+ end
7
+
8
+ def default_run_options
9
+ { :start_date => %q("1 year ago"), :minimum_churn_count => 10}
10
+ end
11
+
12
+ def has_graph?
13
+ false
14
+ end
15
+
16
+ def enable
17
+ super
18
+ end
19
+
20
+ def activate
21
+ super
22
+ end
23
+
24
+ end
5
25
  end
@@ -1,11 +1,15 @@
1
1
  module MetricFu
2
2
 
3
- class Flay < Generator
3
+ class FlayGenerator < Generator
4
+
5
+ def self.metric
6
+ :flay
7
+ end
4
8
 
5
9
  def emit
6
- minimum_score_parameter = MetricFu.flay[:minimum_score] ? "--mass #{MetricFu.flay[:minimum_score]} " : ""
10
+ minimum_score_parameter = options[:minimum_score] ? "--mass #{options[:minimum_score]} " : ""
7
11
 
8
- command = %Q(mf-flay #{minimum_score_parameter} #{MetricFu.flay[:dirs_to_flay].join(" ")})
12
+ command = %Q(mf-flay #{minimum_score_parameter} #{options[:dirs_to_flay].join(" ")})
9
13
  mf_debug "** #{command}"
10
14
  @output = `#{command}`
11
15
  end
@@ -1,14 +1,30 @@
1
- MetricFu::Configuration.run do |config|
2
- require 'flay'
3
- config.add_metric(:flay)
4
- config.add_graph(:flay)
5
- config.configure_metric(:flay,
6
- { :dirs_to_flay => MetricFu.code_dirs, # was @code_dirs
7
- # MetricFu has been setting the minimum score as 100 for
8
- # a long time. This is a really big number, considering
9
- # the default is 16. Commenting it out for documentation
10
- # of the setting, but to use the Flay default.
11
- # :minimum_score => 100,
12
- :filetypes => ['rb'] }
13
- )
1
+ module MetricFu
2
+ class MetricFlay < Metric
3
+
4
+ def name
5
+ :flay
6
+ end
7
+
8
+ def default_run_options
9
+ { :dirs_to_flay => MetricFu::Io::FileSystem.directory('code_dirs'),
10
+ # MetricFu has been setting the minimum score as 100 for
11
+ # a long time. This is a really big number, considering
12
+ # the default is 16. Setting it to nil to use the Flay default.
13
+ :minimum_score => nil,
14
+ :filetypes => ['rb'] }
15
+ end
16
+
17
+ def has_graph?
18
+ true
19
+ end
20
+
21
+ def enable
22
+ super
23
+ end
24
+
25
+ def activate
26
+ super
27
+ end
28
+
29
+ end
14
30
  end
@@ -11,7 +11,7 @@
11
11
  <% end %>
12
12
 
13
13
  <h4>Total Score (lower is better): <%= @flay[:total_score] %></h4>
14
- <h5>Scores less than <%= MetricFu.flay[:minimum_score] %> are not shown or part of the total</h5>
14
+ <h5>Scores less than <%= MetricFu::Metric.get_metric('flay').run_options[:minimum_score] %> are not shown or part of the total</h5>
15
15
 
16
16
  <table>
17
17
  <tr>
@@ -1,58 +1,34 @@
1
1
  require 'pathname'
2
2
  require 'optparse'
3
- require 'rbconfig'
4
- class RubyParser
5
- alias_method :original_process, :process
6
- def process(s,f,t)
7
- original_process(s,f,t)
8
- rescue => e
9
- if e.message =~ /wrong number of arguments/
10
- original_process(s,f)
11
- else
12
- raise
13
- end
14
- end
15
- end
3
+
16
4
  module MetricFu
5
+ class FlogGenerator < Generator
17
6
 
18
- class Flog < Generator
7
+ def self.metric
8
+ :flog
9
+ end
19
10
 
20
11
  def emit
21
- files = []
22
- MetricFu.flog[:dirs_to_flog].each do |directory|
23
- directory = "." if directory=='./'
24
- dir_files = Dir.glob("#{directory}/**/*.rb")
25
- dir_files = remove_excluded_files(dir_files)
26
- files += dir_files
27
- end
28
- options = ::Flog.parse_options [
12
+ parse_options = FlogCLI.parse_options [
29
13
  "--all",
30
- MetricFu.flog[:continue] ? "--continue" : nil,
14
+ options[:continue] ? "--continue" : nil,
31
15
  ].compact
32
-
33
- @flogger = ::Flog.new options
34
- @flogger.flog files
35
-
36
- rescue LoadError => e
37
- message = "#{e.class}\t#{e.message}\n\t#{e.backtrace.join('\n\t')}"
38
- if MetricFu.configuration.mri?
39
- mf_log "Flog Error: #{message}"
40
- else
41
- mf_log "Flog tasks only available in MRI: #{message}"
42
- end
16
+ @flogger = FlogCLI.new parse_options
17
+ @flogger.flog *options[:dirs_to_flog]
43
18
  end
44
19
 
45
20
  def analyze
46
21
  @method_containers = {}
47
- @flogger.calls.each do |full_method_name, operators|
22
+ @flogger.calculate
23
+ @flogger.each_by_score do |full_method_name, score, operators|
48
24
  container_name = full_method_name.split('#').first
49
25
  path = @flogger.method_locations[full_method_name]
50
26
  if @method_containers[container_name]
51
- @method_containers[container_name].add_method(full_method_name, operators, @flogger.totals[full_method_name], path)
27
+ @method_containers[container_name].add_method(full_method_name, operators, score, path)
52
28
  @method_containers[container_name].add_path(path)
53
29
  else
54
30
  mc = MethodContainer.new(container_name, path)
55
- mc.add_method(full_method_name, operators, @flogger.totals[full_method_name], path)
31
+ mc.add_method(full_method_name, operators, score, path)
56
32
  @method_containers[container_name] = mc
57
33
  end
58
34
  end
@@ -60,7 +36,7 @@ module MetricFu
60
36
 
61
37
  def to_h
62
38
  sorted_containers = @method_containers.values.sort_by {|c| c.highest_score}.reverse
63
- {:flog => { :total => @flogger.total,
39
+ {:flog => { :total => @flogger.total_score,
64
40
  :average => @flogger.average,
65
41
  :method_containers => sorted_containers.map {|method_container| method_container.to_h}}}
66
42
  end
@@ -1,8 +1,31 @@
1
- MetricFu::Configuration.run do |config|
2
- require 'flog'
3
- config.add_metric(:flog)
4
- config.add_graph(:flog)
5
- config.configure_metric(:flog,
6
- { :dirs_to_flog => MetricFu.code_dirs }
7
- )
1
+ module MetricFu
2
+ class MetricFlog < Metric
3
+
4
+ def name
5
+ :flog
6
+ end
7
+
8
+ def default_run_options
9
+ { :dirs_to_flog => MetricFu::Io::FileSystem.directory('code_dirs'), :continue => true, :all => true, :quiet => true }
10
+ end
11
+
12
+ def has_graph?
13
+ true
14
+ end
15
+
16
+ def enable
17
+ if MetricFu.configuration.mri?
18
+ super
19
+ else
20
+ MetricFu.configuration.mf_debug("Flog is only available in MRI due to flog tasks")
21
+ end
22
+ end
23
+
24
+ def activate
25
+ activate_library 'flog'
26
+ activate_library 'flog_cli'
27
+ super
28
+ end
29
+
30
+ end
8
31
  end
@@ -1,3 +1,4 @@
1
+ require 'fileutils'
1
2
  module MetricFu
2
3
 
3
4
  # = Generator
@@ -39,6 +40,20 @@ module MetricFu
39
40
  create_data_dir_if_missing
40
41
  end
41
42
 
43
+ @generators = []
44
+ # @return all subclassed generators [Array<MetricFu::Generator>]
45
+ def self.generators
46
+ @generators
47
+ end
48
+
49
+ def self.get_generator(metric)
50
+ generators.find{|generator|generator.metric.to_s == metric.to_s.downcase}
51
+ end
52
+
53
+ def self.inherited(subclass)
54
+ @generators << subclass
55
+ end
56
+
42
57
  # Creates a new generator and returns the output of the
43
58
  # #generate_result method. This is the typical way to
44
59
  # generate a new MetricFu result. For more information see
@@ -70,7 +85,7 @@ module MetricFu
70
85
 
71
86
  # Returns the directory where the Generator will write any output
72
87
  def self.metric_directory
73
- File.join(MetricFu.scratch_directory, class_name)
88
+ File.join(MetricFu::Io::FileSystem.directory('scratch_directory'), class_name)
74
89
  end
75
90
 
76
91
  def create_metric_dir_if_missing #:nodoc:
@@ -80,14 +95,14 @@ module MetricFu
80
95
  end
81
96
 
82
97
  def create_output_dir_if_missing #:nodoc:
83
- unless File.directory?(MetricFu.output_directory)
84
- FileUtils.mkdir_p(MetricFu.output_directory, :verbose => false)
98
+ unless File.directory?(MetricFu::Io::FileSystem.directory('output_directory'))
99
+ FileUtils.mkdir_p(MetricFu::Io::FileSystem.directory('output_directory'), :verbose => false)
85
100
  end
86
101
  end
87
102
 
88
103
  def create_data_dir_if_missing #:nodoc:
89
- unless File.directory?(MetricFu.data_directory)
90
- FileUtils.mkdir_p(MetricFu.data_directory, :verbose => false)
104
+ unless File.directory?(MetricFu::Io::FileSystem.directory('data_directory'))
105
+ FileUtils.mkdir_p(MetricFu::Io::FileSystem.directory('data_directory'), :verbose => false)
91
106
  end
92
107
  end
93
108
 
@@ -97,7 +112,7 @@ module MetricFu
97
112
  self.class.metric_directory
98
113
  end
99
114
 
100
- def remove_excluded_files(paths, globs_to_remove = MetricFu.file_globs_to_ignore)
115
+ def remove_excluded_files(paths, globs_to_remove = MetricFu::Io::FileSystem.file_globs_to_ignore)
101
116
  files_to_remove = []
102
117
  globs_to_remove.each do |glob|
103
118
  files_to_remove.concat(Dir[glob])
@@ -12,7 +12,7 @@ module MetricFu
12
12
  self.clazz = []
13
13
  end
14
14
 
15
- def add(graph_type, graph_engine, output_directory = MetricFu.output_directory)
15
+ def add(graph_type, graph_engine, output_directory = MetricFu::Io::FileSystem.directory('output_directory'))
16
16
  grapher_name = graph_type.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } + graph_engine.to_s.capitalize + "Grapher"
17
17
  self.clazz.push MetricFu.const_get(grapher_name).new.tap{|g| g.output_directory = output_directory }
18
18
  end
@@ -21,7 +21,7 @@ module MetricFu
21
21
  def generate
22
22
  return if self.clazz.empty?
23
23
  mf_log "Generating graphs"
24
- Dir[File.join(MetricFu.data_directory, '*.yml')].sort.each do |metric_file|
24
+ Dir[File.join(MetricFu::Io::FileSystem.directory('data_directory'), '*.yml')].sort.each do |metric_file|
25
25
  mf_log "Generating graphs for #{metric_file}"
26
26
  date_parts = year_month_day_from_filename(metric_file)
27
27
  metrics = YAML::load(File.open(metric_file))
@@ -1,7 +1,11 @@
1
1
  MetricFu.metrics_require { 'hotspots/hotspot_analyzer' }
2
2
  module MetricFu
3
3
 
4
- class Hotspots < Generator
4
+ class HotspotsGenerator < Generator
5
+
6
+ def self.metric
7
+ :hotspots
8
+ end
5
9
 
6
10
  def initialize(options={})
7
11
  super
@@ -1,6 +1,22 @@
1
- # TODO remove explicit Churn dependency
2
- MetricFu::Configuration.run do |config|
3
- config.add_metric(:hotspots)
4
- config.configure_metric(:hotspots,
5
- { :start_date => "1 year ago", :minimum_churn_count => 10})
1
+ module MetricFu
2
+ class MetricHotspots < Metric
3
+
4
+ def name
5
+ :hotspots
6
+ end
7
+
8
+ # TODO remove explicit Churn dependency
9
+ def default_run_options
10
+ { :start_date => "1 year ago", :minimum_churn_count => 10}
11
+ end
12
+
13
+ def has_graph?
14
+ false
15
+ end
16
+
17
+ def enable
18
+ super
19
+ end
20
+
21
+ end
6
22
  end