reek 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
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