kevinrutherford-reek 1.1.3.13 → 1.1.3.14

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 (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