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 +6 -0
- data/config/defaults.reek +4 -0
- data/lib/reek.rb +1 -1
- data/lib/reek/adapters/core_extras.rb +0 -8
- data/lib/reek/adapters/spec.rb +0 -1
- data/lib/reek/class_context.rb +12 -1
- data/lib/reek/code_parser.rb +1 -0
- data/lib/reek/method_context.rb +5 -0
- data/lib/reek/module_context.rb +12 -1
- data/lib/reek/smells/attribute.rb +48 -0
- data/lib/reek/sniffer.rb +2 -0
- data/reek.gemspec +3 -3
- data/spec/reek/adapters/should_reek_of_spec.rb +7 -1
- data/spec/reek/code_parser_spec.rb +90 -4
- data/spec/reek/smells/attribute_spec.rb +26 -0
- data/spec/reek/smells/behaves_like_variable_detector.rb +39 -0
- data/spec/reek/smells/class_variable_spec.rb +10 -65
- data/spec/reek/smells/large_class_spec.rb +0 -51
- data/spec/reek/smells/long_parameter_list_spec.rb +0 -12
- data/spec/reek/smells/utility_function_spec.rb +0 -21
- data/tasks/test.rake +3 -4
- metadata +5 -4
- data/lib/reek/adapters/object_source.rb +0 -52
- data/spec/quality/reek_source_spec.rb +0 -15
data/History.txt
CHANGED
data/config/defaults.reek
CHANGED
data/lib/reek.rb
CHANGED
@@ -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
|
data/lib/reek/adapters/spec.rb
CHANGED
data/lib/reek/class_context.rb
CHANGED
@@ -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
|
data/lib/reek/code_parser.rb
CHANGED
data/lib/reek/method_context.rb
CHANGED
data/lib/reek/module_context.rb
CHANGED
@@ -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.
|
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-
|
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/
|
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
|
-
@
|
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 '
|
8
|
+
it 'reports no problems for empty source code' do
|
9
9
|
''.should_not reek
|
10
10
|
end
|
11
|
-
it '
|
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 '
|
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 '
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
17
|
+
[ClassContext, ModuleContext].each do |klass|
|
18
|
+
context "in a #{klass}" do
|
48
19
|
before :each do
|
49
|
-
@ctx.
|
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
|
-
|
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 =
|
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
|
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:
|
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.
|
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-
|
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
|