kevinrutherford-reek 1.1.3.13 → 1.1.3.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/History.txt +8 -2
  2. data/config/defaults.reek +13 -2
  3. data/features/masking_smells.feature +29 -1
  4. data/features/samples.feature +17 -4
  5. data/lib/reek/adapters/object_source.rb +2 -1
  6. data/lib/reek/class_context.rb +7 -0
  7. data/lib/reek/code_parser.rb +3 -1
  8. data/lib/reek/configuration.rb +51 -0
  9. data/lib/reek/detector_stack.rb +1 -3
  10. data/lib/reek/exceptions.reek +3 -0
  11. data/lib/reek/smell_warning.rb +10 -2
  12. data/lib/reek/smells/duplication.rb +4 -2
  13. data/lib/reek/smells/large_class.rb +8 -4
  14. data/lib/reek/smells/long_method.rb +4 -6
  15. data/lib/reek/smells/long_parameter_list.rb +11 -3
  16. data/lib/reek/smells/simulated_polymorphism.rb +58 -0
  17. data/lib/reek/smells/smell_detector.rb +53 -51
  18. data/lib/reek/smells/uncommunicative_name.rb +13 -9
  19. data/lib/reek/sniffer.rb +4 -0
  20. data/lib/reek.rb +1 -1
  21. data/reek.gemspec +3 -3
  22. data/spec/reek/adapters/report_spec.rb +5 -4
  23. data/spec/reek/class_context_spec.rb +21 -0
  24. data/spec/reek/configuration_spec.rb +12 -0
  25. data/spec/reek/smell_warning_spec.rb +30 -2
  26. data/spec/reek/smells/duplication_spec.rb +2 -1
  27. data/spec/reek/smells/feature_envy_spec.rb +15 -0
  28. data/spec/reek/smells/large_class_spec.rb +21 -20
  29. data/spec/reek/smells/simulated_polymorphism_spec.rb +50 -0
  30. data/spec/reek/smells/smell_detector_spec.rb +5 -5
  31. data/spec/reek/smells/uncommunicative_name_spec.rb +14 -0
  32. data/spec/samples/exceptions.reek +4 -0
  33. data/spec/samples/overrides/masked/dirty.rb +7 -0
  34. data/spec/samples/overrides/masked/lower.reek +5 -0
  35. data/spec/samples/overrides/upper.reek +5 -0
  36. data/tasks/test.rake +6 -1
  37. metadata +12 -3
@@ -1,3 +1,5 @@
1
+ require 'reek/configuration'
2
+
1
3
  class Class
2
4
  def name_words
3
5
  class_name = name.split(/::/)[-1]
@@ -15,37 +17,39 @@ module Reek
15
17
  # smell that should ignore this code element.
16
18
  EXCLUDE_KEY = 'exclude'
17
19
 
18
- # The name fo the config field that specifies whether a smell is
19
- # enabled. Set to +true+ or +false+.
20
- ENABLED_KEY = 'enabled'
21
-
22
- def self.class_name
23
- self.name.split(/::/)[-1]
24
- end
20
+ # The default value for the +EXCLUDE_KEY+ if it isn't specified
21
+ # in any configuration file.
22
+ DEFAULT_EXCLUDE_SET = []
25
23
 
26
- def self.contexts # :nodoc:
27
- [:defn, :defs]
28
- end
29
-
30
- def self.default_config
31
- {
32
- ENABLED_KEY => true,
33
- EXCLUDE_KEY => []
34
- }
35
- end
24
+ class << self
25
+ def class_name
26
+ self.name.split(/::/)[-1]
27
+ end
36
28
 
37
- def self.create(config)
38
- new(config[class_name])
39
- end
29
+ def contexts # :nodoc:
30
+ [:defn, :defs]
31
+ end
32
+
33
+ def default_config
34
+ {
35
+ SmellConfiguration::ENABLED_KEY => true,
36
+ EXCLUDE_KEY => DEFAULT_EXCLUDE_SET
37
+ }
38
+ end
40
39
 
41
- def self.listen(hooks, config)
42
- detector = create(config)
43
- detector.listen_to(hooks)
44
- detector
40
+ def create(config)
41
+ new(config[class_name])
42
+ end
43
+
44
+ def listen(hooks, config)
45
+ detector = create(config)
46
+ detector.listen_to(hooks)
47
+ detector
48
+ end
45
49
  end
46
50
 
47
51
  def initialize(config = SmellDetector.default_config)
48
- @config = config
52
+ @config = SmellConfiguration.new(config)
49
53
  @smells_found = Set.new
50
54
  @masked = false
51
55
  end
@@ -54,16 +58,9 @@ module Reek
54
58
  self.class.contexts.each { |ctx| hooks[ctx] << self }
55
59
  end
56
60
 
57
- def be_masked
58
- @masked = true
59
- end
60
-
61
- def masked?
62
- @masked
63
- end
64
-
61
+ # SMELL: Getter (only used in 1 test)
65
62
  def enabled?
66
- @config[ENABLED_KEY]
63
+ @config.enabled?
67
64
  end
68
65
 
69
66
  def configure(config)
@@ -73,16 +70,23 @@ module Reek
73
70
  end
74
71
 
75
72
  def configure_with(config)
76
- @config.adopt!(config)
73
+ @config.hash.adopt!(config)
77
74
  end
78
75
 
79
76
  def copy
80
- self.class.new(@config.deep_copy)
77
+ self.class.new(@config.hash.deep_copy)
78
+ end
79
+
80
+ def supersede_with(config)
81
+ clone = self.copy
82
+ @masked = true
83
+ clone.configure_with(config)
84
+ clone
81
85
  end
82
86
 
83
87
  def examine(context)
84
88
  before = @smells_found.size
85
- examine_context(context) if enabled? and !exception?(context)
89
+ examine_context(context) if @config.enabled? and !exception?(context)
86
90
  @smells_found.length > before
87
91
  end
88
92
 
@@ -90,29 +94,23 @@ module Reek
90
94
  end
91
95
 
92
96
  def exception?(context)
93
- context.matches?(@config[EXCLUDE_KEY])
97
+ context.matches?(value(EXCLUDE_KEY, context, DEFAULT_EXCLUDE_SET))
94
98
  end
95
99
 
96
100
  def found(scope, warning)
97
- smell = SmellWarning.new(self, scope, warning)
101
+ smell = SmellWarning.new(self, scope, warning, @masked)
98
102
  @smells_found << smell
99
103
  smell
100
104
  end
101
105
 
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
106
+ def has_smell?(patterns)
107
+ return false if @masked
108
+ @smells_found.each { |warning| return true if warning.contains_all?(patterns) }
109
+ false
110
+ end
107
111
 
108
112
  def report_on(report)
109
- @smells_found.each do |smell|
110
- if @masked
111
- report.record_masked_smell(smell)
112
- else
113
- report << smell
114
- end
115
- end
113
+ @smells_found.each { |smell| smell.report_on(report) }
116
114
  end
117
115
 
118
116
  def num_smells
@@ -126,6 +124,10 @@ module Reek
126
124
  def smell_name
127
125
  self.class.name_words.join(' ')
128
126
  end
127
+
128
+ def value(key, ctx, fall_back)
129
+ @config.value(key, ctx, fall_back)
130
+ end
129
131
  end
130
132
  end
131
133
  end
@@ -15,23 +15,27 @@ module Reek
15
15
  #
16
16
  # Currently +UncommunicativeName+ checks for
17
17
  # * 1-character names
18
- # * names consisting of a single character followed by a number
18
+ # * names ending with a number
19
19
  #
20
20
  class UncommunicativeName < SmellDetector
21
21
 
22
22
  # The name of the config field that lists the regexps of
23
23
  # smelly names to be reported.
24
24
  REJECT_KEY = 'reject'
25
+
26
+ DEFAULT_REJECT_SET = [/^.$/, /[0-9]$/]
25
27
 
26
28
  # The name of the config field that lists the specific names that are
27
29
  # to be treated as exceptions; these names will not be reported as
28
30
  # uncommunicative.
29
31
  ACCEPT_KEY = 'accept'
30
32
 
33
+ DEFAULT_ACCEPT_SET = ['Inline::C']
34
+
31
35
  def self.default_config
32
36
  super.adopt(
33
- REJECT_KEY => [/^.[0-9]*$/],
34
- ACCEPT_KEY => ['Inline::C']
37
+ REJECT_KEY => DEFAULT_REJECT_SET,
38
+ ACCEPT_KEY => DEFAULT_ACCEPT_SET
35
39
  )
36
40
  end
37
41
 
@@ -54,22 +58,22 @@ module Reek
54
58
 
55
59
  def consider_variables(context) # :nodoc:
56
60
  context.variable_names.each do |name|
57
- next unless is_bad_name?(name)
61
+ next unless is_bad_name?(name, context)
58
62
  found(context, "has the variable name '#{name}'")
59
63
  end
60
64
  end
61
65
 
62
66
  def consider_name(context) # :nodoc:
63
67
  name = context.name
64
- return false if @config[ACCEPT_KEY].include?(context.to_s) # TODO: fq_name() ?
65
- return false unless is_bad_name?(name)
68
+ return false if value(ACCEPT_KEY, context, DEFAULT_ACCEPT_SET).include?(context.to_s) # TODO: fq_name() ?
69
+ return false unless is_bad_name?(name, context)
66
70
  found(context, "has the name '#{name}'")
67
71
  end
68
72
 
69
- def is_bad_name?(name) # :nodoc:
73
+ def is_bad_name?(name, context) # :nodoc:
70
74
  var = name.effective_name
71
- return false if var == '*' or @config[ACCEPT_KEY].include?(var)
72
- @config[REJECT_KEY].detect {|patt| patt === var}
75
+ return false if var == '*' or value(ACCEPT_KEY, context, DEFAULT_ACCEPT_SET).include?(var)
76
+ value(REJECT_KEY, context, DEFAULT_REJECT_SET).detect {|patt| patt === var}
73
77
  end
74
78
  end
75
79
  end
data/lib/reek/sniffer.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'reek/detector_stack'
2
+
3
+ # SMELL: Duplication -- all these should be found automagically
2
4
  require 'reek/smells/control_couple'
3
5
  require 'reek/smells/duplication'
4
6
  require 'reek/smells/feature_envy'
@@ -7,6 +9,7 @@ require 'reek/smells/long_method'
7
9
  require 'reek/smells/long_parameter_list'
8
10
  require 'reek/smells/long_yield_list'
9
11
  require 'reek/smells/nested_iterators'
12
+ require 'reek/smells/simulated_polymorphism'
10
13
  require 'reek/smells/uncommunicative_name'
11
14
  require 'reek/smells/utility_function'
12
15
  require 'reek/code_parser'
@@ -52,6 +55,7 @@ module Reek
52
55
  Smells::LongParameterList,
53
56
  Smells::LongYieldList,
54
57
  Smells::NestedIterators,
58
+ Smells::SimulatedPolymorphism,
55
59
  Smells::UncommunicativeName,
56
60
  Smells::UtilityFunction,
57
61
  ]
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.13'
4
+ VERSION = '1.1.3.14'
5
5
  end
data/reek.gemspec CHANGED
@@ -2,17 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{reek}
5
- s.version = "1.1.3.13"
5
+ s.version = "1.1.3.14"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Kevin Rutherford"]
9
- s.date = %q{2009-07-26}
9
+ s.date = %q{2009-08-20}
10
10
  s.default_executable = %q{reek}
11
11
  s.description = %q{Code smell detector for Ruby}
12
12
  s.email = ["kevin@rutherford-software.com"]
13
13
  s.executables = ["reek"]
14
14
  s.extra_rdoc_files = ["History.txt", "License.txt", "README.txt"]
15
- s.files = ["History.txt", "License.txt", "README.txt", "Rakefile", "bin/reek", "config/defaults.reek", "features/masking_smells.feature", "features/options.feature", "features/reports.feature", "features/samples.feature", "features/stdin.feature", "features/step_definitions/reek_steps.rb", "features/support/env.rb", "lib/reek.rb", "lib/reek/adapters/application.rb", "lib/reek/adapters/config_file.rb", "lib/reek/adapters/core_extras.rb", "lib/reek/adapters/object_source.rb", "lib/reek/adapters/rake_task.rb", "lib/reek/adapters/report.rb", "lib/reek/adapters/source.rb", "lib/reek/adapters/spec.rb", "lib/reek/block_context.rb", "lib/reek/class_context.rb", "lib/reek/code_context.rb", "lib/reek/code_parser.rb", "lib/reek/command_line.rb", "lib/reek/detector_stack.rb", "lib/reek/exceptions.reek", "lib/reek/if_context.rb", "lib/reek/method_context.rb", "lib/reek/module_context.rb", "lib/reek/name.rb", "lib/reek/object_refs.rb", "lib/reek/sexp_formatter.rb", "lib/reek/singleton_method_context.rb", "lib/reek/smell_warning.rb", "lib/reek/smells/control_couple.rb", "lib/reek/smells/duplication.rb", "lib/reek/smells/feature_envy.rb", "lib/reek/smells/large_class.rb", "lib/reek/smells/long_method.rb", "lib/reek/smells/long_parameter_list.rb", "lib/reek/smells/long_yield_list.rb", "lib/reek/smells/nested_iterators.rb", "lib/reek/smells/smell_detector.rb", "lib/reek/smells/uncommunicative_name.rb", "lib/reek/smells/utility_function.rb", "lib/reek/sniffer.rb", "lib/reek/stop_context.rb", "lib/reek/yield_call_context.rb", "reek.gemspec", "spec/quality/reek_source_spec.rb", "spec/reek/adapters/report_spec.rb", "spec/reek/adapters/should_reek_of_spec.rb", "spec/reek/adapters/should_reek_only_of_spec.rb", "spec/reek/adapters/should_reek_spec.rb", "spec/reek/block_context_spec.rb", "spec/reek/class_context_spec.rb", "spec/reek/code_context_spec.rb", "spec/reek/code_parser_spec.rb", "spec/reek/config_spec.rb", "spec/reek/if_context_spec.rb", "spec/reek/method_context_spec.rb", "spec/reek/module_context_spec.rb", "spec/reek/name_spec.rb", "spec/reek/object_refs_spec.rb", "spec/reek/object_source_spec.rb", "spec/reek/singleton_method_context_spec.rb", "spec/reek/smell_warning_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/duplication_spec.rb", "spec/reek/smells/feature_envy_spec.rb", "spec/reek/smells/large_class_spec.rb", "spec/reek/smells/long_method_spec.rb", "spec/reek/smells/long_parameter_list_spec.rb", "spec/reek/smells/nested_iterators_spec.rb", "spec/reek/smells/smell_detector_spec.rb", "spec/reek/smells/uncommunicative_name_spec.rb", "spec/reek/smells/utility_function_spec.rb", "spec/reek/sniffer_spec.rb", "spec/samples/all_but_one_masked/clean_one.rb", "spec/samples/all_but_one_masked/dirty.rb", "spec/samples/all_but_one_masked/masked.reek", "spec/samples/clean_due_to_masking/clean_one.rb", "spec/samples/clean_due_to_masking/clean_three.rb", "spec/samples/clean_due_to_masking/clean_two.rb", "spec/samples/clean_due_to_masking/dirty_one.rb", "spec/samples/clean_due_to_masking/dirty_two.rb", "spec/samples/clean_due_to_masking/masked.reek", "spec/samples/corrupt_config_file/corrupt.reek", "spec/samples/corrupt_config_file/dirty.rb", "spec/samples/empty_config_file/dirty.rb", "spec/samples/empty_config_file/empty.reek", "spec/samples/inline.rb", "spec/samples/masked/dirty.rb", "spec/samples/masked/masked.reek", "spec/samples/mixed_results/clean_one.rb", "spec/samples/mixed_results/clean_three.rb", "spec/samples/mixed_results/clean_two.rb", "spec/samples/mixed_results/dirty_one.rb", "spec/samples/mixed_results/dirty_two.rb", "spec/samples/not_quite_masked/dirty.rb", "spec/samples/not_quite_masked/masked.reek", "spec/samples/optparse.rb", "spec/samples/redcloth.rb", "spec/samples/three_clean_files/clean_one.rb", "spec/samples/three_clean_files/clean_three.rb", "spec/samples/three_clean_files/clean_two.rb", "spec/samples/two_smelly_files/dirty_one.rb", "spec/samples/two_smelly_files/dirty_two.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/reek.rake", "tasks/test.rake"]
15
+ s.files = ["History.txt", "License.txt", "README.txt", "Rakefile", "bin/reek", "config/defaults.reek", "features/masking_smells.feature", "features/options.feature", "features/reports.feature", "features/samples.feature", "features/stdin.feature", "features/step_definitions/reek_steps.rb", "features/support/env.rb", "lib/reek.rb", "lib/reek/adapters/application.rb", "lib/reek/adapters/config_file.rb", "lib/reek/adapters/core_extras.rb", "lib/reek/adapters/object_source.rb", "lib/reek/adapters/rake_task.rb", "lib/reek/adapters/report.rb", "lib/reek/adapters/source.rb", "lib/reek/adapters/spec.rb", "lib/reek/block_context.rb", "lib/reek/class_context.rb", "lib/reek/code_context.rb", "lib/reek/code_parser.rb", "lib/reek/command_line.rb", "lib/reek/configuration.rb", "lib/reek/detector_stack.rb", "lib/reek/exceptions.reek", "lib/reek/if_context.rb", "lib/reek/method_context.rb", "lib/reek/module_context.rb", "lib/reek/name.rb", "lib/reek/object_refs.rb", "lib/reek/sexp_formatter.rb", "lib/reek/singleton_method_context.rb", "lib/reek/smell_warning.rb", "lib/reek/smells/control_couple.rb", "lib/reek/smells/duplication.rb", "lib/reek/smells/feature_envy.rb", "lib/reek/smells/large_class.rb", "lib/reek/smells/long_method.rb", "lib/reek/smells/long_parameter_list.rb", "lib/reek/smells/long_yield_list.rb", "lib/reek/smells/nested_iterators.rb", "lib/reek/smells/simulated_polymorphism.rb", "lib/reek/smells/smell_detector.rb", "lib/reek/smells/uncommunicative_name.rb", "lib/reek/smells/utility_function.rb", "lib/reek/sniffer.rb", "lib/reek/stop_context.rb", "lib/reek/yield_call_context.rb", "reek.gemspec", "spec/quality/reek_source_spec.rb", "spec/reek/adapters/report_spec.rb", "spec/reek/adapters/should_reek_of_spec.rb", "spec/reek/adapters/should_reek_only_of_spec.rb", "spec/reek/adapters/should_reek_spec.rb", "spec/reek/block_context_spec.rb", "spec/reek/class_context_spec.rb", "spec/reek/code_context_spec.rb", "spec/reek/code_parser_spec.rb", "spec/reek/config_spec.rb", "spec/reek/configuration_spec.rb", "spec/reek/if_context_spec.rb", "spec/reek/method_context_spec.rb", "spec/reek/module_context_spec.rb", "spec/reek/name_spec.rb", "spec/reek/object_refs_spec.rb", "spec/reek/object_source_spec.rb", "spec/reek/singleton_method_context_spec.rb", "spec/reek/smell_warning_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/duplication_spec.rb", "spec/reek/smells/feature_envy_spec.rb", "spec/reek/smells/large_class_spec.rb", "spec/reek/smells/long_method_spec.rb", "spec/reek/smells/long_parameter_list_spec.rb", "spec/reek/smells/nested_iterators_spec.rb", "spec/reek/smells/simulated_polymorphism_spec.rb", "spec/reek/smells/smell_detector_spec.rb", "spec/reek/smells/uncommunicative_name_spec.rb", "spec/reek/smells/utility_function_spec.rb", "spec/reek/sniffer_spec.rb", "spec/samples/all_but_one_masked/clean_one.rb", "spec/samples/all_but_one_masked/dirty.rb", "spec/samples/all_but_one_masked/masked.reek", "spec/samples/clean_due_to_masking/clean_one.rb", "spec/samples/clean_due_to_masking/clean_three.rb", "spec/samples/clean_due_to_masking/clean_two.rb", "spec/samples/clean_due_to_masking/dirty_one.rb", "spec/samples/clean_due_to_masking/dirty_two.rb", "spec/samples/clean_due_to_masking/masked.reek", "spec/samples/corrupt_config_file/corrupt.reek", "spec/samples/corrupt_config_file/dirty.rb", "spec/samples/empty_config_file/dirty.rb", "spec/samples/empty_config_file/empty.reek", "spec/samples/exceptions.reek", "spec/samples/inline.rb", "spec/samples/masked/dirty.rb", "spec/samples/masked/masked.reek", "spec/samples/mixed_results/clean_one.rb", "spec/samples/mixed_results/clean_three.rb", "spec/samples/mixed_results/clean_two.rb", "spec/samples/mixed_results/dirty_one.rb", "spec/samples/mixed_results/dirty_two.rb", "spec/samples/not_quite_masked/dirty.rb", "spec/samples/not_quite_masked/masked.reek", "spec/samples/optparse.rb", "spec/samples/overrides/masked/dirty.rb", "spec/samples/overrides/masked/lower.reek", "spec/samples/overrides/upper.reek", "spec/samples/redcloth.rb", "spec/samples/three_clean_files/clean_one.rb", "spec/samples/three_clean_files/clean_three.rb", "spec/samples/three_clean_files/clean_two.rb", "spec/samples/two_smelly_files/dirty_one.rb", "spec/samples/two_smelly_files/dirty_two.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/reek.rake", "tasks/test.rake"]
16
16
  s.homepage = %q{http://wiki.github.com/kevinrutherford/reek}
17
17
  s.post_install_message = %q{
18
18
  For more information on reek, see http://wiki.github.com/kevinrutherford/reek
@@ -33,16 +33,17 @@ end
33
33
  describe ReportSection, " as a SortedSet" do
34
34
  it 'should only add a smell once' do
35
35
  rpt = ReportSection.new(''.sniff)
36
- rpt << SmellWarning.new(Smells::FeatureEnvy.new, "self", 'too many!')
37
- rpt << SmellWarning.new(Smells::FeatureEnvy.new, "self", 'too many!')
36
+ rpt << SmellWarning.new(Smells::FeatureEnvy.new, "self", 'too many!', false)
37
+ rpt << SmellWarning.new(Smells::FeatureEnvy.new, "self", 'too many!', false)
38
38
  lines = rpt.smell_list.split("\n")
39
39
  lines.should have(1).lines
40
40
  end
41
41
 
42
42
  it 'should not count an identical masked smell' do
43
43
  rpt = ReportSection.new(''.sniff)
44
- rpt << SmellWarning.new(Smells::FeatureEnvy.new, "self", 'too many!')
45
- rpt.record_masked_smell(SmellWarning.new(Smells::FeatureEnvy.new, "self", 'too many!'))
44
+ # SMELL: Duplication -- the SmellWarning knows whether to call << or record_masked_smell
45
+ rpt << SmellWarning.new(Smells::FeatureEnvy.new, "self", 'too many!', false)
46
+ rpt.record_masked_smell(SmellWarning.new(Smells::FeatureEnvy.new, "self", 'too many!', true))
46
47
  rpt.header.should == 'string -- 1 warning'
47
48
  end
48
49
  end
@@ -168,4 +168,25 @@ describe ClassContext do
168
168
  element = ClassContext.create(StopContext.new, [:colon2, [:colon2, [:const, :Treetop], :Runtime], :SyntaxNode])
169
169
  element.num_methods.should == 0
170
170
  end
171
+
172
+ it 'counts conditionals correctly' do
173
+ src = <<EOS
174
+ class Scrunch
175
+ def first
176
+ return @field == :sym ? 0 : 3;
177
+ end
178
+ def second
179
+ if @field == :sym
180
+ @other += " quarts"
181
+ end
182
+ end
183
+ def third
184
+ raise 'flu!' unless @field == :sym
185
+ end
186
+ end
187
+ EOS
188
+
189
+ ctx = ClassContext.from_s(src)
190
+ ctx.conditionals.length.should == 3
191
+ end
171
192
  end
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ require 'reek/configuration'
4
+
5
+ include Reek
6
+
7
+ describe SmellConfiguration do
8
+ it 'returns the default value when key not found' do
9
+ cf = SmellConfiguration.new({})
10
+ cf.value('fred', nil, 27).should == 27
11
+ end
12
+ end
@@ -7,8 +7,8 @@ include Reek
7
7
 
8
8
  describe SmellWarning, 'equality' do
9
9
  before :each do
10
- @first = SmellWarning.new(Smells::FeatureEnvy.new, "self", "self")
11
- @second = SmellWarning.new(Smells::FeatureEnvy.new, "self", "self")
10
+ @first = SmellWarning.new(Smells::FeatureEnvy.new, "self", "self", true)
11
+ @second = SmellWarning.new(Smells::FeatureEnvy.new, "self", "self", false)
12
12
  end
13
13
 
14
14
  it 'should hash equal when the smell is the same' do
@@ -22,4 +22,32 @@ describe SmellWarning, 'equality' do
22
22
  it 'should compare equal when using <=>' do
23
23
  (@first <=> @second).should == 0
24
24
  end
25
+
26
+ class CountingReport
27
+ attr_reader :masked, :non_masked
28
+ def initialize
29
+ @masked = @non_masked = 0
30
+ end
31
+ def <<(sw)
32
+ @non_masked += 1
33
+ end
34
+
35
+ def record_masked_smell(sw)
36
+ @masked += 1
37
+ end
38
+ end
39
+
40
+ it 'reports as masked when masked' do
41
+ rpt = CountingReport.new
42
+ @first.report_on(rpt)
43
+ rpt.masked.should == 1
44
+ rpt.non_masked.should == 0
45
+ end
46
+
47
+ it 'reports as non-masked when non-masked' do
48
+ rpt = CountingReport.new
49
+ @second.report_on(rpt)
50
+ rpt.masked.should == 0
51
+ rpt.non_masked.should == 1
52
+ end
25
53
  end
@@ -1,5 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
2
 
3
+ require 'reek/configuration'
3
4
  require 'reek/method_context'
4
5
  require 'reek/stop_context'
5
6
  require 'reek/smells/duplication'
@@ -65,7 +66,7 @@ end
65
66
  describe Duplication, 'when disabled' do
66
67
  before :each do
67
68
  @ctx = MethodContext.new(StopContext.new, [0, :double_thing])
68
- @dup = Duplication.new({SmellDetector::ENABLED_KEY => false})
69
+ @dup = Duplication.new({SmellConfiguration::ENABLED_KEY => false})
69
70
  end
70
71
 
71
72
  it 'should not report repeated call' do
@@ -182,6 +182,21 @@ def report
182
182
  @report
183
183
  end
184
184
  EOS
185
+
186
+ ruby.should_not reek
187
+ end
188
+
189
+ it 'interprets << correctly' do
190
+ ruby = <<EOS
191
+ def report_on(report)
192
+ if @is_masked
193
+ report.record_masked_smell(self)
194
+ else
195
+ report << self
196
+ end
197
+ end
198
+ EOS
199
+
185
200
  ruby.should_not reek
186
201
  end
187
202
  end
@@ -14,7 +14,7 @@ describe LargeClass, 'checking Class objects' do
14
14
  pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
15
15
  class BigOne
16
16
  26.times do |i|
17
- define_method "method#{i}".to_sym do
17
+ define_method "method#{i}x".to_sym do
18
18
  @melting
19
19
  end
20
20
  end
@@ -25,12 +25,12 @@ describe LargeClass, 'checking Class objects' do
25
25
  it 'should not report short class' do
26
26
  pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
27
27
  class ShortClass
28
- def method1() @var1; end
29
- def method2() @var2; end
30
- def method3() @var3; end
31
- def method4() @var4; end
32
- def method5() @var5; end
33
- def method6() @var6; end
28
+ def method_a() @var_a; end
29
+ def method_b() @var_b; end
30
+ def method_c() @var_c; end
31
+ def method_d() @var_d; end
32
+ def method_e() @var_e; end
33
+ def method_f() @var_f; end
34
34
  end
35
35
  ShortClass.should_not reek
36
36
  end
@@ -111,9 +111,10 @@ describe LargeClass, 'checking source code' do
111
111
 
112
112
  it 'should not report 10 ivars in 2 extensions' do
113
113
  src = <<EOS
114
- class Full;def ivars1() @aa=@ab=@ac=@ad=@ae; end;end
115
- class Full;def ivars2() @af=@ag=@ah=@ai=@aj; end;end
114
+ class Full;def ivars_a() @aa=@ab=@ac=@ad=@ae; end;end
115
+ class Full;def ivars_b() @af=@ag=@ah=@ai=@aj; end;end
116
116
  EOS
117
+
117
118
  src.should_not reek
118
119
  end
119
120
  end
@@ -134,11 +135,11 @@ EOS
134
135
  it 'should not report 25 methods' do
135
136
  src = <<EOS
136
137
  class Full
137
- def me01()3 end;def me02()3 end;def me03()3 end;def me04()3 end;def me05()3 end
138
- def me11()3 end;def me12()3 end;def me13()3 end;def me14()3 end;def me15()3 end
139
- def me21()3 end;def me22()3 end;def me23()3 end;def me24()3 end;def me25()3 end
140
- def me31()3 end;def me32()3 end;def me33()3 end;def me34()3 end;def me35()3 end
141
- def me41()3 end;def me42()3 end;def me43()3 end;def me44()3 end;def me45()3 end
138
+ def me01x()3 end;def me02x()3 end;def me03x()3 end;def me04x()3 end;def me05x()3 end
139
+ def me11x()3 end;def me12x()3 end;def me13x()3 end;def me14x()3 end;def me15x()3 end
140
+ def me21x()3 end;def me22x()3 end;def me23x()3 end;def me24x()3 end;def me25x()3 end
141
+ def me31x()3 end;def me32x()3 end;def me33x()3 end;def me34x()3 end;def me35x()3 end
142
+ def me41x()3 end;def me42x()3 end;def me43x()3 end;def me44x()3 end;def me45x()3 end
142
143
  end
143
144
  EOS
144
145
  src.should_not reek
@@ -147,12 +148,12 @@ EOS
147
148
  it 'should report 26 methods' do
148
149
  src = <<EOS
149
150
  class Full
150
- def me01()3 end;def me02()3 end;def me03()3 end;def me04()3 end;def me05()3 end
151
- def me11()3 end;def me12()3 end;def me13()3 end;def me14()3 end;def me15()3 end
152
- def me21()3 end;def me22()3 end;def me23()3 end;def me24()3 end;def me25()3 end
153
- def me31()3 end;def me32()3 end;def me33()3 end;def me34()3 end;def me35()3 end
154
- def me41()3 end;def me42()3 end;def me43()3 end;def me44()3 end;def me45()3 end
155
- def me51()3 end
151
+ def me01x()3 end;def me02x()3 end;def me03x()3 end;def me04x()3 end;def me05x()3 end
152
+ def me11x()3 end;def me12x()3 end;def me13x()3 end;def me14x()3 end;def me15x()3 end
153
+ def me21x()3 end;def me22x()3 end;def me23x()3 end;def me24x()3 end;def me25x()3 end
154
+ def me31x()3 end;def me32x()3 end;def me33x()3 end;def me34x()3 end;def me35x()3 end
155
+ def me41x()3 end;def me42x()3 end;def me43x()3 end;def me44x()3 end;def me45x()3 end
156
+ def me51x()3 end
156
157
  end
157
158
  EOS
158
159
  src.should reek_of(:LargeClass)
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
+
3
+ require 'reek/smells/simulated_polymorphism'
4
+
5
+ include Reek::Smells
6
+
7
+ describe SimulatedPolymorphism do
8
+ it 'should report 3 similar conditions in a class' do
9
+ src = <<EOS
10
+ class Scrunch
11
+ def first
12
+ return @field == :sym ? 0 : 3;
13
+ end
14
+ def second
15
+ if @field == :sym
16
+ @other += " quarts"
17
+ end
18
+ end
19
+ def third
20
+ raise 'flu!' unless @field == :sym
21
+ end
22
+ end
23
+ EOS
24
+
25
+ src.should reek_only_of(:SimulatedPolymorphism, /@field == :sym/)
26
+ end
27
+
28
+ it 'should include case statements in the count' do
29
+ src = <<EOS
30
+ class Scrunch
31
+ def first
32
+ return @field ? 0 : 3;
33
+ end
34
+ def second
35
+ case @field
36
+ when :sym
37
+ @other += " quarts"
38
+ end
39
+ end
40
+ def third
41
+ raise 'flu!' unless @field
42
+ end
43
+ end
44
+ EOS
45
+
46
+ src.should reek_only_of(:SimulatedPolymorphism, /@field/)
47
+ end
48
+
49
+ # And count code in superclasses, if we have it
50
+ end
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
2
 
3
- require 'reek/adapters/report'
3
+ require 'reek/configuration'
4
4
  require 'reek/smells/duplication'
5
5
  require 'reek/smells/large_class'
6
6
  require 'reek/smells/long_method'
@@ -14,8 +14,8 @@ describe SmellDetector, 'configuration' do
14
14
  end
15
15
 
16
16
  it 'adopts new max_statements value' do
17
- @detector.configure_with('max_statements' => 25)
18
- @detector.max_statements.should == 25
17
+ @detector.configure_with(LongMethod::MAX_ALLOWED_STATEMENTS_KEY => 25)
18
+ @detector.value(LongMethod::MAX_ALLOWED_STATEMENTS_KEY, nil, 0).should == 25
19
19
  end
20
20
  end
21
21
 
@@ -31,7 +31,7 @@ describe SmellDetector, 'when copied' do
31
31
 
32
32
  it 'should change independently of its parent' do
33
33
  default_max = @detector.max_statements
34
- @copy.configure_with('max_statements' => 25)
34
+ @copy.configure_with(LongMethod::MAX_ALLOWED_STATEMENTS_KEY => 25)
35
35
  @detector.max_statements.should == default_max
36
36
  end
37
37
  end
@@ -47,7 +47,7 @@ describe SmellDetector, 'configuration' do
47
47
  it 'becomes disabled when disabled' do
48
48
  @detector = LargeClass.new
49
49
  @detector.should be_enabled
50
- @detector.configure({'LargeClass' => {'enabled' => false}})
50
+ @detector.configure({'LargeClass' => {SmellConfiguration::ENABLED_KEY => false}})
51
51
  @detector.should_not be_enabled
52
52
  end
53
53
  end
@@ -16,6 +16,9 @@ describe UncommunicativeName, "method name" do
16
16
  it 'should report name of the form "x2"' do
17
17
  'def x2(fred) basics(17) end'.should reek_only_of(:UncommunicativeName, /x2/)
18
18
  end
19
+ it 'should report long name ending in a number' do
20
+ 'def method2(fred) basics(17) end'.should reek_only_of(:UncommunicativeName, /method2/)
21
+ end
19
22
  end
20
23
 
21
24
  describe UncommunicativeName, "field name" do
@@ -28,6 +31,9 @@ describe UncommunicativeName, "field name" do
28
31
  it 'should report name of the form "x2"' do
29
32
  'class Thing; def simple(fred) @x2 end end'.should reek_only_of(:UncommunicativeName, /@x2/, /Thing/, /variable name/)
30
33
  end
34
+ it 'should report long name ending in a number' do
35
+ 'class Thing; def simple(fred) @field12 end end'.should reek_only_of(:UncommunicativeName, /@field12/, /Thing/, /variable name/)
36
+ end
31
37
  it 'should report one-letter fieldname in assignment' do
32
38
  'class Thing; def simple(fred) @x = fred end end'.should reek_only_of(:UncommunicativeName, /@x/, /Thing/, /variable name/)
33
39
  end
@@ -43,6 +49,9 @@ describe UncommunicativeName, "local variable name" do
43
49
  it 'should report name of the form "x2"' do
44
50
  'def simple(fred) x2 = jim(45) end'.should reek_only_of(:UncommunicativeName, /x2/, /variable name/)
45
51
  end
52
+ it 'should report long name ending in a number' do
53
+ 'def simple(fred) var123 = jim(45) end'.should reek_only_of(:UncommunicativeName, /var123/, /variable name/)
54
+ end
46
55
  it 'should report variable name only once' do
47
56
  'def simple(fred) x = jim(45); x = y end'.should reek_only_of(:UncommunicativeName, /x/)
48
57
  end
@@ -63,6 +72,9 @@ describe UncommunicativeName, "parameter name" do
63
72
  it 'should report name of the form "x2"' do
64
73
  'def help(x2) basics(17) end'.should reek_only_of(:UncommunicativeName, /x2/, /variable name/)
65
74
  end
75
+ it 'should report long name ending in a number' do
76
+ 'def help(param1) basics(17) end'.should reek_only_of(:UncommunicativeName, /param1/, /variable name/)
77
+ end
66
78
  end
67
79
 
68
80
  describe UncommunicativeName, "block parameter name" do
@@ -78,6 +90,7 @@ def bad
78
90
  end
79
91
  end
80
92
  EOS
93
+
81
94
  src.should reek_only_of(:UncommunicativeName, /'x'/)
82
95
  end
83
96
  end
@@ -100,6 +113,7 @@ class Thing
100
113
  end
101
114
  end
102
115
  EOS
116
+
103
117
  source.should reek_of(:UncommunicativeName, /'x'/)
104
118
  source.should reek_of(:UncommunicativeName, /'y'/)
105
119
  end