reek 1.2.1 → 1.2.2

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 CHANGED
@@ -1,3 +1,9 @@
1
+ == 1.2.2 (under development in github)
2
+
3
+ === Minor Changes
4
+ * New smell: Attribute (disabled by default)
5
+ * Removed support for MyClass.should_not reek due to ParseTree EOL
6
+
1
7
  == 1.2.1 (2009-10-02)
2
8
 
3
9
  === Minor Changes
data/config/defaults.reek CHANGED
@@ -48,6 +48,10 @@ UtilityFunction:
48
48
  exclude: []
49
49
 
50
50
  enabled: true
51
+ Attribute:
52
+ exclude: []
53
+
54
+ enabled: false
51
55
  SimulatedPolymorphism:
52
56
  exclude: []
53
57
 
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.2.1'
4
+ VERSION = '1.2.2'
5
5
  end
@@ -10,14 +10,6 @@ class Object
10
10
  def sniff
11
11
  Reek::Sniffer.new(self.to_reek_source)
12
12
  end
13
-
14
- #
15
- # Constructs a Sniffer which examines this object for code smells.
16
- # (This feature is only enabled if you have the ParseTree gem installed.)
17
- #
18
- def to_reek_source
19
- ObjectSource.new(self, self.to_s)
20
- end
21
13
  end
22
14
 
23
15
  class File
@@ -1,6 +1,5 @@
1
1
  require 'reek/sniffer'
2
2
  require 'reek/adapters/core_extras'
3
- require 'reek/adapters/object_source'
4
3
  require 'reek/adapters/report'
5
4
 
6
5
  module Reek
@@ -24,7 +24,7 @@ module Reek
24
24
  CodeParser.new(sniffer).process_class(source.syntax_tree)
25
25
  end
26
26
 
27
- attr_reader :conditionals, :parsed_methods, :class_variables
27
+ attr_reader :conditionals, :parsed_methods, :class_variables, :attributes
28
28
 
29
29
  # SMELL: inconsistent with other contexts (not linked to the sexp)
30
30
  def initialize(outer, name, superclass = nil)
@@ -34,6 +34,7 @@ module Reek
34
34
  @parsed_methods = []
35
35
  @instance_variables = Set.new
36
36
  @conditionals = []
37
+ @attributes = Set.new
37
38
  @class_variables = Set.new
38
39
  end
39
40
 
@@ -59,6 +60,16 @@ module Reek
59
60
  @parsed_methods.length
60
61
  end
61
62
 
63
+ def check_for_attribute_declaration(exp)
64
+ if [:attr, :attr_reader, :attr_writer, :attr_accessor].include? exp[2]
65
+ exp[3][1..-1].each {|arg| record_attribute(arg[1])}
66
+ end
67
+ end
68
+
69
+ def record_attribute(attr)
70
+ @attributes << Name.new(attr)
71
+ end
72
+
62
73
  def record_class_variable(cvar)
63
74
  @class_variables << Name.new(cvar)
64
75
  end
@@ -119,6 +119,7 @@ module Reek
119
119
 
120
120
  def process_call(exp)
121
121
  @element.record_call_to(exp)
122
+ @element.check_for_attribute_declaration(exp)
122
123
  process_default(exp)
123
124
  end
124
125
 
@@ -85,6 +85,11 @@ module Reek
85
85
 
86
86
  def record_call_to(exp)
87
87
  @calls[exp] += 1
88
+ record_receiver(exp)
89
+ check_for_attribute_declaration(exp)
90
+ end
91
+
92
+ def record_receiver(exp)
88
93
  receiver, meth = exp[1..2]
89
94
  receiver ||= [:self]
90
95
  case receiver[0]
@@ -14,14 +14,21 @@ module Reek
14
14
  CodeParser.new(sniffer).process_module(source.syntax_tree)
15
15
  end
16
16
 
17
- attr_reader :class_variables
17
+ attr_reader :class_variables, :attributes
18
18
 
19
19
  def initialize(outer, name)
20
20
  super(outer, nil)
21
21
  @name = name
22
+ @attributes = Set.new
22
23
  @class_variables = Set.new
23
24
  end
24
25
 
26
+ def check_for_attribute_declaration(exp)
27
+ if [:attr, :attr_reader, :attr_writer, :attr_accessor].include? exp[2]
28
+ exp[3][1..-1].each {|arg| record_attribute(arg[1])}
29
+ end
30
+ end
31
+
25
32
  def myself
26
33
  @myself ||= @outer.find_module(@name)
27
34
  end
@@ -35,6 +42,10 @@ module Reek
35
42
  "#{@outer.outer_name}#{@name}::"
36
43
  end
37
44
 
45
+ def record_attribute(attr)
46
+ @attributes << Name.new(attr)
47
+ end
48
+
38
49
  def record_class_variable(cvar)
39
50
  @class_variables << Name.new(cvar)
40
51
  end
@@ -0,0 +1,48 @@
1
+ require 'reek/smells/smell_detector'
2
+
3
+ module Reek
4
+ module Smells
5
+
6
+ #
7
+ # A class that publishes a getter or setter for an instance variable
8
+ # invites client classes to become too intimate with its inner workings,
9
+ # and in particular with its representation of state.
10
+ #
11
+ # Currently this detector raises a warning for every +attr+,
12
+ # +attr_reader+, +attr_writer+ and +attr_accessor+ -- including those
13
+ # that are private.
14
+ #
15
+ # TODO:
16
+ # * eliminate private attributes
17
+ # * catch attributes declared "by hand"
18
+ #
19
+ class Attribute < SmellDetector
20
+
21
+ def self.contexts # :nodoc:
22
+ [:class, :module]
23
+ end
24
+
25
+ def self.default_config
26
+ super.adopt(SmellConfiguration::ENABLED_KEY => false)
27
+ end
28
+
29
+ def initialize(config = Attribute.default_config)
30
+ super(config)
31
+ end
32
+
33
+ #
34
+ # Checks whether the given class declares any attributes.
35
+ # Remembers any smells found.
36
+ #
37
+ def examine_context(mod)
38
+ # SMELL: Duplication
39
+ # MethodContext, ClassContext and ModuleContext all know which
40
+ # calls constitute attribute declarations. Need a method on
41
+ # ModuleContext: each_public_call.select [names] {...}
42
+ mod.attributes.each do |attr|
43
+ found(mod, "declares the attribute #{attr}")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
data/lib/reek/sniffer.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'reek/detector_stack'
2
2
 
3
3
  # SMELL: Duplication -- all these should be found automagically
4
+ require 'reek/smells/attribute'
4
5
  require 'reek/smells/class_variable'
5
6
  require 'reek/smells/control_couple'
6
7
  require 'reek/smells/data_clump'
@@ -49,6 +50,7 @@ module Reek
49
50
  def self.smell_classes
50
51
  # SMELL: Duplication -- these should be loaded by listing the files
51
52
  [
53
+ Smells::Attribute,
52
54
  Smells::ClassVariable,
53
55
  Smells::ControlCouple,
54
56
  Smells::DataClump,
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.2.1"
5
+ s.version = "1.2.2"
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-10-03}
9
+ s.date = %q{2009-10-06}
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.rdoc"]
15
- s.files = ["History.txt", "License.txt", "README.rdoc", "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/command_line.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/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/class_variable.rb", "lib/reek/smells/control_couple.rb", "lib/reek/smells/data_clump.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/class_variable_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/data_clump_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/reek/stop_context_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"]
15
+ s.files = ["History.txt", "License.txt", "README.rdoc", "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/command_line.rb", "lib/reek/adapters/config_file.rb", "lib/reek/adapters/core_extras.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/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/attribute.rb", "lib/reek/smells/class_variable.rb", "lib/reek/smells/control_couple.rb", "lib/reek/smells/data_clump.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/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/attribute_spec.rb", "spec/reek/smells/behaves_like_variable_detector.rb", "spec/reek/smells/class_variable_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/data_clump_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/reek/stop_context_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
@@ -8,8 +8,14 @@ include Reek::Spec
8
8
 
9
9
  # belongs in its own spec file
10
10
  describe ReekMatcher do
11
+ before :each do
12
+ smelly_code = Dir['spec/samples/two_smelly_files/*.rb']
13
+ @sniffers = smelly_code.sniff.sniffers
14
+ @full = FullReport.new(@sniffers, '%c %w (%s)', false).report
15
+ end
16
+
11
17
  it 'reports quietly' do
12
- @smelly_code = 'def x() y = 4; end'
18
+ ReekMatcher.create_reporter(@sniffers).should_not == @full
13
19
  end
14
20
  end
15
21
 
@@ -5,22 +5,22 @@ require 'reek/code_parser'
5
5
  include Reek
6
6
 
7
7
  describe CodeParser, "with no method definitions" do
8
- it 'should report no problems for empty source code' do
8
+ it 'reports no problems for empty source code' do
9
9
  ''.should_not reek
10
10
  end
11
- it 'should report no problems for empty class' do
11
+ it 'reports no problems for empty class' do
12
12
  'class Fred; end'.should_not reek
13
13
  end
14
14
  end
15
15
 
16
16
  describe CodeParser, 'with a global method definition' do
17
- it 'should report no problems for simple method' do
17
+ it 'reports no problems for simple method' do
18
18
  'def Outermost::fred() true; end'.should_not reek
19
19
  end
20
20
  end
21
21
 
22
22
  describe CodeParser, 'when a yield is the receiver' do
23
- it 'should report no problems' do
23
+ it 'reports no problems' do
24
24
  source = 'def values(*args)
25
25
  @to_sql += case
26
26
  when block_given? then " #{yield.to_sql}"
@@ -140,4 +140,90 @@ describe CodeParser do
140
140
  it_should_behave_like 'one variable found'
141
141
  end
142
142
  end
143
+
144
+ context 'with no attributes' do
145
+ it 'records nothing in the class' do
146
+ klass = ClassContext.from_s('class Fred; end')
147
+ klass.attributes.should be_empty
148
+ end
149
+ it 'records nothing in the module' do
150
+ ctx = ModuleContext.from_s('module Fred; end')
151
+ ctx.attributes.should be_empty
152
+ end
153
+ end
154
+
155
+ context 'with one attribute' do
156
+ shared_examples_for 'one attribute found' do
157
+ it 'records the attribute' do
158
+ @ctx.attributes.should include(Name.new(:property))
159
+ end
160
+ it 'records only that attribute' do
161
+ @ctx.attributes.length.should == 1
162
+ end
163
+ end
164
+
165
+ context 'declared in a class' do
166
+ before :each do
167
+ @ctx = ClassContext.from_s('class Fred; attr :property; end')
168
+ end
169
+
170
+ it_should_behave_like 'one attribute found'
171
+ end
172
+
173
+ context 'reader in a class' do
174
+ before :each do
175
+ @ctx = ClassContext.from_s('class Fred; attr_reader :property; end')
176
+ end
177
+
178
+ it_should_behave_like 'one attribute found'
179
+ end
180
+
181
+ context 'writer in a class' do
182
+ before :each do
183
+ @ctx = ClassContext.from_s('class Fred; attr_writer :property; end')
184
+ end
185
+
186
+ it_should_behave_like 'one attribute found'
187
+ end
188
+
189
+ context 'accessor in a class' do
190
+ before :each do
191
+ @ctx = ClassContext.from_s('class Fred; attr_accessor :property; end')
192
+ end
193
+
194
+ it_should_behave_like 'one attribute found'
195
+ end
196
+
197
+ context 'declared in a module' do
198
+ before :each do
199
+ @ctx = ModuleContext.from_s('module Fred; attr :property; end')
200
+ end
201
+
202
+ it_should_behave_like 'one attribute found'
203
+ end
204
+
205
+ context 'reader in a module' do
206
+ before :each do
207
+ @ctx = ModuleContext.from_s('module Fred; attr_reader :property; end')
208
+ end
209
+
210
+ it_should_behave_like 'one attribute found'
211
+ end
212
+
213
+ context 'writer in a module' do
214
+ before :each do
215
+ @ctx = ModuleContext.from_s('module Fred; attr_writer :property; end')
216
+ end
217
+
218
+ it_should_behave_like 'one attribute found'
219
+ end
220
+
221
+ context 'accessor in a module' do
222
+ before :each do
223
+ @ctx = ModuleContext.from_s('module Fred; attr_accessor :property; end')
224
+ end
225
+
226
+ it_should_behave_like 'one attribute found'
227
+ end
228
+ end
143
229
  end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper.rb'
2
+
3
+ require 'reek/smells/attribute'
4
+ require 'reek/class_context'
5
+
6
+ require 'spec/reek/smells/behaves_like_variable_detector'
7
+
8
+ include Reek
9
+ include Reek::Smells
10
+
11
+ describe Attribute do
12
+ before :each do
13
+ @detector = Attribute.new
14
+ @record_variable = :record_attribute
15
+ end
16
+
17
+ [ClassContext, ModuleContext].each do |klass|
18
+ context "in a #{klass}" do
19
+ before :each do
20
+ @ctx = klass.create(StopContext.new, "Fred")
21
+ end
22
+
23
+ it_should_behave_like 'a variable detector'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,39 @@
1
+ shared_examples_for 'a variable detector' do
2
+ context 'with no variables' do
3
+ it "doesn't record a smell" do
4
+ @detector.examine_context(@ctx)
5
+ @detector.num_smells.should == 0
6
+ end
7
+ end
8
+
9
+ context 'with one variable encountered twice' do
10
+ before :each do
11
+ @ctx.send(@record_variable, :something)
12
+ @ctx.send(@record_variable, :something)
13
+ @detector.examine_context(@ctx)
14
+ end
15
+
16
+ it 'records only one smell' do
17
+ @detector.num_smells.should == 1
18
+ end
19
+ it 'mentions the variable name in the report' do
20
+ @detector.should have_smell([/something/])
21
+ end
22
+ end
23
+
24
+ context 'with two variables' do
25
+ before :each do
26
+ @ctx.send(@record_variable, :something)
27
+ @ctx.send(@record_variable, :something_else)
28
+ @detector.examine_context(@ctx)
29
+ end
30
+
31
+ it 'records both smells' do
32
+ @detector.num_smells.should == 2
33
+ end
34
+ it 'mentions both variable names in the report' do
35
+ @detector.should have_smell([/something/])
36
+ @detector.should have_smell([/something_else/])
37
+ end
38
+ end
39
+ end
@@ -3,79 +3,24 @@ require File.dirname(__FILE__) + '/../../spec_helper.rb'
3
3
  require 'reek/smells/class_variable'
4
4
  require 'reek/class_context'
5
5
 
6
+ require 'spec/reek/smells/behaves_like_variable_detector'
7
+
6
8
  include Reek
7
9
  include Reek::Smells
8
10
 
9
11
  describe ClassVariable do
10
- shared_examples_for 'a class variable container' do
11
- context 'no class variables' do
12
- it "doesn't record a smell" do
13
- @detector.examine_context(@ctx)
14
- @detector.num_smells.should == 0
15
- end
16
- end
17
-
18
- context 'one class variable' do
19
- before :each do
20
- @ctx.record_class_variable(:@@cvar)
21
- @detector.examine_context(@ctx)
22
- end
23
-
24
- it 'records a smell' do
25
- @detector.num_smells.should == 1
26
- end
27
- it 'mentions the variable name in the report' do
28
- @detector.should have_smell([/@@cvar/])
29
- end
30
- end
31
-
32
- context 'one class variable encountered twice' do
33
- before :each do
34
- @ctx.record_class_variable(:@@cvar)
35
- @ctx.record_class_variable(:@@cvar)
36
- @detector.examine_context(@ctx)
37
- end
38
-
39
- it 'records only one smell' do
40
- @detector.num_smells.should == 1
41
- end
42
- it 'mentions the variable name in the report' do
43
- @detector.should have_smell([/@@cvar/])
44
- end
45
- end
12
+ before :each do
13
+ @detector = ClassVariable.new
14
+ @record_variable = :record_class_variable
15
+ end
46
16
 
47
- context 'two class variables' do
17
+ [ClassContext, ModuleContext].each do |klass|
18
+ context "in a #{klass}" do
48
19
  before :each do
49
- @ctx.record_class_variable(:@@cvar)
50
- @ctx.record_class_variable(:@@another)
51
- @detector.examine_context(@ctx)
52
- end
53
-
54
- it 'records a smell' do
55
- @detector.num_smells.should == 2
56
- end
57
- it 'mentions both variable names in the report' do
58
- @detector.should have_smell([/@@cvar/])
59
- @detector.should have_smell([/@@another/])
20
+ @ctx = klass.create(StopContext.new, "Fred")
60
21
  end
61
- end
62
- end
63
22
 
64
- context 'in a class' do
65
- before :each do
66
- @ctx = ClassContext.create(StopContext.new, "Fred")
67
- @detector = ClassVariable.new
23
+ it_should_behave_like 'a variable detector'
68
24
  end
69
-
70
- it_should_behave_like 'a class variable container'
71
- end
72
-
73
- context 'in a module' do
74
- before :each do
75
- @ctx = ModuleContext.create(StopContext.new, "Fred")
76
- @detector = ClassVariable.new
77
- end
78
-
79
- it_should_behave_like 'a class variable container'
80
25
  end
81
26
  end
@@ -8,57 +8,6 @@ require 'reek/smells/large_class'
8
8
  include Reek
9
9
  include Reek::Smells
10
10
 
11
- describe LargeClass, 'checking Class objects' do
12
-
13
- it 'should not report class with 26 methods' do
14
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
15
- class BigOne
16
- 26.times do |i|
17
- define_method "method#{i}x".to_sym do
18
- @melting
19
- end
20
- end
21
- end
22
- BigOne.should_not reek
23
- end
24
-
25
- it 'should not report short class' do
26
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
27
- class ShortClass
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
- end
35
- ShortClass.should_not reek
36
- end
37
-
38
- describe LargeClass, 'counting instance variables' do
39
- it 'should not report class with 10 ivars' do
40
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
41
- class ManyIvars
42
- def meth
43
- @vara = @varb = @varc = @vard = @vare
44
- @varf = @varg = @varh = @vari = @varj
45
- end
46
- end
47
- ManyIvars.should_not reek
48
- end
49
-
50
- it 'ignores class with only a couple of ivars' do
51
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
52
- LargeClass.should_not reek_of(:LargeClass)
53
- end
54
-
55
- it 'ignores fq class with only a couple of ivars' do
56
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
57
- Reek::Smells::LargeClass.should_not reek_of(:LargeClass)
58
- end
59
- end
60
- end
61
-
62
11
  describe LargeClass, 'when exceptions are listed' do
63
12
 
64
13
  before(:each) do
@@ -53,18 +53,6 @@ describe LongParameterList do
53
53
  'def simple(aarg, polly=2, yep=true, zero=nil) f(3);false end'.should reek_only_of(:LongParameterList, /4 parameters/)
54
54
  end
55
55
  end
56
-
57
- describe 'in a class' do
58
- class InnerTest
59
- def xyzero(arga,argb) f(3);true end
60
- def abc(argx,yep,zero,argm) f(3);false end
61
- end
62
-
63
- it 'should only report long param list' do
64
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
65
- InnerTest.should reek_only_of(:LongParameterList, /abc/)
66
- end
67
- end
68
56
  end
69
57
 
70
58
  describe 'yield' do
@@ -79,24 +79,3 @@ EOS
79
79
  end
80
80
  end
81
81
  end
82
-
83
- describe UtilityFunction do
84
- it 'should not report attrset' do
85
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
86
- class Fred
87
- attr_writer :xyz
88
- end
89
- Fred.should_not reek
90
- end
91
-
92
- it 'should not report overriding methods' do
93
- pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
94
- class Father
95
- def thing(ff); @kids = 0; end
96
- end
97
- class Son < Father
98
- def thing(ff); ff; end
99
- end
100
- Son.should_not reek
101
- end
102
- end
data/tasks/test.rake CHANGED
@@ -6,7 +6,6 @@ require 'spec/rake/spectask'
6
6
 
7
7
  namespace 'test' do
8
8
  UNIT_TESTS = FileList['spec/reek/**/*_spec.rb']
9
- QUALITY_TESTS = FileList['spec/quality/**/*_spec.rb']
10
9
 
11
10
  Spec::Rake::SpecTask.new('spec') do |t|
12
11
  t.spec_files = UNIT_TESTS
@@ -16,7 +15,7 @@ namespace 'test' do
16
15
  end
17
16
 
18
17
  Spec::Rake::SpecTask.new('quality') do |t|
19
- t.spec_files = QUALITY_TESTS
18
+ t.spec_files = FileList['quality/**/*_spec.rb']
20
19
  t.spec_opts = ['--color']
21
20
  t.ruby_opts = ['-Ilib']
22
21
  t.rcov = false
@@ -24,7 +23,7 @@ namespace 'test' do
24
23
 
25
24
  desc 'Runs all unit tests under RCov'
26
25
  Spec::Rake::SpecTask.new('rcov') do |t|
27
- t.spec_files = UNIT_TESTS + QUALITY_TESTS
26
+ t.spec_files = UNIT_TESTS
28
27
  t.rcov = true
29
28
  t.rcov_dir = 'build/coverage'
30
29
  end
@@ -39,7 +38,7 @@ namespace 'test' do
39
38
  end
40
39
 
41
40
  desc 'Runs all unit tests, acceptance tests and quality checks'
42
- task 'all' => ['test:spec', 'test:features', 'test:quality', 'test:multiruby']
41
+ task 'all' => ['test:spec', 'test:features', 'test:multiruby']
43
42
  end
44
43
 
45
44
  task 'clobber_rcov' => 'test:clobber_rcov'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reek
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Rutherford
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-03 00:00:00 +01:00
12
+ date: 2009-10-06 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -72,7 +72,6 @@ files:
72
72
  - lib/reek/adapters/command_line.rb
73
73
  - lib/reek/adapters/config_file.rb
74
74
  - lib/reek/adapters/core_extras.rb
75
- - lib/reek/adapters/object_source.rb
76
75
  - lib/reek/adapters/rake_task.rb
77
76
  - lib/reek/adapters/report.rb
78
77
  - lib/reek/adapters/source.rb
@@ -92,6 +91,7 @@ files:
92
91
  - lib/reek/sexp_formatter.rb
93
92
  - lib/reek/singleton_method_context.rb
94
93
  - lib/reek/smell_warning.rb
94
+ - lib/reek/smells/attribute.rb
95
95
  - lib/reek/smells/class_variable.rb
96
96
  - lib/reek/smells/control_couple.rb
97
97
  - lib/reek/smells/data_clump.rb
@@ -110,7 +110,6 @@ files:
110
110
  - lib/reek/stop_context.rb
111
111
  - lib/reek/yield_call_context.rb
112
112
  - reek.gemspec
113
- - spec/quality/reek_source_spec.rb
114
113
  - spec/reek/adapters/report_spec.rb
115
114
  - spec/reek/adapters/should_reek_of_spec.rb
116
115
  - spec/reek/adapters/should_reek_only_of_spec.rb
@@ -129,6 +128,8 @@ files:
129
128
  - spec/reek/object_source_spec.rb
130
129
  - spec/reek/singleton_method_context_spec.rb
131
130
  - spec/reek/smell_warning_spec.rb
131
+ - spec/reek/smells/attribute_spec.rb
132
+ - spec/reek/smells/behaves_like_variable_detector.rb
132
133
  - spec/reek/smells/class_variable_spec.rb
133
134
  - spec/reek/smells/control_couple_spec.rb
134
135
  - spec/reek/smells/data_clump_spec.rb
@@ -1,52 +0,0 @@
1
- require 'reek/adapters/source'
2
- require 'reek/configuration'
3
- require 'reek/smells/large_class'
4
-
5
- include Reek::Smells
6
-
7
- module Reek
8
- class ObjectSource < Source # :nodoc:
9
-
10
- def self.unify(sexp) # :nodoc:
11
- unifier = Unifier.new
12
- unifier.processors.each do |proc|
13
- proc.unsupported.delete :cfunc # HACK
14
- end
15
- return unifier.process(sexp[0])
16
- end
17
-
18
- def configure(sniffer)
19
- super
20
- disabled_config = {Reek::SmellConfiguration::ENABLED_KEY => false}
21
- sniffer.configure(LargeClass, disabled_config)
22
- end
23
-
24
- def self.can_parse_objects?
25
- return true if Object.const_defined?(:ParseTree)
26
- begin
27
- require 'parse_tree'
28
- true
29
- rescue LoadError
30
- false
31
- end
32
- end
33
-
34
- def syntax_tree
35
- if ObjectSource.can_parse_objects?
36
- ObjectSource.unify(ParseTree.new.parse_tree(@source))
37
- else
38
- throw ArgumentError.new('You must install the ParseTree gem to use this feature')
39
- end
40
- end
41
- end
42
- end
43
-
44
- class Object
45
- #
46
- # Constructs a Sniffer which examines this object for code smells.
47
- # (This feature is only enabled if you have the ParseTree gem installed.)
48
- #
49
- def to_reek_source
50
- ObjectSource.new(self, self.to_s)
51
- end
52
- end
@@ -1,15 +0,0 @@
1
- require File.dirname(__FILE__) + '/../spec_helper.rb'
2
-
3
- describe 'Reek source code' do
4
- it 'has no smells' do
5
- Dir['lib/**/*.rb'].should_not reek
6
- end
7
-
8
- nucleus = Dir['lib/reek/**.rb'] - Dir['lib/reek/adapters/**/*.rb']
9
- nucleus.each do |src|
10
- it "#{src} contains no references from the nucleus out to the adapters" do
11
- IO.readlines(src).grep(/adapters/).should == []
12
- end
13
- end
14
-
15
- end