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.
Files changed (60) hide show
  1. data/History.txt +5 -1
  2. data/bin/reek +2 -17
  3. data/features/masking_smells.feature +22 -8
  4. data/features/options.feature +12 -5
  5. data/features/reports.feature +22 -12
  6. data/features/samples.feature +66 -66
  7. data/lib/reek/adapters/application.rb +47 -0
  8. data/lib/reek/{config_file.rb → adapters/config_file.rb} +0 -0
  9. data/lib/reek/adapters/core_extras.rb +72 -0
  10. data/lib/reek/{object_source.rb → adapters/object_source.rb} +7 -6
  11. data/lib/reek/{rake_task.rb → adapters/rake_task.rb} +2 -2
  12. data/lib/reek/adapters/report.rb +91 -0
  13. data/lib/reek/adapters/source.rb +49 -0
  14. data/lib/reek/{spec.rb → adapters/spec.rb} +20 -9
  15. data/lib/reek/block_context.rb +1 -1
  16. data/lib/reek/class_context.rb +3 -2
  17. data/lib/reek/code_parser.rb +4 -0
  18. data/lib/reek/command_line.rb +85 -0
  19. data/lib/reek/detector_stack.rb +23 -6
  20. data/lib/reek/exceptions.reek +5 -1
  21. data/lib/reek/smell_warning.rb +5 -1
  22. data/lib/reek/smells/duplication.rb +5 -3
  23. data/lib/reek/smells/smell_detector.rb +15 -1
  24. data/lib/reek/smells/uncommunicative_name.rb +1 -1
  25. data/lib/reek/sniffer.rb +34 -66
  26. data/lib/reek.rb +1 -1
  27. data/reek.gemspec +3 -3
  28. data/spec/quality/reek_source_spec.rb +15 -0
  29. data/spec/reek/adapters/report_spec.rb +48 -0
  30. data/spec/reek/{should_reek_of_spec.rb → adapters/should_reek_of_spec.rb} +14 -11
  31. data/spec/reek/{should_reek_only_of_spec.rb → adapters/should_reek_only_of_spec.rb} +6 -4
  32. data/spec/reek/{should_reek_spec.rb → adapters/should_reek_spec.rb} +13 -10
  33. data/spec/reek/block_context_spec.rb +6 -0
  34. data/spec/reek/code_parser_spec.rb +6 -1
  35. data/spec/reek/config_spec.rb +3 -3
  36. data/spec/reek/smell_warning_spec.rb +2 -1
  37. data/spec/reek/smells/duplication_spec.rb +1 -1
  38. data/spec/reek/smells/large_class_spec.rb +3 -2
  39. data/spec/reek/smells/long_method_spec.rb +4 -3
  40. data/spec/reek/smells/long_parameter_list_spec.rb +0 -2
  41. data/spec/reek/smells/smell_detector_spec.rb +2 -16
  42. data/spec/reek/smells/uncommunicative_name_spec.rb +1 -2
  43. data/spec/reek/smells/utility_function_spec.rb +4 -0
  44. data/spec/samples/not_quite_masked/dirty.rb +8 -0
  45. data/spec/samples/not_quite_masked/masked.reek +5 -0
  46. data/spec/spec_helper.rb +1 -1
  47. data/tasks/reek.rake +2 -2
  48. data/tasks/test.rake +8 -8
  49. metadata +18 -20
  50. data/features/rake_task.feature +0 -9
  51. data/lib/reek/core_extras.rb +0 -50
  52. data/lib/reek/options.rb +0 -103
  53. data/lib/reek/report.rb +0 -115
  54. data/lib/reek/source.rb +0 -36
  55. data/spec/reek/options_spec.rb +0 -13
  56. data/spec/reek/report_spec.rb +0 -49
  57. data/spec/slow/inline_spec.rb +0 -44
  58. data/spec/slow/optparse_spec.rb +0 -112
  59. data/spec/slow/redcloth_spec.rb +0 -105
  60. 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 source to reek, but it didn't"
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#{@sniffer.quiet_report}"
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#{@sniffer.quiet_report}"
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
- def initialize(klass, patterns)
75
- @klass = klass
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#{@sniffer.quiet_report}"
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"
@@ -11,7 +11,7 @@ module Reek
11
11
  case slice(0)
12
12
  when :masgn
13
13
  @names = arg[1..-1].map {|lasgn| Name.new(lasgn[1]) }
14
- when :lasgn
14
+ when :lasgn, :iasgn
15
15
  @names = [Name.new(arg)]
16
16
  end
17
17
  end
@@ -16,8 +16,9 @@ module Reek
16
16
  end
17
17
 
18
18
  def ClassContext.from_s(src)
19
- sniffer = src.sniff
20
- CodeParser.new(sniffer).process_class(sniffer.source.syntax_tree)
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)
@@ -82,6 +82,10 @@ module Reek
82
82
  @element.record_depends_on_self if /^@/ === exp[1].to_s
83
83
  end
84
84
 
85
+ def process_zsuper(exp)
86
+ @element.record_use_of_self
87
+ end
88
+
85
89
  def process_lit(exp)
86
90
  val = exp[1]
87
91
  @element.record_depends_on_self if val == :self
@@ -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
@@ -7,18 +7,35 @@ module Reek
7
7
  end
8
8
 
9
9
  def push(config)
10
- det = @detectors[0].copy
11
- det.configure_with(config)
12
- @detectors.each {|smell| smell.be_masked}
13
- @detectors << det
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 { |smell| smell.listen_to(hooks) }
17
+ @detectors.each { |det| det.listen_to(hooks) }
18
18
  end
19
19
 
20
20
  def report_on(report)
21
- @detectors.each { |smell| smell.report_on(report) }
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
@@ -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
@@ -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 |call|
37
- found(method, "calls #{SexpFormatter.format(call)} multiple times")
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.map { |call_exp| call_exp[0] }
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 rejected.
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
- attr_accessor :source
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
- # Configures this sniffer using any *.reek config files found
71
- # on the path to the named file. Config files are applied in order,
72
- # "root-first", so that config files closer to the named file override
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
- report.length > 0
114
- end
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
- report.length
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
- report.has_smell?(smell_class, patterns)
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
- report.length == 1 and has_smell?(klass, patterns)
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 :sniffers, :desc
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 smells_only_of?(klass, patterns)
193
- ReportList.new(@sniffers).length == 1 and has_smell?(klass, patterns)
161
+ def num_smells
162
+ total = 0
163
+ @sniffers.each {|sniffer| total += sniffer.num_smells}
164
+ total
194
165
  end
195
166
 
196
- def quiet_report
197
- ReportList.new(@sniffers).quiet_report
167
+ def smells_only_of?(klass, patterns)
168
+ num_smells == 1 and has_smell?(klass, patterns)
198
169
  end
199
170
 
200
-
201
- # SMELL: Shotgun Surgery
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
@@ -1,5 +1,5 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
3
  module Reek # :doc:
4
- VERSION = '1.1.3.10'
4
+ VERSION = '1.1.3.11'
5
5
  end