kevinrutherford-reek 1.1.3.10 → 1.1.3.11
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.txt +5 -1
- data/bin/reek +2 -17
- data/features/masking_smells.feature +22 -8
- data/features/options.feature +12 -5
- data/features/reports.feature +22 -12
- data/features/samples.feature +66 -66
- data/lib/reek/adapters/application.rb +47 -0
- data/lib/reek/{config_file.rb → adapters/config_file.rb} +0 -0
- data/lib/reek/adapters/core_extras.rb +72 -0
- data/lib/reek/{object_source.rb → adapters/object_source.rb} +7 -6
- data/lib/reek/{rake_task.rb → adapters/rake_task.rb} +2 -2
- data/lib/reek/adapters/report.rb +91 -0
- data/lib/reek/adapters/source.rb +49 -0
- data/lib/reek/{spec.rb → adapters/spec.rb} +20 -9
- data/lib/reek/block_context.rb +1 -1
- data/lib/reek/class_context.rb +3 -2
- data/lib/reek/code_parser.rb +4 -0
- data/lib/reek/command_line.rb +85 -0
- data/lib/reek/detector_stack.rb +23 -6
- data/lib/reek/exceptions.reek +5 -1
- data/lib/reek/smell_warning.rb +5 -1
- data/lib/reek/smells/duplication.rb +5 -3
- data/lib/reek/smells/smell_detector.rb +15 -1
- data/lib/reek/smells/uncommunicative_name.rb +1 -1
- data/lib/reek/sniffer.rb +34 -66
- data/lib/reek.rb +1 -1
- data/reek.gemspec +3 -3
- data/spec/quality/reek_source_spec.rb +15 -0
- data/spec/reek/adapters/report_spec.rb +48 -0
- data/spec/reek/{should_reek_of_spec.rb → adapters/should_reek_of_spec.rb} +14 -11
- data/spec/reek/{should_reek_only_of_spec.rb → adapters/should_reek_only_of_spec.rb} +6 -4
- data/spec/reek/{should_reek_spec.rb → adapters/should_reek_spec.rb} +13 -10
- data/spec/reek/block_context_spec.rb +6 -0
- data/spec/reek/code_parser_spec.rb +6 -1
- data/spec/reek/config_spec.rb +3 -3
- data/spec/reek/smell_warning_spec.rb +2 -1
- data/spec/reek/smells/duplication_spec.rb +1 -1
- data/spec/reek/smells/large_class_spec.rb +3 -2
- data/spec/reek/smells/long_method_spec.rb +4 -3
- data/spec/reek/smells/long_parameter_list_spec.rb +0 -2
- data/spec/reek/smells/smell_detector_spec.rb +2 -16
- data/spec/reek/smells/uncommunicative_name_spec.rb +1 -2
- data/spec/reek/smells/utility_function_spec.rb +4 -0
- data/spec/samples/not_quite_masked/dirty.rb +8 -0
- data/spec/samples/not_quite_masked/masked.reek +5 -0
- data/spec/spec_helper.rb +1 -1
- data/tasks/reek.rake +2 -2
- data/tasks/test.rake +8 -8
- metadata +18 -20
- data/features/rake_task.feature +0 -9
- data/lib/reek/core_extras.rb +0 -50
- data/lib/reek/options.rb +0 -103
- data/lib/reek/report.rb +0 -115
- data/lib/reek/source.rb +0 -36
- data/spec/reek/options_spec.rb +0 -13
- data/spec/reek/report_spec.rb +0 -49
- data/spec/slow/inline_spec.rb +0 -44
- data/spec/slow/optparse_spec.rb +0 -112
- data/spec/slow/redcloth_spec.rb +0 -105
- data/spec/slow/reek_source_spec.rb +0 -13
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'reek/command_line' # SMELL: Global Variable
|
3
|
+
|
4
|
+
module Reek
|
5
|
+
class ReportSection
|
6
|
+
|
7
|
+
def initialize(sniffer) # :nodoc:
|
8
|
+
@masked_warnings = SortedSet.new
|
9
|
+
@warnings = SortedSet.new
|
10
|
+
@desc = sniffer.desc
|
11
|
+
sniffer.report_on(self)
|
12
|
+
end
|
13
|
+
|
14
|
+
def <<(smell) # :nodoc:
|
15
|
+
@warnings << smell
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def record_masked_smell(smell)
|
20
|
+
@masked_warnings << smell
|
21
|
+
end
|
22
|
+
|
23
|
+
def num_masked_smells # SMELL: getter
|
24
|
+
@masked_warnings.length
|
25
|
+
end
|
26
|
+
|
27
|
+
# Creates a formatted report of all the +Smells::SmellWarning+ objects recorded in
|
28
|
+
# this report, with a heading.
|
29
|
+
def full_report
|
30
|
+
return quiet_report if Options[:quiet]
|
31
|
+
result = header
|
32
|
+
result += ":\n#{smell_list}" if should_report
|
33
|
+
result += "\n"
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
def quiet_report
|
38
|
+
return '' unless should_report
|
39
|
+
"#{header}:\n#{smell_list}\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
def header
|
43
|
+
@all_warnings = SortedSet.new(@warnings) # SMELL: Temporary Field
|
44
|
+
@all_warnings.merge(@masked_warnings)
|
45
|
+
"#{@desc} -- #{visible_header}#{masked_header}"
|
46
|
+
end
|
47
|
+
|
48
|
+
# Creates a formatted report of all the +Smells::SmellWarning+ objects recorded in
|
49
|
+
# this report.
|
50
|
+
def smell_list
|
51
|
+
smells = Options[:show_all] ? @all_warnings : @warnings
|
52
|
+
smells.map {|smell| " #{smell.report}"}.join("\n")
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def should_report
|
58
|
+
@warnings.length > 0 or (Options[:show_all] and @masked_warnings.length > 0)
|
59
|
+
end
|
60
|
+
|
61
|
+
def visible_header
|
62
|
+
num_smells = @warnings.length
|
63
|
+
result = "#{num_smells} warning"
|
64
|
+
result += 's' unless num_smells == 1
|
65
|
+
result
|
66
|
+
end
|
67
|
+
|
68
|
+
def masked_header
|
69
|
+
num_masked_warnings = @all_warnings.length - @warnings.length
|
70
|
+
num_masked_warnings == 0 ? '' : " (+#{num_masked_warnings} masked)"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Report
|
75
|
+
|
76
|
+
def initialize(sniffers)
|
77
|
+
@partials = Array(sniffers).map {|sn| ReportSection.new(sn)}
|
78
|
+
end
|
79
|
+
|
80
|
+
# SMELL: Shotgun Surgery
|
81
|
+
# This method and the next will have to be repeated for every new
|
82
|
+
# kind of report.
|
83
|
+
def full_report
|
84
|
+
@partials.map { |rpt| rpt.full_report }.join
|
85
|
+
end
|
86
|
+
|
87
|
+
def quiet_report
|
88
|
+
@partials.map { |rpt| rpt.quiet_report }.join
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'reek/adapters/config_file'
|
2
|
+
|
3
|
+
module Reek
|
4
|
+
|
5
|
+
#
|
6
|
+
# A +Source+ object represents a chunk of Ruby source code.
|
7
|
+
#
|
8
|
+
class Source
|
9
|
+
|
10
|
+
attr_reader :desc
|
11
|
+
|
12
|
+
def initialize(code, desc)
|
13
|
+
@source = code
|
14
|
+
@desc = desc
|
15
|
+
end
|
16
|
+
|
17
|
+
def configure(sniffer) end
|
18
|
+
|
19
|
+
def syntax_tree
|
20
|
+
RubyParser.new.parse(@source, @desc) || s()
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Represents a file of Ruby source, whose contents will be examined
|
26
|
+
# for code smells.
|
27
|
+
#
|
28
|
+
class SourceFile < Source
|
29
|
+
|
30
|
+
def initialize(file)
|
31
|
+
@file = file
|
32
|
+
super(@file.lines.to_a.join, @file.path)
|
33
|
+
end
|
34
|
+
|
35
|
+
def configure(sniffer)
|
36
|
+
path = File.expand_path(File.dirname(@file.path))
|
37
|
+
all_config_files(path).each { |cf| ConfigFile.new(cf).configure(sniffer) }
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def all_config_files(path)
|
43
|
+
return [] unless File.exist?(path)
|
44
|
+
parent = File.dirname(path)
|
45
|
+
return [] if path == parent
|
46
|
+
all_config_files(parent) + Dir["#{path}/*.reek"]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,4 +1,7 @@
|
|
1
1
|
require 'reek/sniffer'
|
2
|
+
require 'reek/adapters/core_extras'
|
3
|
+
require 'reek/adapters/object_source'
|
4
|
+
require 'reek/adapters/report'
|
2
5
|
|
3
6
|
module Reek
|
4
7
|
|
@@ -40,20 +43,30 @@ module Reek
|
|
40
43
|
# ruby.should_not reek_of(:FeatureEnvy)
|
41
44
|
#
|
42
45
|
module Spec
|
46
|
+
module ReekMatcher
|
47
|
+
def report
|
48
|
+
Report.new(@sniffer.sniffers).quiet_report
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
43
52
|
class ShouldReek # :nodoc:
|
53
|
+
include ReekMatcher
|
54
|
+
|
44
55
|
def matches?(actual)
|
45
56
|
@sniffer = actual.sniff
|
46
57
|
@sniffer.smelly?
|
47
58
|
end
|
48
59
|
def failure_message_for_should
|
49
|
-
"Expected
|
60
|
+
"Expected #{@sniffer.desc} to reek, but it didn't"
|
50
61
|
end
|
51
62
|
def failure_message_for_should_not
|
52
|
-
"Expected no smells, but got:\n#{
|
63
|
+
"Expected no smells, but got:\n#{report}"
|
53
64
|
end
|
54
65
|
end
|
55
66
|
|
56
67
|
class ShouldReekOf # :nodoc:
|
68
|
+
include ReekMatcher
|
69
|
+
|
57
70
|
def initialize(klass, patterns)
|
58
71
|
@klass = klass
|
59
72
|
@patterns = patterns
|
@@ -66,21 +79,19 @@ module Reek
|
|
66
79
|
"Expected #{@sniffer.desc} to reek of #{@klass}, but it didn't"
|
67
80
|
end
|
68
81
|
def failure_message_for_should_not
|
69
|
-
"Expected #{@sniffer.desc} not to reek of #{@klass}, but got:\n#{
|
82
|
+
"Expected #{@sniffer.desc} not to reek of #{@klass}, but got:\n#{report}"
|
70
83
|
end
|
71
84
|
end
|
72
85
|
|
73
|
-
class ShouldReekOnlyOf # :nodoc:
|
74
|
-
|
75
|
-
|
76
|
-
@patterns = patterns
|
77
|
-
end
|
86
|
+
class ShouldReekOnlyOf < ShouldReekOf # :nodoc:
|
87
|
+
include ReekMatcher
|
88
|
+
|
78
89
|
def matches?(actual)
|
79
90
|
@sniffer = actual.sniff
|
80
91
|
@sniffer.smells_only_of?(@klass, @patterns)
|
81
92
|
end
|
82
93
|
def failure_message_for_should
|
83
|
-
"Expected #{@sniffer.desc} to reek only of #{@klass}, but got:\n#{
|
94
|
+
"Expected #{@sniffer.desc} to reek only of #{@klass}, but got:\n#{report}"
|
84
95
|
end
|
85
96
|
def failure_message_for_should_not
|
86
97
|
"Expected #{@sniffer.desc} not to reek only of #{@klass}, but it did"
|
data/lib/reek/block_context.rb
CHANGED
data/lib/reek/class_context.rb
CHANGED
@@ -16,8 +16,9 @@ module Reek
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def ClassContext.from_s(src)
|
19
|
-
|
20
|
-
|
19
|
+
source = src.to_reek_source
|
20
|
+
sniffer = Sniffer.new(source)
|
21
|
+
CodeParser.new(sniffer).process_class(source.syntax_tree)
|
21
22
|
end
|
22
23
|
|
23
24
|
def initialize(outer, name, superclass = nil)
|
data/lib/reek/code_parser.rb
CHANGED
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'reek'
|
3
|
+
|
4
|
+
module Reek
|
5
|
+
|
6
|
+
# SMELL: Greedy Module
|
7
|
+
# This creates the command-line parser AND invokes it. And for the
|
8
|
+
# -v and -h options it also executes them. And it holds the config
|
9
|
+
# options for the rest of the application.
|
10
|
+
class Options
|
11
|
+
|
12
|
+
CTX_SORT = '%m%c %w (%s)'
|
13
|
+
SMELL_SORT = '%m[%s] %c %w'
|
14
|
+
|
15
|
+
def self.default_options
|
16
|
+
{
|
17
|
+
:format => CTX_SORT,
|
18
|
+
:show_all => false,
|
19
|
+
:quiet => false
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
# SMELL: Global Variable
|
24
|
+
@@opts = default_options
|
25
|
+
|
26
|
+
def self.[](key)
|
27
|
+
@@opts[key]
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(argv)
|
31
|
+
@argv = argv
|
32
|
+
@parser = OptionParser.new
|
33
|
+
set_options
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse
|
37
|
+
@parser.parse!(@argv)
|
38
|
+
@argv
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_options
|
42
|
+
@parser.banner = <<EOB
|
43
|
+
Usage: #{@parser.program_name} [options] [files]
|
44
|
+
|
45
|
+
Examples:
|
46
|
+
|
47
|
+
#{@parser.program_name} lib/*.rb
|
48
|
+
#{@parser.program_name} -q -a lib
|
49
|
+
cat my_class.rb | #{@parser.program_name}
|
50
|
+
|
51
|
+
See http://wiki.github.com/kevinrutherford/reek for detailed help.
|
52
|
+
|
53
|
+
EOB
|
54
|
+
|
55
|
+
@parser.separator "Common options:"
|
56
|
+
|
57
|
+
@parser.on("-h", "--help", "Show this message") do
|
58
|
+
puts @parser
|
59
|
+
exit(0)
|
60
|
+
end
|
61
|
+
@parser.on("-v", "--version", "Show version") do
|
62
|
+
puts "#{@parser.program_name} #{Reek::VERSION}"
|
63
|
+
exit(0)
|
64
|
+
end
|
65
|
+
|
66
|
+
@parser.separator "\nReport formatting:"
|
67
|
+
|
68
|
+
@parser.on("-a", "--[no-]show-all", "Show all smells, including those masked by config settings") do |opt|
|
69
|
+
@@opts[:show_all] = opt
|
70
|
+
end
|
71
|
+
@parser.on("-q", "--quiet", "Suppress headings for smell-free source files") do
|
72
|
+
@@opts[:quiet] = true
|
73
|
+
end
|
74
|
+
@parser.on('-f', "--format FORMAT", 'Specify the format of smell warnings') do |arg|
|
75
|
+
@@opts[:format] = arg unless arg.nil?
|
76
|
+
end
|
77
|
+
@parser.on('-c', '--context-first', "Sort by context; sets the format string to \"#{CTX_SORT}\"") do
|
78
|
+
@@opts[:format] = CTX_SORT
|
79
|
+
end
|
80
|
+
@parser.on('-s', '--smell-first', "Sort by smell; sets the format string to \"#{SMELL_SORT}\"") do
|
81
|
+
@@opts[:format] = SMELL_SORT
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/reek/detector_stack.rb
CHANGED
@@ -7,18 +7,35 @@ module Reek
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def push(config)
|
10
|
-
|
11
|
-
|
12
|
-
@detectors.each {|
|
13
|
-
@detectors <<
|
10
|
+
clone = @detectors[0].copy
|
11
|
+
clone.configure_with(config)
|
12
|
+
@detectors.each {|det| det.be_masked}
|
13
|
+
@detectors << clone
|
14
14
|
end
|
15
15
|
|
16
16
|
def listen_to(hooks)
|
17
|
-
@detectors.each { |
|
17
|
+
@detectors.each { |det| det.listen_to(hooks) }
|
18
18
|
end
|
19
19
|
|
20
20
|
def report_on(report)
|
21
|
-
@detectors.each { |
|
21
|
+
@detectors.each { |det| det.report_on(report) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def num_smells
|
25
|
+
total = 0
|
26
|
+
@detectors.each { |det| total += det.num_smells }
|
27
|
+
total
|
28
|
+
end
|
29
|
+
|
30
|
+
def has_smell?(patterns)
|
31
|
+
@detectors.each { |det| return true if det.has_smell?(patterns) }
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def smelly?
|
36
|
+
# SMELL: Duplication: look at al those loops!
|
37
|
+
@detectors.each { |det| return true if det.smelly? }
|
38
|
+
false
|
22
39
|
end
|
23
40
|
end
|
24
41
|
end
|
data/lib/reek/exceptions.reek
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
---
|
1
|
+
---
|
2
|
+
Duplication:
|
3
|
+
exclude:
|
4
|
+
- Reek::Options#set_options
|
2
5
|
FeatureEnvy:
|
3
6
|
exclude:
|
4
7
|
- examine_context
|
@@ -8,6 +11,7 @@ LargeClass:
|
|
8
11
|
LongMethod:
|
9
12
|
exclude:
|
10
13
|
- Reek::SexpFormatter#self.format
|
14
|
+
- Reek::Options#set_options
|
11
15
|
UtilityFunction:
|
12
16
|
exclude:
|
13
17
|
- Reek::Spec
|
data/lib/reek/smell_warning.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'reek/options
|
1
|
+
require 'reek/command_line' # SMELL: Global Variable used for options
|
2
2
|
|
3
3
|
module Reek
|
4
4
|
|
@@ -31,6 +31,10 @@ module Reek
|
|
31
31
|
#
|
32
32
|
def matches?(smell_class, patterns)
|
33
33
|
return false unless smell_class.to_s == @detector.class.class_name
|
34
|
+
contains_all?(patterns)
|
35
|
+
end
|
36
|
+
|
37
|
+
def contains_all?(patterns)
|
34
38
|
rpt = report
|
35
39
|
return patterns.all? {|exp| exp === rpt}
|
36
40
|
end
|
@@ -33,15 +33,17 @@ module Reek
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def examine_context(method)
|
36
|
-
smelly_calls(method).each do |
|
37
|
-
|
36
|
+
smelly_calls(method).each do |call_data|
|
37
|
+
num = call_data[1]
|
38
|
+
multiple = num == 2 ? 'twice' : "#{num} times"
|
39
|
+
found(method, "calls #{SexpFormatter.format(call_data[0])} #{multiple}")
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
43
|
def smelly_calls(method) # :nodoc:
|
42
44
|
method.calls.select do |key,val|
|
43
45
|
val > @config[MAX_ALLOWED_CALLS_KEY] and key[2] != :new
|
44
|
-
end
|
46
|
+
end
|
45
47
|
end
|
46
48
|
end
|
47
49
|
end
|
@@ -46,7 +46,7 @@ module Reek
|
|
46
46
|
|
47
47
|
def initialize(config = SmellDetector.default_config)
|
48
48
|
@config = config
|
49
|
-
@smells_found =
|
49
|
+
@smells_found = Set.new
|
50
50
|
@masked = false
|
51
51
|
end
|
52
52
|
|
@@ -99,6 +99,12 @@ module Reek
|
|
99
99
|
smell
|
100
100
|
end
|
101
101
|
|
102
|
+
def has_smell?(patterns)
|
103
|
+
return false if @masked
|
104
|
+
@smells_found.each { |warning| return true if warning.contains_all?(patterns) }
|
105
|
+
false
|
106
|
+
end
|
107
|
+
|
102
108
|
def report_on(report)
|
103
109
|
@smells_found.each do |smell|
|
104
110
|
if @masked
|
@@ -109,6 +115,14 @@ module Reek
|
|
109
115
|
end
|
110
116
|
end
|
111
117
|
|
118
|
+
def num_smells
|
119
|
+
@masked ? 0 : @smells_found.length
|
120
|
+
end
|
121
|
+
|
122
|
+
def smelly?
|
123
|
+
(not @masked) and (@smells_found.length > 0)
|
124
|
+
end
|
125
|
+
|
112
126
|
def smell_name
|
113
127
|
self.class.name_words.join(' ')
|
114
128
|
end
|
@@ -20,7 +20,7 @@ module Reek
|
|
20
20
|
class UncommunicativeName < SmellDetector
|
21
21
|
|
22
22
|
# The name of the config field that lists the regexps of
|
23
|
-
# smelly names to be
|
23
|
+
# smelly names to be reported.
|
24
24
|
REJECT_KEY = 'reject'
|
25
25
|
|
26
26
|
# The name of the config field that lists the specific names that are
|
data/lib/reek/sniffer.rb
CHANGED
@@ -9,9 +9,7 @@ require 'reek/smells/long_yield_list'
|
|
9
9
|
require 'reek/smells/nested_iterators'
|
10
10
|
require 'reek/smells/uncommunicative_name'
|
11
11
|
require 'reek/smells/utility_function'
|
12
|
-
require 'reek/config_file'
|
13
12
|
require 'reek/code_parser'
|
14
|
-
require 'reek/report'
|
15
13
|
require 'yaml'
|
16
14
|
|
17
15
|
class Hash
|
@@ -58,36 +56,27 @@ module Reek
|
|
58
56
|
Smells::UtilityFunction,
|
59
57
|
]
|
60
58
|
|
61
|
-
|
62
|
-
|
63
|
-
def initialize
|
59
|
+
def initialize(src)
|
60
|
+
@already_checked_for_smells = false
|
64
61
|
@typed_detectors = nil
|
65
62
|
@detectors = Hash.new
|
66
63
|
SMELL_CLASSES.each { |klass| @detectors[klass] = DetectorStack.new(klass.new) }
|
64
|
+
@source = src
|
65
|
+
src.configure(self)
|
67
66
|
end
|
68
67
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
# those further up the path.
|
74
|
-
#
|
75
|
-
def configure_along_path(filename)
|
76
|
-
path = File.expand_path(File.dirname(filename))
|
77
|
-
all_reekfiles(path).each { |config_file| ConfigFile.new(config_file).configure(self) }
|
78
|
-
self
|
68
|
+
def check_for_smells
|
69
|
+
return if @already_checked_for_smells
|
70
|
+
CodeParser.new(self).process(@source.syntax_tree)
|
71
|
+
@already_checked_for_smells = true
|
79
72
|
end
|
80
73
|
|
81
74
|
def configure(klass, config)
|
82
75
|
@detectors[klass].push(config)
|
83
76
|
end
|
84
77
|
|
85
|
-
def disable(klass)
|
86
|
-
disabled_config = {Reek::Smells::SmellDetector::ENABLED_KEY => false}
|
87
|
-
@detectors[klass].push(disabled_config)
|
88
|
-
end
|
89
|
-
|
90
78
|
def report_on(report)
|
79
|
+
check_for_smells
|
91
80
|
@detectors.each_value { |stack| stack.report_on(report) }
|
92
81
|
end
|
93
82
|
|
@@ -96,36 +85,17 @@ module Reek
|
|
96
85
|
listeners.each {|smell| smell.examine(scope) } if listeners
|
97
86
|
end
|
98
87
|
|
99
|
-
#
|
100
|
-
# Returns a +Report+ listing the smells found in this source. The first
|
101
|
-
# call to +report+ parses the source code and constructs a list of
|
102
|
-
# +SmellWarning+s found; subsequent calls simply return this same list.
|
103
|
-
#
|
104
|
-
def report
|
105
|
-
unless @report
|
106
|
-
CodeParser.new(self).process(@source.syntax_tree)
|
107
|
-
@report = Report.new(self)
|
108
|
-
end
|
109
|
-
@report
|
110
|
-
end
|
111
|
-
|
112
88
|
def smelly?
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
def quiet_report
|
117
|
-
report.quiet_report
|
118
|
-
end
|
119
|
-
|
120
|
-
# SMELL: Shotgun Surgery
|
121
|
-
# This and the above method will need to be replicated for every new
|
122
|
-
# kind of report.
|
123
|
-
def full_report
|
124
|
-
report.full_report
|
89
|
+
check_for_smells
|
90
|
+
@detectors.each_value { |stack| return true if stack.smelly? }
|
91
|
+
false
|
125
92
|
end
|
126
93
|
|
127
94
|
def num_smells
|
128
|
-
|
95
|
+
check_for_smells
|
96
|
+
total = 0
|
97
|
+
@detectors.each_value { |stack| total += stack.num_smells }
|
98
|
+
total
|
129
99
|
end
|
130
100
|
|
131
101
|
def desc
|
@@ -139,17 +109,23 @@ module Reek
|
|
139
109
|
# only if one of them has a report string matching all of the +patterns+.
|
140
110
|
#
|
141
111
|
def has_smell?(smell_class, patterns=[])
|
142
|
-
|
112
|
+
check_for_smells
|
113
|
+
stack = @detectors[Reek::Smells.const_get(smell_class)] # SMELL: Duplication of code in ConfigFile
|
114
|
+
stack.has_smell?(patterns)
|
143
115
|
end
|
144
116
|
|
145
117
|
def smells_only_of?(klass, patterns)
|
146
|
-
|
118
|
+
num_smells == 1 and has_smell?(klass, patterns)
|
147
119
|
end
|
148
120
|
|
149
121
|
def sniff
|
150
122
|
self
|
151
123
|
end
|
152
124
|
|
125
|
+
def sniffers
|
126
|
+
[self]
|
127
|
+
end
|
128
|
+
|
153
129
|
private
|
154
130
|
|
155
131
|
def smell_listeners()
|
@@ -159,18 +135,11 @@ private
|
|
159
135
|
end
|
160
136
|
@typed_detectors
|
161
137
|
end
|
162
|
-
|
163
|
-
def all_reekfiles(path)
|
164
|
-
return [] unless File.exist?(path)
|
165
|
-
parent = File.dirname(path)
|
166
|
-
return [] if path == parent
|
167
|
-
all_reekfiles(parent) + Dir["#{path}/*.reek"]
|
168
|
-
end
|
169
138
|
end
|
170
139
|
|
171
140
|
class SnifferSet
|
172
141
|
|
173
|
-
attr_reader :
|
142
|
+
attr_reader :desc, :sniffers
|
174
143
|
|
175
144
|
def initialize(sniffers, desc)
|
176
145
|
@sniffers = sniffers
|
@@ -189,20 +158,19 @@ private
|
|
189
158
|
@sniffers.any? {|sniffer| sniffer.has_smell?(smell_class, patterns)}
|
190
159
|
end
|
191
160
|
|
192
|
-
def
|
193
|
-
|
161
|
+
def num_smells
|
162
|
+
total = 0
|
163
|
+
@sniffers.each {|sniffer| total += sniffer.num_smells}
|
164
|
+
total
|
194
165
|
end
|
195
166
|
|
196
|
-
def
|
197
|
-
|
167
|
+
def smells_only_of?(klass, patterns)
|
168
|
+
num_smells == 1 and has_smell?(klass, patterns)
|
198
169
|
end
|
199
170
|
|
200
|
-
|
201
|
-
|
202
|
-
# This and the above method will need to be replicated for every new
|
203
|
-
# kind of report.
|
204
|
-
def full_report
|
205
|
-
ReportList.new(@sniffers).full_report
|
171
|
+
def sniff
|
172
|
+
self
|
206
173
|
end
|
174
|
+
|
207
175
|
end
|
208
176
|
end
|
data/lib/reek.rb
CHANGED