metric_fu 1.5.1 → 2.0.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.
- data/HISTORY +5 -0
- data/MIT-LICENSE +1 -1
- data/README +8 -6
- data/Rakefile +5 -3
- data/TODO +0 -5
- data/lib/base/base_template.rb +16 -0
- data/lib/base/churn_analyzer.rb +52 -0
- data/lib/base/code_issue.rb +97 -0
- data/lib/base/configuration.rb +4 -2
- data/lib/base/flay_analyzer.rb +50 -0
- data/lib/base/flog_analyzer.rb +43 -0
- data/lib/base/line_numbers.rb +65 -0
- data/lib/base/location.rb +83 -0
- data/lib/base/metric_analyzer.rb +404 -0
- data/lib/base/ranking.rb +33 -0
- data/lib/base/rcov_analyzer.rb +43 -0
- data/lib/base/reek_analyzer.rb +114 -0
- data/lib/base/roodi_analyzer.rb +37 -0
- data/lib/base/saikuro_analyzer.rb +48 -0
- data/lib/base/scoring_strategies.rb +29 -0
- data/lib/base/stats_analyzer.rb +37 -0
- data/lib/base/table.rb +102 -0
- data/lib/generators/hotspots.rb +52 -0
- data/lib/generators/rcov.rb +41 -0
- data/lib/metric_fu.rb +5 -3
- data/lib/templates/awesome/hotspots.html.erb +54 -0
- data/lib/templates/awesome/index.html.erb +3 -0
- data/lib/templates/standard/hotspots.html.erb +54 -0
- data/spec/base/line_numbers_spec.rb +62 -0
- data/spec/generators/rails_best_practices_spec.rb +52 -0
- data/spec/generators/rcov_spec.rb +180 -0
- data/spec/generators/roodi_spec.rb +24 -0
- data/spec/graphs/rails_best_practices_grapher_spec.rb +61 -0
- data/spec/graphs/stats_grapher_spec.rb +68 -0
- data/spec/resources/line_numbers/foo.rb +33 -0
- data/spec/resources/line_numbers/module.rb +11 -0
- data/spec/resources/line_numbers/module_surrounds_class.rb +15 -0
- data/spec/resources/line_numbers/two_classes.rb +11 -0
- data/spec/resources/yml/metric_missing.yml +1 -0
- metadata +51 -11
data/HISTORY
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
=== MetricFu 2.0.0 / 2010-11-10
|
2
|
+
|
3
|
+
* Hotspots - Dan Mayer, Ben Brinckerhoff, Jake Scruggs
|
4
|
+
* Rcov integration with Hotspots - Jake Scruggs, Tony Castiglione, Rob Meyer
|
5
|
+
|
1
6
|
=== MetricFu 1.5.1 / 2010-7-28
|
2
7
|
|
3
8
|
* Patch that allows graphers to skip dates that didn't generate metrics for that graph (GitHub Issue #20). - Chris Griego
|
data/MIT-LICENSE
CHANGED
data/README
CHANGED
@@ -3,12 +3,13 @@ See http://metric-fu.rubyforge.org/ for documentation, or the HISTORY file for a
|
|
3
3
|
How to contribute:
|
4
4
|
|
5
5
|
1. Fork metric_fu on github.
|
6
|
-
2. 'gem install metric_fu
|
7
|
-
3.
|
8
|
-
4. Run
|
9
|
-
5.
|
10
|
-
6. Make
|
11
|
-
7.
|
6
|
+
2. 'gem install metric_fu' #to get gem dependencies
|
7
|
+
3. Install the gems RSpec 1.3.0, test-construct, and googlecharts
|
8
|
+
4. Run the tests ('rake')
|
9
|
+
5. Run metric_fu on itself ('rake metrics:all')
|
10
|
+
6. Make the changes you want and back them up with tests.
|
11
|
+
7. Make sure two important rake tests still run ('rake' and 'rake metrics:all')
|
12
|
+
8. Commit and send me a pull request with details as to what has been changed.
|
12
13
|
|
13
14
|
Extra Credit:
|
14
15
|
1. Make sure your changes work in 1.8.7, Ruby Enterprise Edition, and 1.9.1 (Hint use 'rvm' to help install multiple rubies)
|
@@ -24,4 +25,5 @@ Resources:
|
|
24
25
|
Homepage: http://metric-fu.rubyforge.org/
|
25
26
|
Github: http://github.com/jscruggs/metric_fu
|
26
27
|
Google Group: http://groups.google.com/group/metric_fu
|
28
|
+
Issue Tracker: http://github.com/jscruggs/metric_fu/issues
|
27
29
|
My Blog: http://jakescruggs.blogspot.com/
|
data/Rakefile
CHANGED
@@ -8,9 +8,11 @@ desc "Run all specs in spec directory"
|
|
8
8
|
Spec::Rake::SpecTask.new(:spec) do |t|
|
9
9
|
t.spec_files = FileList['spec/**/*_spec.rb']
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
MetricFu::Configuration.run do |config|
|
13
|
-
config.roodi
|
13
|
+
config.roodi = config.roodi.merge(:roodi_config => 'config/roodi_config.yml')
|
14
|
+
config.churn = { :start_date => "1 year ago", :minimum_churn_count => 10}
|
15
|
+
config.hotspots = { :start_date => "1 year ago", :minimum_churn_count => 10}
|
14
16
|
end
|
15
|
-
|
17
|
+
|
16
18
|
task :default => :spec
|
data/TODO
CHANGED
@@ -1,9 +1,4 @@
|
|
1
1
|
== TODO list
|
2
2
|
|
3
3
|
* Color code flog results with scale from: http://jakescruggs.blogspot.com/2008/08/whats-good-flog-score.html
|
4
|
-
* Integrate Flog, Saikuro, and Coverage into one report so you can see methods that have high complexity and low coverage (this is a big one)
|
5
|
-
* Update flog specs so that they actually run flog
|
6
|
-
* Add flay specs that run flay
|
7
|
-
* Convert readme to markdown and rename to README.mkdn so github will render it
|
8
|
-
* Saikuro.rb falls over if tries to parse an empty file. Fair enough. We shouldn't feed it empty files
|
9
4
|
* Make running metric_fu on metric_fu less embarrassing
|
data/lib/base/base_template.rb
CHANGED
@@ -117,6 +117,22 @@ module MetricFu
|
|
117
117
|
name
|
118
118
|
end
|
119
119
|
end
|
120
|
+
|
121
|
+
def display_location(location, stat)
|
122
|
+
file_path, class_name, method_name = location.file_path, location.class_name, location.method_name
|
123
|
+
str = ""
|
124
|
+
str += link_to_filename(file_path)
|
125
|
+
str += " : " if method_name || class_name
|
126
|
+
if(method_name)
|
127
|
+
str += "#{method_name}"
|
128
|
+
else
|
129
|
+
#TODO HOTSPOTS BUG ONLY exists on move over to metric_fu
|
130
|
+
if class_name.is_a?(String)
|
131
|
+
str+= "#{class_name}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
str
|
135
|
+
end
|
120
136
|
|
121
137
|
def file_url(name, line) # :nodoc:
|
122
138
|
return '' unless name
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class ChurnAnalyzer
|
2
|
+
include ScoringStrategies
|
3
|
+
|
4
|
+
COLUMNS = %w{times_changed}
|
5
|
+
|
6
|
+
def columns
|
7
|
+
COLUMNS
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
:churn
|
12
|
+
end
|
13
|
+
|
14
|
+
def map(row)
|
15
|
+
ScoringStrategies.present(row)
|
16
|
+
end
|
17
|
+
|
18
|
+
def reduce(scores)
|
19
|
+
ScoringStrategies.sum(scores)
|
20
|
+
end
|
21
|
+
|
22
|
+
def score(metric_ranking, item)
|
23
|
+
flat_churn_score = 0.50
|
24
|
+
metric_ranking.scored?(item) ? flat_churn_score : 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_records(data, table)
|
28
|
+
return if data==nil
|
29
|
+
Array(data[:changes]).each do |change|
|
30
|
+
table << {
|
31
|
+
"metric" => :churn,
|
32
|
+
"times_changed" => change[:times_changed],
|
33
|
+
"file_path" => change[:file_path]
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def self.update_changes(total, changed)
|
41
|
+
changed.each do |change|
|
42
|
+
#should work as has_key(change), but hash == doesn't work on 1.8.6 here for some reason it never matches
|
43
|
+
if total.has_key?(change.to_a.sort)
|
44
|
+
total[change.to_a.sort] += 1
|
45
|
+
else
|
46
|
+
total[change.to_a.sort] = 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
total
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require MetricFu::LIB_ROOT + '/base/metric_analyzer'
|
3
|
+
require MetricFu::LIB_ROOT + '/base/flog_analyzer'
|
4
|
+
require MetricFu::LIB_ROOT + '/base/saikuro_analyzer'
|
5
|
+
require MetricFu::LIB_ROOT + '/base/churn_analyzer'
|
6
|
+
require MetricFu::LIB_ROOT + '/base/reek_analyzer'
|
7
|
+
require MetricFu::LIB_ROOT + '/base/flay_analyzer'
|
8
|
+
|
9
|
+
module CarefulArray
|
10
|
+
|
11
|
+
def carefully_remove(elements)
|
12
|
+
missing_elements = elements - self
|
13
|
+
raise "Cannot delete missing elements: #{missing_elements.inspect}" unless missing_elements.empty?
|
14
|
+
(self - elements).extend(CarefulArray)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
class CodeIssue < DelegateClass(Record) #DelegateClass(Ruport::Data::Record)
|
20
|
+
include Comparable
|
21
|
+
|
22
|
+
# TODO: Yuck! 'stat_value' is a column for StatAnalyzer
|
23
|
+
EXCLUDED_COLUMNS = FlogAnalyzer::COLUMNS + SaikuroAnalyzer::COLUMNS + ['stat_value'] + ChurnAnalyzer::COLUMNS + ReekAnalyzer.new.columns.extend(CarefulArray).carefully_remove(['reek__type_name', 'reek__comparable_message']) + FlayAnalyzer.new.columns.extend(CarefulArray).carefully_remove(['flay_matching_reason'])
|
24
|
+
|
25
|
+
def <=>(other)
|
26
|
+
spaceship_for_columns(self.attributes, other)
|
27
|
+
end
|
28
|
+
|
29
|
+
def ===(other)
|
30
|
+
self.hash_for(included_columns_hash, included_columns) == other.hash_for(included_columns_hash, included_columns)
|
31
|
+
end
|
32
|
+
|
33
|
+
def spaceship_for_columns(columns, other)
|
34
|
+
columns.each do |column|
|
35
|
+
equality = self[column].to_s <=> other[column].to_s
|
36
|
+
return equality if equality!=0
|
37
|
+
end
|
38
|
+
return 0
|
39
|
+
end
|
40
|
+
|
41
|
+
def hash_for(column_hash, columns)
|
42
|
+
@hashes ||= {}
|
43
|
+
# fetch would be cleaner, but slower
|
44
|
+
if @hashes.has_key?(column_hash)
|
45
|
+
@hashes[column_hash]
|
46
|
+
else
|
47
|
+
values = columns.map {|column| self[column]}
|
48
|
+
hash_for_columns = values.join('').hash
|
49
|
+
@hashes[column_hash]=hash_for_columns
|
50
|
+
hash_for_columns
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def included_columns_hash
|
55
|
+
@included_columns_hash ||= included_columns.hash
|
56
|
+
end
|
57
|
+
|
58
|
+
def included_columns
|
59
|
+
@included_columns ||= self.attributes.extend(CarefulArray).carefully_remove(EXCLUDED_COLUMNS)
|
60
|
+
end
|
61
|
+
|
62
|
+
def find_counterpart_index_in(collection)
|
63
|
+
# each_with_index is cleaner, but it is slower and we
|
64
|
+
# spend a lot of time in this loop
|
65
|
+
index = 0
|
66
|
+
collection.each do |issue|
|
67
|
+
return index if self === issue
|
68
|
+
index += 1
|
69
|
+
end
|
70
|
+
return nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def modifies?(other)
|
74
|
+
case self.metric
|
75
|
+
when :reek
|
76
|
+
#return false unless ["Large Class", "Long Method", "Long Parameter List"].include?(self.reek__type_name)
|
77
|
+
return false if self.reek__type_name != other.reek__type_name
|
78
|
+
self.reek__value != other.reek__value
|
79
|
+
when :flog
|
80
|
+
self.score != other.score
|
81
|
+
when :saikuro
|
82
|
+
self.complexity != other.complexity
|
83
|
+
when :stats
|
84
|
+
self.stat_value != other.stat_value
|
85
|
+
when :churn
|
86
|
+
self.times_changed != other.times_changed
|
87
|
+
when :flay
|
88
|
+
#self.flay_reason != other.flay_reason
|
89
|
+
# do nothing for now
|
90
|
+
when :roodi, :stats
|
91
|
+
# do nothing
|
92
|
+
else
|
93
|
+
raise ArgumentError, "Invalid metric type #{self.metric}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
data/lib/base/configuration.rb
CHANGED
@@ -6,7 +6,8 @@ module MetricFu
|
|
6
6
|
# course, in order to use these metrics, their respective gems must
|
7
7
|
# be installed on the system.
|
8
8
|
AVAILABLE_METRICS = [:churn, :flog, :flay, :reek,
|
9
|
-
:roodi, :saikuro, :rcov
|
9
|
+
:roodi, :saikuro, :rcov,
|
10
|
+
:hotspots]
|
10
11
|
|
11
12
|
AVAILABLE_GRAPHS = [:flog, :flay, :reek, :roodi, :rcov, :rails_best_practices]
|
12
13
|
AVAILABLE_GRAPH_ENGINES = [:gchart, :bluff]
|
@@ -139,6 +140,7 @@ module MetricFu
|
|
139
140
|
:external => nil
|
140
141
|
}
|
141
142
|
@rails_best_practices = {}
|
143
|
+
@hotspots = {}
|
142
144
|
@file_globs_to_ignore = []
|
143
145
|
|
144
146
|
@graph_engine = :bluff # can be :bluff or :gchart
|
@@ -159,7 +161,7 @@ module MetricFu
|
|
159
161
|
@metrics = MetricFu::AVAILABLE_METRICS + [:stats, :rails_best_practices]
|
160
162
|
else
|
161
163
|
@metrics = MetricFu::AVAILABLE_METRICS
|
162
|
-
end
|
164
|
+
end
|
163
165
|
end
|
164
166
|
|
165
167
|
def set_graphs
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class FlayAnalyzer
|
2
|
+
include ScoringStrategies
|
3
|
+
|
4
|
+
COLUMNS = %w{flay_reason flay_matching_reason}
|
5
|
+
|
6
|
+
def columns
|
7
|
+
COLUMNS
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
:flay
|
12
|
+
end
|
13
|
+
|
14
|
+
def map(row)
|
15
|
+
ScoringStrategies.present(row)
|
16
|
+
end
|
17
|
+
|
18
|
+
def reduce(scores)
|
19
|
+
ScoringStrategies.sum(scores)
|
20
|
+
end
|
21
|
+
|
22
|
+
def score(metric_ranking, item)
|
23
|
+
ScoringStrategies.percentile(metric_ranking, item)
|
24
|
+
end
|
25
|
+
|
26
|
+
def generate_records(data, table)
|
27
|
+
return if data==nil
|
28
|
+
Array(data[:matches]).each do |match|
|
29
|
+
problems = match[:reason]
|
30
|
+
matching_reason = problems.gsub(/^[0-9]+\) /,'').gsub(/\:[0-9]+/,'')
|
31
|
+
files = []
|
32
|
+
locations = []
|
33
|
+
match[:matches].each do |file_match|
|
34
|
+
file_path = file_match[:name].sub(%r{^/},'')
|
35
|
+
locations << "#{file_path}:#{file_match[:line]}"
|
36
|
+
files << file_path
|
37
|
+
end
|
38
|
+
files = files.uniq
|
39
|
+
files.each do |file|
|
40
|
+
table << {
|
41
|
+
"metric" => self.name,
|
42
|
+
"file_path" => file,
|
43
|
+
"flay_reason" => problems+" files: #{locations.join(', ')}",
|
44
|
+
"flay_matching_reason" => matching_reason
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class FlogAnalyzer
|
2
|
+
include ScoringStrategies
|
3
|
+
|
4
|
+
COLUMNS = %w{score}
|
5
|
+
|
6
|
+
def columns
|
7
|
+
COLUMNS
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
:flog
|
12
|
+
end
|
13
|
+
|
14
|
+
def map(row)
|
15
|
+
row.score
|
16
|
+
end
|
17
|
+
|
18
|
+
def reduce(scores)
|
19
|
+
ScoringStrategies.average(scores)
|
20
|
+
end
|
21
|
+
|
22
|
+
def score(metric_ranking, item)
|
23
|
+
ScoringStrategies.identity(metric_ranking, item)
|
24
|
+
end
|
25
|
+
|
26
|
+
def generate_records(data, table)
|
27
|
+
return if data==nil
|
28
|
+
Array(data[:method_containers]).each do |method_container|
|
29
|
+
Array(method_container[:methods]).each do |entry|
|
30
|
+
file_path = entry[1][:path].sub(%r{^/},'') if entry[1][:path]
|
31
|
+
location = Location.for(entry.first)
|
32
|
+
table << {
|
33
|
+
"metric" => name,
|
34
|
+
"score" => entry[1][:score],
|
35
|
+
"file_path" => file_path,
|
36
|
+
"class_name" => location.class_name,
|
37
|
+
"method_name" => location.method_name
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'ruby_parser'
|
2
|
+
|
3
|
+
class LineNumbers
|
4
|
+
|
5
|
+
def initialize(contents)
|
6
|
+
rp = RubyParser.new
|
7
|
+
file_sexp = rp.parse(contents)
|
8
|
+
@locations = {}
|
9
|
+
case file_sexp[0]
|
10
|
+
when :class
|
11
|
+
process_class(file_sexp)
|
12
|
+
when :module
|
13
|
+
process_module(file_sexp)
|
14
|
+
when :block
|
15
|
+
file_sexp.each_of_type(:class) { |sexp| process_class(sexp) }
|
16
|
+
else
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def in_method? line_number
|
21
|
+
!!@locations.detect do |method_name, line_number_range|
|
22
|
+
line_number_range.include?(line_number)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_at_line line_number
|
27
|
+
found_method_and_range = @locations.detect do |method_name, line_number_range|
|
28
|
+
line_number_range.include?(line_number)
|
29
|
+
end
|
30
|
+
return nil unless found_method_and_range
|
31
|
+
found_method_and_range.first
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def process_module(sexp)
|
37
|
+
module_name = sexp[1]
|
38
|
+
sexp.each_of_type(:class) do |sexp|
|
39
|
+
process_class(sexp, module_name)
|
40
|
+
hide_methods_from_next_round(sexp)
|
41
|
+
end
|
42
|
+
process_class(sexp)
|
43
|
+
end
|
44
|
+
|
45
|
+
def process_class(sexp, module_name=nil)
|
46
|
+
class_name = sexp[1]
|
47
|
+
process_class_self_blocks(sexp, class_name)
|
48
|
+
module_name_string = module_name ? "#{module_name}::" : nil
|
49
|
+
sexp.each_of_type(:defn) { |s| @locations["#{module_name_string}#{class_name}##{s[1]}"] = (s.line)..(s.last.line) }
|
50
|
+
sexp.each_of_type(:defs) { |s| @locations["#{module_name_string}#{class_name}::#{s[2]}"] = (s.line)..(s.last.line) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def process_class_self_blocks(sexp, class_name)
|
54
|
+
sexp.each_of_type(:sclass) do |sexp_in_class_self_block|
|
55
|
+
sexp_in_class_self_block.each_of_type(:defn) { |s| @locations["#{class_name}::#{s[1]}"] = (s.line)..(s.last.line) }
|
56
|
+
hide_methods_from_next_round(sexp_in_class_self_block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def hide_methods_from_next_round(sexp)
|
61
|
+
sexp.find_and_replace_all(:defn, :ignore_me)
|
62
|
+
sexp.find_and_replace_all(:defs, :ignore_me)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class Location
|
2
|
+
include Comparable
|
3
|
+
|
4
|
+
attr_accessor :class_name, :method_name, :file_path, :simple_method_name, :hash
|
5
|
+
|
6
|
+
def self.get(file_path, class_name, method_name)
|
7
|
+
# This could be more 'confident' using Maybe, but we want it to be as fast as possible
|
8
|
+
file_path_copy = file_path == nil ? nil : file_path.clone
|
9
|
+
class_name_copy = class_name == nil ? nil : class_name.clone
|
10
|
+
method_name_copy = method_name == nil ? nil : method_name.clone
|
11
|
+
key = [file_path_copy, class_name_copy, method_name_copy]
|
12
|
+
@@locations ||= {}
|
13
|
+
if @@locations.has_key?(key)
|
14
|
+
@@locations[key]
|
15
|
+
else
|
16
|
+
location = self.new(file_path_copy, class_name_copy, method_name_copy)
|
17
|
+
@@locations[key] = location
|
18
|
+
location.freeze # we cache a lot of method call results, so we want location to be immutable
|
19
|
+
location
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(file_path, class_name, method_name)
|
24
|
+
@file_path = file_path
|
25
|
+
@class_name = class_name
|
26
|
+
@method_name = method_name
|
27
|
+
@simple_method_name = @method_name.sub(@class_name,'') unless @method_name == nil
|
28
|
+
@hash = [@file_path, @class_name, @method_name].hash
|
29
|
+
end
|
30
|
+
|
31
|
+
# TODO - we need this method (and hash accessor above) as a temporary hack where we're using Location as a hash key
|
32
|
+
def eql?(other)
|
33
|
+
[self.file_path.to_s, self.class_name.to_s, self.method_name.to_s] == [other.file_path.to_s, other.class_name.to_s, other.method_name.to_s]
|
34
|
+
end
|
35
|
+
|
36
|
+
# END we need these methods as a temporary hack where we're using Location as a hash key
|
37
|
+
|
38
|
+
def self.for(class_or_method_name)
|
39
|
+
class_or_method_name = strip_modules(class_or_method_name)
|
40
|
+
if(class_or_method_name)
|
41
|
+
begin
|
42
|
+
match = class_or_method_name.match(/(.*)((\.|\#|\:\:[a-z])(.+))/)
|
43
|
+
rescue => error
|
44
|
+
#new error during port to metric_fu occasionally a unintialized
|
45
|
+
#MatchData object shows up here. Not expected.
|
46
|
+
match = nil
|
47
|
+
end
|
48
|
+
|
49
|
+
# reek reports the method with :: not # on modules like
|
50
|
+
# module ApplicationHelper \n def signed_in?, convert it so it records correctly
|
51
|
+
# but classes have to start with a capital letter... HACK for REEK bug, reported underlying issue to REEK
|
52
|
+
if(match)
|
53
|
+
class_name = strip_modules(match[1])
|
54
|
+
method_name = class_or_method_name.gsub(/\:\:/,"#")
|
55
|
+
else
|
56
|
+
class_name = strip_modules(class_or_method_name)
|
57
|
+
method_name = nil
|
58
|
+
end
|
59
|
+
else
|
60
|
+
class_name = nil
|
61
|
+
method_name = nil
|
62
|
+
end
|
63
|
+
self.get(nil, class_name, method_name)
|
64
|
+
end
|
65
|
+
|
66
|
+
def <=>(other)
|
67
|
+
[self.file_path.to_s, self.class_name.to_s, self.method_name.to_s] <=> [other.file_path.to_s, other.class_name.to_s, other.method_name.to_s]
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def self.strip_modules(class_or_method_name)
|
73
|
+
# reek reports the method with :: not # on modules like
|
74
|
+
# module ApplicationHelper \n def signed_in?, convert it so it records correctly
|
75
|
+
# but classes have to start with a capital letter... HACK for REEK bug, reported underlying issue to REEK
|
76
|
+
if(class_or_method_name=~/\:\:[A-Z]/)
|
77
|
+
class_or_method_name.split("::").last
|
78
|
+
else
|
79
|
+
class_or_method_name
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|