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