metric_fu 4.4.0 → 4.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +12 -0
  3. data/Rakefile +0 -1
  4. data/bin/mf-roodi +2 -2
  5. data/checksum/metric_fu-4.4.0.gem.sha512 +1 -1
  6. data/gem_tasks/build.rake +24 -22
  7. data/lib/metric_fu/configuration.rb +0 -10
  8. data/lib/metric_fu/data_structures/line_numbers.rb +2 -0
  9. data/lib/metric_fu/initial_requires.rb +0 -1
  10. data/lib/metric_fu/metric.rb +1 -1
  11. data/lib/metric_fu/metrics/churn/churn_hotspot.rb +10 -11
  12. data/lib/metric_fu/metrics/flay/flay_hotspot.rb +7 -20
  13. data/lib/metric_fu/metrics/flog/flog_hotspot.rb +7 -14
  14. data/lib/metric_fu/metrics/generator.rb +0 -14
  15. data/lib/metric_fu/metrics/graph.rb +50 -15
  16. data/lib/metric_fu/metrics/hotspots/analysis/analyzed_problems.rb +21 -27
  17. data/lib/metric_fu/metrics/hotspots/analysis/analyzer_tables.rb +0 -6
  18. data/lib/metric_fu/metrics/hotspots/analysis/grouping.rb +2 -17
  19. data/lib/metric_fu/metrics/hotspots/analysis/groupings.rb +1 -9
  20. data/lib/metric_fu/metrics/hotspots/analysis/problems.rb +3 -7
  21. data/lib/metric_fu/metrics/hotspots/analysis/ranking.rb +3 -7
  22. data/lib/metric_fu/metrics/hotspots/analysis/rankings.rb +6 -6
  23. data/lib/metric_fu/metrics/hotspots/analysis/record.rb +3 -12
  24. data/lib/metric_fu/metrics/hotspots/analysis/scoring_strategies.rb +9 -14
  25. data/lib/metric_fu/metrics/hotspots/analysis/table.rb +3 -43
  26. data/lib/metric_fu/metrics/hotspots/hotspot.rb +59 -7
  27. data/lib/metric_fu/metrics/hotspots/hotspot_analyzer.rb +1 -36
  28. data/lib/metric_fu/metrics/hotspots/hotspots.rb +0 -4
  29. data/lib/metric_fu/metrics/rails_best_practices/init.rb +0 -1
  30. data/lib/metric_fu/metrics/rcov/rcov_hotspot.rb +6 -13
  31. data/lib/metric_fu/metrics/reek/reek_hotspot.rb +6 -87
  32. data/lib/metric_fu/metrics/roodi/roodi_hotspot.rb +7 -18
  33. data/lib/metric_fu/metrics/saikuro/saikuro.rb +0 -5
  34. data/lib/metric_fu/metrics/saikuro/saikuro_hotspot.rb +7 -14
  35. data/lib/metric_fu/metrics/stats/stats_hotspot.rb +7 -7
  36. data/lib/metric_fu/reporting/templates/awesome/awesome_template.rb +2 -1
  37. data/lib/metric_fu/utility.rb +20 -0
  38. data/lib/metric_fu/version.rb +1 -1
  39. data/metric_fu.gemspec +6 -6
  40. data/spec/metric_fu/configuration_spec.rb +2 -21
  41. data/spec/metric_fu/metrics/flog/flog_grapher_spec.rb +2 -2
  42. data/spec/metric_fu/metrics/generator_spec.rb +0 -14
  43. data/spec/metric_fu/metrics/graph_spec.rb +7 -6
  44. data/spec/metric_fu/metrics/hotspots/analysis/analyzed_problems_spec.rb +113 -0
  45. data/spec/metric_fu/metrics/hotspots/analysis/analyzer_tables_spec.rb +71 -0
  46. data/spec/metric_fu/metrics/hotspots/analysis/ranking_spec.rb +3 -12
  47. data/spec/metric_fu/metrics/hotspots/analysis/rankings_spec.rb +100 -0
  48. data/spec/metric_fu/metrics/hotspots/analysis/table_spec.rb +1 -30
  49. data/spec/metric_fu/metrics/hotspots/hotspot_analyzer_spec.rb +3 -442
  50. data/spec/metric_fu/metrics/rcov/rcov_spec.rb +2 -0
  51. data/spec/metric_fu/metrics/saikuro/saikuro_spec.rb +0 -11
  52. data/spec/resources/yml/hotspots/flog.yml +86 -0
  53. data/spec/resources/yml/hotspots/reek.yml +14 -0
  54. data/spec/resources/yml/hotspots/roodi.yml +13 -0
  55. data/spec/resources/yml/hotspots/saikuro.yml +27 -0
  56. data/spec/resources/yml/hotspots/several_metrics.yml +47 -0
  57. data/spec/resources/yml/hotspots/stats.yml +4 -0
  58. data/spec/resources/yml/hotspots/three_metrics_on_same_file.yml +36 -0
  59. data/spec/support/helper_methods.rb +13 -0
  60. metadata +62 -21
  61. data/lib/metric_fu/data_structures/careful_array.rb +0 -11
  62. data/lib/metric_fu/metrics/hotspots/analysis/code_issue.rb +0 -109
  63. data/lib/metric_fu/parser_ext.rb +0 -15
  64. data/lib/metric_fu/sexp_ext.rb +0 -11
@@ -97,12 +97,6 @@ module MetricFu
97
97
  @file_paths ||= @table.column('file_path').uniq
98
98
  end
99
99
 
100
- # These tables are an optimization. They contain subsets of the master table.
101
- # TODO - these should be pushed into the Table class now
102
- def optimized_tables
103
- @optimized_tables ||= make_table_hash(@columns)
104
- end
105
-
106
100
  def file_tables
107
101
  @file_tables ||= make_table_hash(@columns)
108
102
  end
@@ -6,28 +6,13 @@ module MetricFu
6
6
 
7
7
  def initialize(table, opts)
8
8
  column_name = opts.fetch(:by)
9
- order = opts.fetch(:order) { nil }
10
9
  hash = {}
11
10
  if column_name.to_sym == :metric # special optimized case
12
11
  hash = table.group_by_metric
13
12
  else
14
- table.each do |row|
15
- hash[row[column_name]] ||= MetricFu::Table.new(:column_names => row.attributes)
16
- hash[row[column_name]] << row
17
- end
13
+ raise "Unexpected column_name #{column_name}"
18
14
  end
19
- if order
20
- @arr = hash.sort_by(&order)
21
- else
22
- @arr = hash.to_a
23
- end
24
- end
25
-
26
- def [](key)
27
- @arr.each do |group_key, table|
28
- return table if group_key == key
29
- end
30
- return nil
15
+ @arr = hash.to_a
31
16
  end
32
17
 
33
18
  def each
@@ -4,18 +4,10 @@ module MetricFu
4
4
  def initialize(table, opts)
5
5
  @table, @opts = table, opts
6
6
  end
7
+
7
8
  def get_grouping
8
- #Ruport::Data::Grouping.new(table, opts)
9
9
  MetricFu::Grouping.new(@table, @opts)
10
- #@grouping_cache ||= {}
11
- #@grouping_cache.fetch(grouping_key(table,opts)) do
12
- # @grouping_cache[grouping_key(table,opts)] = Ruport::Data::Grouping.new(table, opts)
13
- #end
14
10
  end
15
11
 
16
- # UNUSED
17
- # def grouping_key(table, opts)
18
- # "table #{table.object_id} opts #{opts.inspect}"
19
- # end
20
12
  end
21
13
  end
@@ -1,18 +1,14 @@
1
1
  module MetricFu
2
2
  class HotspotProblems
3
3
 
4
- def initialize(grouping, details, exclude_details)
5
- @grouping, @details, @exclude_details = grouping, details, exclude_details
4
+ def initialize(grouping)
5
+ @grouping = grouping
6
6
  end
7
7
 
8
8
  def problems
9
9
  problems = {}
10
10
  @grouping.each do |metric, table|
11
- if @details == :summary || @exclude_details.include?(metric)
12
- problems[metric] = MetricFu::Hotspot.analyzer_for_metric(metric).present_group(table)
13
- else
14
- problems[metric] = MetricFu::Hotspot.analyzer_for_metric(metric).present_group_details(table)
15
- end
11
+ problems[metric] = MetricFu::Hotspot.analyzer_for_metric(metric).present_group(table)
16
12
  end
17
13
  problems
18
14
  end
@@ -7,12 +7,8 @@ module MetricFu
7
7
  @items_to_score = {}
8
8
  end
9
9
 
10
- def top(num=nil)
11
- if(num.is_a?(Numeric))
12
- sorted_items[0,num]
13
- else
14
- sorted_items
15
- end
10
+ def top
11
+ sorted_items
16
12
  end
17
13
 
18
14
  def percentile(item)
@@ -22,7 +18,7 @@ module MetricFu
22
18
  end
23
19
 
24
20
  def_delegator :@items_to_score, :has_key?, :scored?
25
- def_delegators :@items_to_score, :[], :[]=, :length, :each, :delete
21
+ def_delegators :@items_to_score, :[], :[]=, :length, :each, :delete, :fetch
26
22
 
27
23
  private
28
24
 
@@ -14,19 +14,19 @@ module MetricFu
14
14
  end
15
15
  end
16
16
 
17
- def worst_methods(size = nil)
17
+ def worst_methods
18
18
  @method_ranking.delete(nil)
19
- @method_ranking.top(size)
19
+ @method_ranking.top
20
20
  end
21
21
 
22
- def worst_classes(size = nil)
22
+ def worst_classes
23
23
  @class_ranking.delete(nil)
24
- @class_ranking.top(size)
24
+ @class_ranking.top
25
25
  end
26
26
 
27
- def worst_files(size = nil)
27
+ def worst_files
28
28
  @file_ranking.delete(nil)
29
- @file_ranking.top(size)
29
+ @file_ranking.top
30
30
  end
31
31
 
32
32
  private
@@ -5,15 +5,14 @@ module MetricFu
5
5
 
6
6
  def initialize(data, columns)
7
7
  @data = data
8
- @columns = columns
9
8
  end
10
9
 
11
10
  def method_missing(name, *args, &block)
12
11
  key = name.to_s
13
- if @data.has_key?(key)
12
+ if key == 'fetch'
13
+ @data.send(name, *args, &block)
14
+ elsif @data.has_key?(key)
14
15
  @data[key]
15
- elsif @columns.member?(key)
16
- nil
17
16
  else
18
17
  super(name, *args, &block)
19
18
  end
@@ -27,17 +26,9 @@ module MetricFu
27
26
  @data[key]
28
27
  end
29
28
 
30
- def keys
31
- @data.keys
32
- end
33
-
34
29
  def has_key?(key)
35
30
  @data.has_key?(key)
36
31
  end
37
32
 
38
- def attributes
39
- @columns
40
- end
41
-
42
33
  end
43
34
  end
@@ -1,31 +1,26 @@
1
1
  module MetricFu
2
2
  module HotspotScoringStrategies
3
3
 
4
+ module_function
5
+
6
+ # per project score percentile
4
7
  def percentile(ranking, item)
5
- ranking.percentile(item) # per project score percentile
8
+ ranking.percentile(item)
6
9
  end
7
10
 
11
+ # Use the score you got
12
+ # (ex flog score of 20 is not bad even if it is the top one in project)
8
13
  def identity(ranking, item)
9
- ranking[item] # Use the score you got (ex flog score of 20 is not bad even if it is the top one in project)
10
- end
11
-
12
- def present(row)
13
- 1 # If present it's a one, not present it's a zero - For things like Reek that don't have a number
14
+ ranking.fetch(item)
14
15
  end
15
16
 
16
17
  def sum(scores)
17
- scores.inject(0) {|s,x| s+x}
18
+ scores.inject(&:+)
18
19
  end
19
20
 
20
21
  def average(scores)
21
- # remove dependency on statarray
22
- # scores.to_statarray.mean
23
- score_length = scores.length
24
- total = 0
25
- total= scores.inject( nil ) { |sum,x| sum ? sum+x : x }
26
- (total.to_f / score_length.to_f)
22
+ sum(scores).to_f / scores.size.to_f
27
23
  end
28
24
 
29
- extend self
30
25
  end
31
26
  end
@@ -1,9 +1,10 @@
1
- %w(record code_issue).each do |path|
1
+ %w(record).each do |path|
2
2
  MetricFu.metrics_require { "hotspots/analysis/#{path}" }
3
3
  end
4
4
 
5
5
  module MetricFu
6
6
  class Table
7
+ include Enumerable
7
8
 
8
9
  def initialize(opts = {})
9
10
  @rows = []
@@ -15,7 +16,7 @@ module MetricFu
15
16
 
16
17
  def <<(row)
17
18
  record = nil
18
- if row.is_a?(MetricFu::Record) || row.is_a?(MetricFu::CodeIssue)
19
+ if row.is_a?(MetricFu::Record)
19
20
  record = row
20
21
  else
21
22
  record = MetricFu::Record.new(row, @columns)
@@ -54,49 +55,8 @@ module MetricFu
54
55
  @metric_index.to_a
55
56
  end
56
57
 
57
- def rows_with(conditions)
58
- if optimized_conditions?(conditions)
59
- optimized_select(conditions)
60
- else
61
- slow_select(conditions)
62
- end
63
- end
64
-
65
- def delete_at(index)
66
- @rows.delete_at(index)
67
- end
68
-
69
- def to_a
70
- @rows
71
- end
72
-
73
- def map
74
- new_table = MetricFu::Table.new(:column_names => @columns)
75
- @rows.map do |row|
76
- new_table << (yield row)
77
- end
78
- new_table
79
- end
80
-
81
58
  private
82
59
 
83
- def optimized_conditions?(conditions)
84
- conditions.keys.length == 1 && conditions.keys.first.to_sym == :metric
85
- end
86
-
87
- def optimized_select(conditions)
88
- metric = (conditions['metric'] || conditions[:metric]).to_s
89
- @metric_index[metric].to_a.clone
90
- end
91
-
92
- def slow_select(conditions)
93
- @rows.select do |row|
94
- conditions.all? do |key, value|
95
- row.has_key?(key.to_s) && row[key.to_s] == value
96
- end
97
- end
98
- end
99
-
100
60
  def updated_key_index(record)
101
61
  if record.has_key?('metric')
102
62
  @metric_index[record.metric] ||= MetricFu::Table.new(:column_names => @columns, :make_index => false)
@@ -1,7 +1,7 @@
1
1
  module MetricFu
2
2
  class Hotspot
3
3
  def self.metric
4
- self.name.split('Hotspot')[0].downcase.to_sym
4
+ self.name.split('::')[-1].split('Hotspot')[0].downcase.to_sym
5
5
  end
6
6
  @analyzers = {}
7
7
  def self.analyzers
@@ -18,13 +18,65 @@ module MetricFu
18
18
  @analyzers[subclass.metric] = subclass.new
19
19
  end
20
20
 
21
- # TODO simplify calculation
22
- # DUPLICATES CODE IN ScoringStrategies
23
21
  def get_mean(collection)
24
- collection_length = collection.length
25
- total = 0
26
- total = collection.inject( nil ) { |sum,x| sum ? sum+x : x }
27
- (total.to_f / collection_length.to_f)
22
+ MetricFu::HotspotScoringStrategies.average(collection)
23
+ end
24
+
25
+ def map(row)
26
+ mapping_strategies.fetch(map_strategy) { row.public_send(map_strategy) }
27
+ end
28
+
29
+ def mapping_strategies
30
+ {
31
+ :present => 1,
32
+ :absent => 0,
33
+ }
34
+ end
35
+
36
+ def map_strategy
37
+ not_implemented
38
+ end
39
+
40
+ def reduce(scores)
41
+ {
42
+ :average => MetricFu::HotspotScoringStrategies.average(scores),
43
+ :sum => MetricFu::HotspotScoringStrategies.sum(scores),
44
+ :absent => 0,
45
+ }.fetch(reduce_strategy) { raise "#{reduce_strategy} not a know reduce strategy" }
46
+ end
47
+
48
+ def reduce_strategy
49
+ not_implemented
50
+ end
51
+
52
+ # @return [Integer]
53
+ def score(metric_ranking, item)
54
+ {
55
+ :identity => MetricFu::HotspotScoringStrategies.identity(metric_ranking, item),
56
+ :percentile => MetricFu::HotspotScoringStrategies.percentile(metric_ranking, item),
57
+ :absent => 0,
58
+ }.fetch(score_strategy) { method(score_strategy).call(metric_ranking, item) }
59
+ end
60
+
61
+ def score_strategy
62
+ not_implemented
63
+ end
64
+
65
+ # Transforms the data param, if non-nil, into a hash with keys:
66
+ # 'metric', etc.
67
+ # and appends the hash to the table param
68
+ # Has no return value
69
+ def generate_records(data, table)
70
+ not_implemented
71
+ end
72
+
73
+ # @return [String] description result
74
+ def present_group(group)
75
+ not_implemented
76
+ end
77
+
78
+ def not_implemented
79
+ raise "#{caller[0]} not implemented"
28
80
  end
29
81
  end
30
82
  end
@@ -11,9 +11,6 @@ module MetricFu
11
11
  COMMON_COLUMNS = %w{metric}
12
12
  GRANULARITIES = %w{file_path class_name method_name}
13
13
 
14
- # TODO , UNUSED
15
- # attr_accessor :table
16
-
17
14
  def tool_analyzers
18
15
  MetricFu::Hotspot.analyzers
19
16
  end
@@ -25,7 +22,6 @@ module MetricFu
25
22
  setup(result_hash)
26
23
  end
27
24
 
28
- # def worst_items; previous method name
29
25
  def hotspots
30
26
  analyzed_problems.worst_items
31
27
  end
@@ -33,14 +29,6 @@ module MetricFu
33
29
  def analyzed_problems
34
30
  @analyzed_problems = MetricFu::HotspotAnalyzedProblems.new(@rankings, @analyzer_tables)
35
31
  end
36
- # just for testing
37
- # TODO remove the delegators
38
- # and refactor the tests
39
- alias_method :worst_items, :hotspots
40
- extend Forwardable
41
- def_delegators :@analyzer_tables, :table
42
- def_delegators :@analyzed_problems, :problems_with, :location
43
- def_delegators :@rankings, :worst_files, :worst_methods, :worst_classes
44
32
 
45
33
  private
46
34
 
@@ -52,7 +40,7 @@ module MetricFu
52
40
  # TODO There is likely a clash that will happen between
53
41
  # column names eventually. We should probably auto-prefix
54
42
  # them (e.g. "roodi_problem")
55
- analyzer_columns = COMMON_COLUMNS + GRANULARITIES + tool_analyzers.map{|analyzer| analyzer.columns}.flatten
43
+ analyzer_columns = COMMON_COLUMNS + GRANULARITIES + tool_analyzers.map(&:columns).flatten
56
44
  # though the tool_analyzers aren't returned, they are processed in
57
45
  # various places here, then by the analyzer tables
58
46
  # then by the rankings
@@ -64,33 +52,10 @@ module MetricFu
64
52
  @analyzer_tables.generate_records
65
53
  @rankings = MetricFu::HotspotRankings.new(@analyzer_tables.tool_tables)
66
54
  @rankings.calculate_scores(tool_analyzers, GRANULARITIES)
67
- # just for testing
68
55
  # TODO does it not need to return something here?
69
56
  analyzed_problems
70
57
  end
71
58
 
72
- # TODO remove, UNUSED
73
- # def most_common_column(column_name, size)
74
- # #grouping = Ruport::Data::Grouping.new(@table,
75
- # # :by => column_name,
76
- # # :order => lambda { |g| -g.size})
77
- # get_grouping(@table, :by => column_name, :order => lambda {|g| -g.size})
78
- # values = []
79
- # grouping.each do |value, _|
80
- # values << value if value!=nil
81
- # if(values.size==size)
82
- # break
83
- # end
84
- # end
85
- # return nil if values.empty?
86
- # if(values.size == 1)
87
- # return values.first
88
- # else
89
- # return values
90
- # end
91
- # end
92
-
93
-
94
59
 
95
60
  end
96
61
  end
@@ -11,10 +11,6 @@ module MetricFu
11
11
  super
12
12
  end
13
13
 
14
- def self.verify_dependencies!
15
- true
16
- end
17
-
18
14
  def emit
19
15
  @analyzer = MetricFu::HotspotAnalyzer.new(MetricFu.result.result_hash)
20
16
  end