kevinrutherford-reek 1.1.3.14 → 1.1.3.15
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 +2 -0
- data/config/defaults.reek +6 -0
- data/features/samples.feature +4 -2
- data/lib/reek/class_context.rb +7 -3
- data/lib/reek/code_parser.rb +1 -8
- data/lib/reek/method_context.rb +53 -11
- data/lib/reek/name.rb +8 -2
- data/lib/reek/smells/data_clump.rb +88 -0
- data/lib/reek/sniffer.rb +19 -16
- data/lib/reek.rb +1 -1
- data/reek.gemspec +3 -3
- data/spec/reek/block_context_spec.rb +1 -1
- data/spec/reek/name_spec.rb +24 -0
- data/spec/reek/singleton_method_context_spec.rb +1 -1
- data/spec/reek/smells/data_clump_spec.rb +87 -0
- data/spec/reek/smells/large_class_spec.rb +1 -1
- data/spec/reek/smells/uncommunicative_name_spec.rb +2 -2
- metadata +5 -4
data/History.txt
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
=== Major Changes
|
4
4
|
* Reek passes all its tests under ruby 1.8.6, 1.8.7 and 1.9.1 (fixed #16)
|
5
|
+
* New smell -- Data Clump:
|
6
|
+
** Looks within a class for 3 or more methods taking the same 2 or more parameters
|
5
7
|
* New smell -- Simulated Polymorphism:
|
6
8
|
** Currently only performs basic check for multiple tests of same value
|
7
9
|
* Reek's output reports are now formatted differently:
|
data/config/defaults.reek
CHANGED
data/features/samples.feature
CHANGED
@@ -9,8 +9,9 @@ Feature: Basic smell detection
|
|
9
9
|
Then it fails with exit status 2
|
10
10
|
And it reports:
|
11
11
|
"""
|
12
|
-
spec/samples/inline.rb --
|
12
|
+
spec/samples/inline.rb -- 36 warnings (+1 masked):
|
13
13
|
Inline::C has at least 13 instance variables (Large Class)
|
14
|
+
Inline::C takes parameters [options, src] to 5 methods (Data Clump)
|
14
15
|
Inline::C tests $DEBUG at least 7 times (Simulated Polymorphism)
|
15
16
|
Inline::C tests $TESTING at least 4 times (Simulated Polymorphism)
|
16
17
|
Inline::C tests @@type_map.has_key?(type) at least 3 times (Simulated Polymorphism)
|
@@ -183,8 +184,9 @@ Feature: Basic smell detection
|
|
183
184
|
Then it fails with exit status 2
|
184
185
|
And it reports:
|
185
186
|
"""
|
186
|
-
spec/samples/redcloth.rb --
|
187
|
+
spec/samples/redcloth.rb -- 100 warnings:
|
187
188
|
RedCloth has at least 44 methods (Large Class)
|
189
|
+
RedCloth takes parameters [atts, cite, content, tag] to 3 methods (Data Clump)
|
188
190
|
RedCloth tests atts at least 6 times (Simulated Polymorphism)
|
189
191
|
RedCloth tests codepre.zero? at least 3 times (Simulated Polymorphism)
|
190
192
|
RedCloth tests href at least 3 times (Simulated Polymorphism)
|
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
|
27
|
+
attr_reader :conditionals, :parsed_methods
|
28
28
|
|
29
29
|
# SMELL: inconsistent with other contexts (not linked to the sexp)
|
30
30
|
def initialize(outer, name, superclass = nil)
|
@@ -62,8 +62,8 @@ module Reek
|
|
62
62
|
@instance_variables << Name.new(sym)
|
63
63
|
end
|
64
64
|
|
65
|
-
def record_method(
|
66
|
-
@parsed_methods <<
|
65
|
+
def record_method(meth)
|
66
|
+
@parsed_methods << meth
|
67
67
|
end
|
68
68
|
|
69
69
|
def outer_name
|
@@ -81,5 +81,9 @@ module Reek
|
|
81
81
|
def record_conditional(exp)
|
82
82
|
@conditionals << exp
|
83
83
|
end
|
84
|
+
|
85
|
+
def parameterized_methods(min_clump_size)
|
86
|
+
parsed_methods.select {|meth| meth.parameters.length >= min_clump_size }
|
87
|
+
end
|
84
88
|
end
|
85
89
|
end
|
data/lib/reek/code_parser.rb
CHANGED
@@ -74,9 +74,7 @@ module Reek
|
|
74
74
|
handle_context(SingletonMethodContext, :defs, exp)
|
75
75
|
end
|
76
76
|
|
77
|
-
def process_args(exp)
|
78
|
-
exp[1..-1].each {|sym| @element.record_parameter(sym) }
|
79
|
-
end
|
77
|
+
def process_args(exp) end
|
80
78
|
|
81
79
|
def process_attrset(exp)
|
82
80
|
@element.record_depends_on_self if /^@/ === exp[1].to_s
|
@@ -95,11 +93,6 @@ module Reek
|
|
95
93
|
process(exp[1])
|
96
94
|
handle_context(BlockContext, :iter, exp[2..-1])
|
97
95
|
end
|
98
|
-
|
99
|
-
def process_dasgn_curr(exp)
|
100
|
-
@element.record_parameter(exp[1])
|
101
|
-
process_default(exp)
|
102
|
-
end
|
103
96
|
|
104
97
|
def process_block(exp)
|
105
98
|
@element.count_statements(CodeParser.count_statements(exp))
|
data/lib/reek/method_context.rb
CHANGED
@@ -2,7 +2,55 @@ require 'reek/name'
|
|
2
2
|
require 'reek/code_context'
|
3
3
|
require 'reek/object_refs'
|
4
4
|
|
5
|
+
class Array
|
6
|
+
def power_set
|
7
|
+
self.inject([[]]) { |cum, element| cum.cross(element) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def bounded_power_set(lower_bound)
|
11
|
+
power_set.select {|ps| ps.length > lower_bound}
|
12
|
+
end
|
13
|
+
|
14
|
+
def cross(element)
|
15
|
+
result = []
|
16
|
+
self.each do |set|
|
17
|
+
result << set
|
18
|
+
result << (set + [element])
|
19
|
+
end
|
20
|
+
result
|
21
|
+
end
|
22
|
+
|
23
|
+
def intersection
|
24
|
+
self.inject { |res, elem| elem & res }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
5
28
|
module Reek
|
29
|
+
|
30
|
+
module MethodParameters
|
31
|
+
def self.is_arg?(param)
|
32
|
+
return false if (Array === param and param[0] == :block)
|
33
|
+
return !(param.to_s =~ /^\&/)
|
34
|
+
end
|
35
|
+
|
36
|
+
def names
|
37
|
+
return @names if @names
|
38
|
+
@names = self[1..-1].select {|arg| MethodParameters.is_arg?(arg)}.map {|arg| Name.new(arg)}
|
39
|
+
end
|
40
|
+
|
41
|
+
def length
|
42
|
+
names.length
|
43
|
+
end
|
44
|
+
|
45
|
+
def include?(name)
|
46
|
+
names.include?(name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
"[#{names.map{|nm| nm.to_s}.join(', ')}]"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
6
54
|
class MethodContext < CodeContext
|
7
55
|
attr_reader :parameters
|
8
56
|
attr_reader :calls
|
@@ -11,14 +59,16 @@ module Reek
|
|
11
59
|
|
12
60
|
def initialize(outer, exp, record = true)
|
13
61
|
super(outer, exp)
|
14
|
-
@parameters = []
|
62
|
+
@parameters = exp[exp[0] == :defn ? 2 : 3] # SMELL: SimulatedPolymorphism
|
63
|
+
@parameters ||= []
|
64
|
+
@parameters.extend(MethodParameters)
|
15
65
|
@local_variables = []
|
16
66
|
@name = Name.new(exp[1])
|
17
67
|
@num_statements = 0
|
18
68
|
@calls = Hash.new(0)
|
19
69
|
@depends_on_self = false
|
20
70
|
@refs = ObjectRefs.new
|
21
|
-
@outer.record_method(
|
71
|
+
@outer.record_method(self)
|
22
72
|
end
|
23
73
|
|
24
74
|
def count_statements(num)
|
@@ -63,14 +113,6 @@ module Reek
|
|
63
113
|
@local_variables << Name.new(sym)
|
64
114
|
end
|
65
115
|
|
66
|
-
def self.is_block_arg?(param)
|
67
|
-
(Array === param and param[0] == :block) or (param.to_s =~ /^\&/)
|
68
|
-
end
|
69
|
-
|
70
|
-
def record_parameter(param)
|
71
|
-
@parameters << Name.new(param) unless MethodContext.is_block_arg?(param)
|
72
|
-
end
|
73
|
-
|
74
116
|
def outer_name
|
75
117
|
"#{@outer.outer_name}#{@name}/"
|
76
118
|
end
|
@@ -85,7 +127,7 @@ module Reek
|
|
85
127
|
end
|
86
128
|
|
87
129
|
def variable_names
|
88
|
-
@parameters + @local_variables
|
130
|
+
@parameters.names + @local_variables
|
89
131
|
end
|
90
132
|
end
|
91
133
|
end
|
data/lib/reek/name.rb
CHANGED
@@ -32,16 +32,22 @@ module Reek
|
|
32
32
|
@name.hash
|
33
33
|
end
|
34
34
|
|
35
|
+
def eql?(other)
|
36
|
+
self == other
|
37
|
+
end
|
38
|
+
|
35
39
|
def <=>(other) # :nodoc:
|
36
40
|
@name <=> other.to_s
|
37
41
|
end
|
38
42
|
|
39
|
-
alias eql? <=>
|
40
|
-
|
41
43
|
def effective_name
|
42
44
|
@name.gsub(/^@*/, '')
|
43
45
|
end
|
44
46
|
|
47
|
+
def inspect
|
48
|
+
@name.inspect
|
49
|
+
end
|
50
|
+
|
45
51
|
def to_s
|
46
52
|
@name
|
47
53
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'reek/smells/smell_detector'
|
2
|
+
require 'reek/smell_warning'
|
3
|
+
require 'reek/sexp_formatter'
|
4
|
+
|
5
|
+
module Reek
|
6
|
+
module Smells
|
7
|
+
|
8
|
+
#
|
9
|
+
# A Data Clump occurs when the same two or three items frequently
|
10
|
+
# appear together in classes and parameter lists, or when a group
|
11
|
+
# of instance variable names start or end with similar substrings.
|
12
|
+
#
|
13
|
+
# The recurrence of the items often means there is duplicate code
|
14
|
+
# spread around to handle them. There may be an abstraction missing
|
15
|
+
# from the code, making the system harder to understand.
|
16
|
+
#
|
17
|
+
# Currently Reek looks for a group of two or more parameters with
|
18
|
+
# the same names that are expected by three or more methods of a class.
|
19
|
+
#
|
20
|
+
class DataClump < SmellDetector
|
21
|
+
|
22
|
+
def self.contexts # :nodoc:
|
23
|
+
[:class]
|
24
|
+
end
|
25
|
+
|
26
|
+
# The name of the config field that sets the maximum allowed
|
27
|
+
# copies of any clump.
|
28
|
+
MAX_COPIES_KEY = 'max_copies'
|
29
|
+
|
30
|
+
DEFAULT_MAX_COPIES = 2
|
31
|
+
|
32
|
+
MIN_CLUMP_SIZE_KEY = 'min_clump_size'
|
33
|
+
DEFAULT_MIN_CLUMP_SIZE = 2
|
34
|
+
|
35
|
+
def self.default_config
|
36
|
+
super.adopt(
|
37
|
+
MAX_COPIES_KEY => DEFAULT_MAX_COPIES,
|
38
|
+
MIN_CLUMP_SIZE_KEY => DEFAULT_MIN_CLUMP_SIZE
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(config = DataClump.default_config)
|
43
|
+
super(config)
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Checks the given ClassContext for multiple identical conditional tests.
|
48
|
+
# Remembers any smells found.
|
49
|
+
#
|
50
|
+
def examine_context(klass)
|
51
|
+
max_copies = value(MAX_COPIES_KEY, klass, DEFAULT_MAX_COPIES)
|
52
|
+
min_clump_size = value(MIN_CLUMP_SIZE_KEY, klass, DEFAULT_MIN_CLUMP_SIZE)
|
53
|
+
MethodGroup.new(klass, min_clump_size, max_copies).clumps.each do |clump, occurs|
|
54
|
+
found(klass, "takes parameters #{DataClump.print_clump(clump)} to #{occurs} methods")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.print_clump(clump)
|
59
|
+
"[#{clump.map {|name| name.to_s}.join(', ')}]"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Represents a group of methods
|
65
|
+
class MethodGroup # :nodoc:
|
66
|
+
|
67
|
+
def self.intersection_of_parameters_of(methods)
|
68
|
+
methods.map {|meth| meth.parameters.names.sort}.intersection
|
69
|
+
end
|
70
|
+
|
71
|
+
def initialize(klass, min_clump_size, max_copies)
|
72
|
+
@klass = klass
|
73
|
+
@min_clump_size = min_clump_size
|
74
|
+
@max_copies = max_copies
|
75
|
+
end
|
76
|
+
|
77
|
+
def clumps
|
78
|
+
results = Hash.new(0)
|
79
|
+
@klass.parameterized_methods(@min_clump_size).bounded_power_set(@max_copies).each do |methods|
|
80
|
+
clump = MethodGroup.intersection_of_parameters_of(methods)
|
81
|
+
if clump.length >= @min_clump_size
|
82
|
+
results[clump] = [methods.length, results[clump]].max
|
83
|
+
end
|
84
|
+
end
|
85
|
+
results
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/reek/sniffer.rb
CHANGED
@@ -2,6 +2,7 @@ require 'reek/detector_stack'
|
|
2
2
|
|
3
3
|
# SMELL: Duplication -- all these should be found automagically
|
4
4
|
require 'reek/smells/control_couple'
|
5
|
+
require 'reek/smells/data_clump'
|
5
6
|
require 'reek/smells/duplication'
|
6
7
|
require 'reek/smells/feature_envy'
|
7
8
|
require 'reek/smells/large_class'
|
@@ -44,27 +45,29 @@ end
|
|
44
45
|
module Reek
|
45
46
|
class Sniffer
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
48
|
+
def self.smell_classes
|
49
|
+
# SMELL: Duplication -- these should be loaded by listing the files
|
50
|
+
[
|
51
|
+
Smells::ControlCouple,
|
52
|
+
Smells::DataClump,
|
53
|
+
Smells::Duplication,
|
54
|
+
Smells::FeatureEnvy,
|
55
|
+
Smells::LargeClass,
|
56
|
+
Smells::LongMethod,
|
57
|
+
Smells::LongParameterList,
|
58
|
+
Smells::LongYieldList,
|
59
|
+
Smells::NestedIterators,
|
60
|
+
Smells::SimulatedPolymorphism,
|
61
|
+
Smells::UncommunicativeName,
|
62
|
+
Smells::UtilityFunction,
|
63
|
+
]
|
64
|
+
end
|
62
65
|
|
63
66
|
def initialize(src)
|
64
67
|
@already_checked_for_smells = false
|
65
68
|
@typed_detectors = nil
|
66
69
|
@detectors = Hash.new
|
67
|
-
|
70
|
+
Sniffer.smell_classes.each { |klass| @detectors[klass] = DetectorStack.new(klass.new) }
|
68
71
|
@source = src
|
69
72
|
src.configure(self)
|
70
73
|
end
|
data/lib/reek.rb
CHANGED
data/reek.gemspec
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{reek}
|
5
|
-
s.version = "1.1.3.
|
5
|
+
s.version = "1.1.3.15"
|
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-
|
9
|
+
s.date = %q{2009-09-03}
|
10
10
|
s.default_executable = %q{reek}
|
11
11
|
s.description = %q{Code smell detector for Ruby}
|
12
12
|
s.email = ["kevin@rutherford-software.com"]
|
13
13
|
s.executables = ["reek"]
|
14
14
|
s.extra_rdoc_files = ["History.txt", "License.txt", "README.txt"]
|
15
|
-
s.files = ["History.txt", "License.txt", "README.txt", "Rakefile", "bin/reek", "config/defaults.reek", "features/masking_smells.feature", "features/options.feature", "features/reports.feature", "features/samples.feature", "features/stdin.feature", "features/step_definitions/reek_steps.rb", "features/support/env.rb", "lib/reek.rb", "lib/reek/adapters/application.rb", "lib/reek/adapters/config_file.rb", "lib/reek/adapters/core_extras.rb", "lib/reek/adapters/object_source.rb", "lib/reek/adapters/rake_task.rb", "lib/reek/adapters/report.rb", "lib/reek/adapters/source.rb", "lib/reek/adapters/spec.rb", "lib/reek/block_context.rb", "lib/reek/class_context.rb", "lib/reek/code_context.rb", "lib/reek/code_parser.rb", "lib/reek/command_line.rb", "lib/reek/configuration.rb", "lib/reek/detector_stack.rb", "lib/reek/exceptions.reek", "lib/reek/if_context.rb", "lib/reek/method_context.rb", "lib/reek/module_context.rb", "lib/reek/name.rb", "lib/reek/object_refs.rb", "lib/reek/sexp_formatter.rb", "lib/reek/singleton_method_context.rb", "lib/reek/smell_warning.rb", "lib/reek/smells/control_couple.rb", "lib/reek/smells/duplication.rb", "lib/reek/smells/feature_envy.rb", "lib/reek/smells/large_class.rb", "lib/reek/smells/long_method.rb", "lib/reek/smells/long_parameter_list.rb", "lib/reek/smells/long_yield_list.rb", "lib/reek/smells/nested_iterators.rb", "lib/reek/smells/simulated_polymorphism.rb", "lib/reek/smells/smell_detector.rb", "lib/reek/smells/uncommunicative_name.rb", "lib/reek/smells/utility_function.rb", "lib/reek/sniffer.rb", "lib/reek/stop_context.rb", "lib/reek/yield_call_context.rb", "reek.gemspec", "spec/quality/reek_source_spec.rb", "spec/reek/adapters/report_spec.rb", "spec/reek/adapters/should_reek_of_spec.rb", "spec/reek/adapters/should_reek_only_of_spec.rb", "spec/reek/adapters/should_reek_spec.rb", "spec/reek/block_context_spec.rb", "spec/reek/class_context_spec.rb", "spec/reek/code_context_spec.rb", "spec/reek/code_parser_spec.rb", "spec/reek/config_spec.rb", "spec/reek/configuration_spec.rb", "spec/reek/if_context_spec.rb", "spec/reek/method_context_spec.rb", "spec/reek/module_context_spec.rb", "spec/reek/name_spec.rb", "spec/reek/object_refs_spec.rb", "spec/reek/object_source_spec.rb", "spec/reek/singleton_method_context_spec.rb", "spec/reek/smell_warning_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/duplication_spec.rb", "spec/reek/smells/feature_envy_spec.rb", "spec/reek/smells/large_class_spec.rb", "spec/reek/smells/long_method_spec.rb", "spec/reek/smells/long_parameter_list_spec.rb", "spec/reek/smells/nested_iterators_spec.rb", "spec/reek/smells/simulated_polymorphism_spec.rb", "spec/reek/smells/smell_detector_spec.rb", "spec/reek/smells/uncommunicative_name_spec.rb", "spec/reek/smells/utility_function_spec.rb", "spec/reek/sniffer_spec.rb", "spec/samples/all_but_one_masked/clean_one.rb", "spec/samples/all_but_one_masked/dirty.rb", "spec/samples/all_but_one_masked/masked.reek", "spec/samples/clean_due_to_masking/clean_one.rb", "spec/samples/clean_due_to_masking/clean_three.rb", "spec/samples/clean_due_to_masking/clean_two.rb", "spec/samples/clean_due_to_masking/dirty_one.rb", "spec/samples/clean_due_to_masking/dirty_two.rb", "spec/samples/clean_due_to_masking/masked.reek", "spec/samples/corrupt_config_file/corrupt.reek", "spec/samples/corrupt_config_file/dirty.rb", "spec/samples/empty_config_file/dirty.rb", "spec/samples/empty_config_file/empty.reek", "spec/samples/exceptions.reek", "spec/samples/inline.rb", "spec/samples/masked/dirty.rb", "spec/samples/masked/masked.reek", "spec/samples/mixed_results/clean_one.rb", "spec/samples/mixed_results/clean_three.rb", "spec/samples/mixed_results/clean_two.rb", "spec/samples/mixed_results/dirty_one.rb", "spec/samples/mixed_results/dirty_two.rb", "spec/samples/not_quite_masked/dirty.rb", "spec/samples/not_quite_masked/masked.reek", "spec/samples/optparse.rb", "spec/samples/overrides/masked/dirty.rb", "spec/samples/overrides/masked/lower.reek", "spec/samples/overrides/upper.reek", "spec/samples/redcloth.rb", "spec/samples/three_clean_files/clean_one.rb", "spec/samples/three_clean_files/clean_three.rb", "spec/samples/three_clean_files/clean_two.rb", "spec/samples/two_smelly_files/dirty_one.rb", "spec/samples/two_smelly_files/dirty_two.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/reek.rake", "tasks/test.rake"]
|
15
|
+
s.files = ["History.txt", "License.txt", "README.txt", "Rakefile", "bin/reek", "config/defaults.reek", "features/masking_smells.feature", "features/options.feature", "features/reports.feature", "features/samples.feature", "features/stdin.feature", "features/step_definitions/reek_steps.rb", "features/support/env.rb", "lib/reek.rb", "lib/reek/adapters/application.rb", "lib/reek/adapters/config_file.rb", "lib/reek/adapters/core_extras.rb", "lib/reek/adapters/object_source.rb", "lib/reek/adapters/rake_task.rb", "lib/reek/adapters/report.rb", "lib/reek/adapters/source.rb", "lib/reek/adapters/spec.rb", "lib/reek/block_context.rb", "lib/reek/class_context.rb", "lib/reek/code_context.rb", "lib/reek/code_parser.rb", "lib/reek/command_line.rb", "lib/reek/configuration.rb", "lib/reek/detector_stack.rb", "lib/reek/exceptions.reek", "lib/reek/if_context.rb", "lib/reek/method_context.rb", "lib/reek/module_context.rb", "lib/reek/name.rb", "lib/reek/object_refs.rb", "lib/reek/sexp_formatter.rb", "lib/reek/singleton_method_context.rb", "lib/reek/smell_warning.rb", "lib/reek/smells/control_couple.rb", "lib/reek/smells/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/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/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
|
@@ -27,7 +27,7 @@ describe BlockContext do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should not pass parameters upward" do
|
30
|
-
mc = MethodContext.new(StopContext.new, s(:defn, :help))
|
30
|
+
mc = MethodContext.new(StopContext.new, s(:defn, :help, s(:args)))
|
31
31
|
element = BlockContext.new(mc, s(s(:lasgn, :x)))
|
32
32
|
mc.variable_names.should be_empty
|
33
33
|
end
|
data/spec/reek/name_spec.rb
CHANGED
@@ -11,3 +11,27 @@ describe Name, 'resolving symbols' do
|
|
11
11
|
res[1].should == "LargeClass"
|
12
12
|
end
|
13
13
|
end
|
14
|
+
|
15
|
+
describe Name do
|
16
|
+
it 'compares correctly' do
|
17
|
+
a1 = [Name.new('conts'), Name.new('p1'), Name.new('p2'), Name.new('p3')]
|
18
|
+
a2 = [Name.new('name'), Name.new('windowH'), Name.new('windowW')]
|
19
|
+
(a1 & a2).should == []
|
20
|
+
end
|
21
|
+
|
22
|
+
it do
|
23
|
+
[Name.new(:fred)].should include(Name.new(:fred))
|
24
|
+
end
|
25
|
+
|
26
|
+
it do
|
27
|
+
set = Set.new
|
28
|
+
set << Name.new(:fred)
|
29
|
+
set.should include(Name.new(:fred))
|
30
|
+
end
|
31
|
+
|
32
|
+
it do
|
33
|
+
fred = Name.new(:fred)
|
34
|
+
fred.should eql(fred)
|
35
|
+
fred.should eql(Name.new(:fred))
|
36
|
+
end
|
37
|
+
end
|
@@ -11,7 +11,7 @@ describe SingletonMethodContext, 'outer_name' do
|
|
11
11
|
it "should report full context" do
|
12
12
|
element = StopContext.new
|
13
13
|
element = ModuleContext.new(element, Name.new(:mod))
|
14
|
-
element = SingletonMethodContext.new(element,
|
14
|
+
element = SingletonMethodContext.new(element, s(:defs, s(:call, nil, :a, s(:arglist)), :b, s(:args)))
|
15
15
|
element.outer_name.should match(/mod::a\.b/)
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'reek/smells/data_clump'
|
4
|
+
|
5
|
+
include Reek::Smells
|
6
|
+
|
7
|
+
describe DataClump do
|
8
|
+
it 'should not report small parameter sets' do
|
9
|
+
src = <<EOS
|
10
|
+
class Scrunch
|
11
|
+
def first(pa) @field == :sym ? 0 : 3; end
|
12
|
+
def second(pa) @field == :sym; end
|
13
|
+
def third(pa) pa - pb + @fred; end
|
14
|
+
end
|
15
|
+
EOS
|
16
|
+
|
17
|
+
src.should_not reek
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should report 3 identical pairs in a class' do
|
21
|
+
src = <<EOS
|
22
|
+
class Scrunch
|
23
|
+
def first(pa, pb) @field == :sym ? 0 : 3; end
|
24
|
+
def second(pa, pb) @field == :sym; end
|
25
|
+
def third(pa, pb) pa - pb + @fred; end
|
26
|
+
end
|
27
|
+
EOS
|
28
|
+
|
29
|
+
src.should reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should report 3 swapped pairs in a class' do
|
33
|
+
src = <<EOS
|
34
|
+
class Scrunch
|
35
|
+
def one(pa, pb) @field == :sym ? 0 : 3; end
|
36
|
+
def two(pb, pa) @field == :sym; end
|
37
|
+
def tri(pa, pb) pa - pb + @fred; end
|
38
|
+
end
|
39
|
+
EOS
|
40
|
+
|
41
|
+
src.should reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should report 3 identical parameter sets in a class' do
|
45
|
+
src = <<EOS
|
46
|
+
class Scrunch
|
47
|
+
def first(pa, pb, pc) @field == :sym ? 0 : 3; end
|
48
|
+
def second(pa, pb, pc) @field == :sym; end
|
49
|
+
def third(pa, pb, pc) pa - pb + @fred; end
|
50
|
+
end
|
51
|
+
EOS
|
52
|
+
|
53
|
+
src.should reek_of(:DataClump, /\[pa, pb, pc\]/, /3 methods/)
|
54
|
+
src.should_not reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
|
55
|
+
src.should_not reek_of(:DataClump, /\[pa, pc\]/, /3 methods/)
|
56
|
+
src.should_not reek_of(:DataClump, /\[pb, pc\]/, /3 methods/)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should recognise re-ordered identical parameter sets' do
|
60
|
+
src = <<EOS
|
61
|
+
class Scrunch
|
62
|
+
def first(pb, pa, pc) @field == :sym ? 0 : 3; end
|
63
|
+
def second(pc, pb, pa) @field == :sym; end
|
64
|
+
def third(pa, pb, pc) pa - pb + @fred; end
|
65
|
+
end
|
66
|
+
EOS
|
67
|
+
|
68
|
+
src.should reek_of(:DataClump, /\[pa, pb, pc\]/, /3 methods/)
|
69
|
+
src.should_not reek_of(:DataClump, /\[pa, pb\]/, /3 methods/)
|
70
|
+
src.should_not reek_of(:DataClump, /\[pa, pc\]/, /3 methods/)
|
71
|
+
src.should_not reek_of(:DataClump, /\[pb, pc\]/, /3 methods/)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should count only identical parameter sets' do
|
75
|
+
src = <<EOS
|
76
|
+
class RedCloth
|
77
|
+
def fa(p1, p2, p3, conten) end
|
78
|
+
def fb(p1, p2, p3, conten) end
|
79
|
+
def fc(name, windowW, windowH) end
|
80
|
+
end
|
81
|
+
EOS
|
82
|
+
|
83
|
+
src.should_not reek_of(:DataClump)
|
84
|
+
end
|
85
|
+
|
86
|
+
# TODO: include singleton methods in the calcs
|
87
|
+
end
|
@@ -39,7 +39,7 @@ describe LargeClass, 'checking Class objects' do
|
|
39
39
|
it 'should not report class with 10 ivars' do
|
40
40
|
pending('test requires ParseTree') unless ObjectSource.can_parse_objects?
|
41
41
|
class ManyIvars
|
42
|
-
def
|
42
|
+
def meth
|
43
43
|
@vara = @varb = @varc = @vard = @vare
|
44
44
|
@varf = @varg = @varh = @vari = @varj
|
45
45
|
end
|
@@ -125,12 +125,12 @@ describe UncommunicativeName, '#examine' do
|
|
125
125
|
end
|
126
126
|
|
127
127
|
it 'should return true when reporting a smell' do
|
128
|
-
mc = MethodContext.new(StopContext.new,
|
128
|
+
mc = MethodContext.new(StopContext.new, s(:defn, :x, s(:args)))
|
129
129
|
@uc.examine(mc).should == true
|
130
130
|
end
|
131
131
|
|
132
132
|
it 'should return false when not reporting a smell' do
|
133
|
-
mc = MethodContext.new(StopContext.new,
|
133
|
+
mc = MethodContext.new(StopContext.new, s(:defn, :not_bad, s(:args)))
|
134
134
|
@uc.examine(mc).should == false
|
135
135
|
end
|
136
136
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kevinrutherford-reek
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.3.
|
4
|
+
version: 1.1.3.15
|
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-
|
12
|
+
date: 2009-09-03 00:00:00 -07:00
|
13
13
|
default_executable: reek
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -93,6 +93,7 @@ files:
|
|
93
93
|
- lib/reek/singleton_method_context.rb
|
94
94
|
- lib/reek/smell_warning.rb
|
95
95
|
- lib/reek/smells/control_couple.rb
|
96
|
+
- lib/reek/smells/data_clump.rb
|
96
97
|
- lib/reek/smells/duplication.rb
|
97
98
|
- lib/reek/smells/feature_envy.rb
|
98
99
|
- lib/reek/smells/large_class.rb
|
@@ -128,6 +129,7 @@ files:
|
|
128
129
|
- spec/reek/singleton_method_context_spec.rb
|
129
130
|
- spec/reek/smell_warning_spec.rb
|
130
131
|
- spec/reek/smells/control_couple_spec.rb
|
132
|
+
- spec/reek/smells/data_clump_spec.rb
|
131
133
|
- spec/reek/smells/duplication_spec.rb
|
132
134
|
- spec/reek/smells/feature_envy_spec.rb
|
133
135
|
- spec/reek/smells/large_class_spec.rb
|
@@ -179,7 +181,6 @@ files:
|
|
179
181
|
- tasks/test.rake
|
180
182
|
has_rdoc: false
|
181
183
|
homepage: http://wiki.github.com/kevinrutherford/reek
|
182
|
-
licenses:
|
183
184
|
post_install_message: |
|
184
185
|
|
185
186
|
For more information on reek, see http://wiki.github.com/kevinrutherford/reek
|
@@ -204,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
204
205
|
requirements: []
|
205
206
|
|
206
207
|
rubyforge_project: reek
|
207
|
-
rubygems_version: 1.
|
208
|
+
rubygems_version: 1.2.0
|
208
209
|
signing_key:
|
209
210
|
specification_version: 3
|
210
211
|
summary: Code smell detector for Ruby
|