kevinrutherford-reek 1.1.3.2 → 1.1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -6
- data/lib/reek/class_context.rb +5 -0
- data/lib/reek/code_parser.rb +10 -16
- data/lib/reek/object_source.rb +1 -1
- data/lib/reek/report.rb +24 -4
- data/lib/reek/smells/control_couple.rb +3 -4
- data/lib/reek/smells/duplication.rb +2 -3
- data/lib/reek/smells/feature_envy.rb +3 -4
- data/lib/reek/smells/large_class.rb +8 -10
- data/lib/reek/smells/long_method.rb +3 -4
- data/lib/reek/smells/long_parameter_list.rb +3 -4
- data/lib/reek/smells/nested_iterators.rb +3 -3
- data/lib/reek/smells/smell_detector.rb +28 -5
- data/lib/reek/smells/uncommunicative_name.rb +8 -10
- data/lib/reek/smells/utility_function.rb +3 -4
- data/lib/reek/{smells/smells.rb → sniffer.rb} +42 -15
- data/lib/reek/source.rb +7 -7
- data/lib/reek.rb +1 -1
- data/reek.gemspec +4 -4
- data/spec/reek/report_spec.rb +1 -4
- data/spec/reek/{smells/smell_spec.rb → smell_warning_spec.rb} +1 -1
- data/spec/reek/smells/duplication_spec.rb +4 -6
- data/spec/reek/smells/feature_envy_spec.rb +2 -18
- data/spec/reek/smells/large_class_spec.rb +9 -18
- data/spec/reek/smells/long_method_spec.rb +1 -1
- data/spec/reek/smells/smell_detector_spec.rb +23 -0
- data/spec/reek/smells/uncommunicative_name_spec.rb +2 -3
- data/spec/reek/smells/utility_function_spec.rb +0 -14
- metadata +5 -4
data/History.txt
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
== 1.1.4 (in git)
|
2
2
|
|
3
3
|
=== Minor Changes
|
4
|
-
* LongMethod now counts statements deeper into each method (#25)
|
4
|
+
* LongMethod now counts statements deeper into each method (fixed #25)
|
5
5
|
* LongMethod no longer counts control structures, only their contained stmts
|
6
|
-
* LargeClass is disabled when checking in-memory classes
|
6
|
+
* LargeClass is disabled when checking in-memory classes (fixed #28)
|
7
|
+
* Output now reports on all files examined, even if they have no smells
|
8
|
+
* Smell warnings are indented in the report to distinguish them from file headers
|
7
9
|
|
8
10
|
== 1.1.3 2009-05-19
|
9
11
|
|
@@ -11,7 +13,7 @@
|
|
11
13
|
* No longer depends directly on the sexp_processor gem
|
12
14
|
|
13
15
|
=== Fixes
|
14
|
-
* LargeClass now relies only on the given source code (#26)
|
16
|
+
* LargeClass now relies only on the given source code (fixed #26)
|
15
17
|
|
16
18
|
== 1.1.2 2009-05-18
|
17
19
|
|
@@ -22,7 +24,7 @@
|
|
22
24
|
== 1.1.1 2009-05-08
|
23
25
|
|
24
26
|
=== Minor enhancements
|
25
|
-
* LargeClass now also warns about any class with > 9 instance variables (#6)
|
27
|
+
* LargeClass now also warns about any class with > 9 instance variables (fixed #6)
|
26
28
|
* Now depends on ruby2ruby, to display code better
|
27
29
|
* Duplication notices more repeated method calls
|
28
30
|
* Smells within blocks are now reported better
|
@@ -30,7 +32,7 @@
|
|
30
32
|
== 1.1.0 2009-04-10
|
31
33
|
|
32
34
|
=== Minor enhancements
|
33
|
-
* Now possible to write 'MyClass.should_not reek' (#33)
|
35
|
+
* Now possible to write 'MyClass.should_not reek' (fixed #33)
|
34
36
|
|
35
37
|
=== Fixes
|
36
38
|
* Now counts attr assignments ([]= etc) in feature envy calculations
|
@@ -39,7 +41,7 @@
|
|
39
41
|
== 1.0.1 2009-04-06
|
40
42
|
|
41
43
|
=== Fixes
|
42
|
-
* Dir[...].to_source now creates a Report that can be browsed (#36)
|
44
|
+
* Dir[...].to_source now creates a Report that can be browsed (fixed #36)
|
43
45
|
|
44
46
|
== 1.0.0 2009-04-05
|
45
47
|
|
data/lib/reek/class_context.rb
CHANGED
@@ -15,6 +15,11 @@ module Reek
|
|
15
15
|
ClassContext.new(res[0], res[1], exp[2])
|
16
16
|
end
|
17
17
|
|
18
|
+
def ClassContext.from_s(src)
|
19
|
+
source = Source.from_s(src)
|
20
|
+
CodeParser.new(Sniffer.new).process_class(source.generate_syntax_tree)
|
21
|
+
end
|
22
|
+
|
18
23
|
def initialize(outer, name, superclass = nil)
|
19
24
|
super(outer, nil)
|
20
25
|
@name = name
|
data/lib/reek/code_parser.rb
CHANGED
@@ -27,11 +27,11 @@ module Reek
|
|
27
27
|
|
28
28
|
class CodeParser
|
29
29
|
|
30
|
-
#
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
@
|
30
|
+
#
|
31
|
+
# Creates a new Ruby code checker.
|
32
|
+
#
|
33
|
+
def initialize(sniffer, ctx = StopContext.new)
|
34
|
+
@sniffer = sniffer
|
35
35
|
@element = ctx
|
36
36
|
end
|
37
37
|
|
@@ -127,9 +127,7 @@ module Reek
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def process_while(exp)
|
130
|
-
|
131
|
-
process_default(exp)
|
132
|
-
@element.count_statements(-1)
|
130
|
+
process_until(exp)
|
133
131
|
end
|
134
132
|
|
135
133
|
def process_until(exp)
|
@@ -140,19 +138,16 @@ module Reek
|
|
140
138
|
|
141
139
|
def process_for(exp)
|
142
140
|
count_clause(exp[3])
|
143
|
-
|
144
|
-
@element.count_statements(-1)
|
141
|
+
process_case(exp)
|
145
142
|
end
|
146
143
|
|
147
144
|
def process_rescue(exp)
|
148
145
|
count_clause(exp[1])
|
149
|
-
|
150
|
-
@element.count_statements(-1)
|
146
|
+
process_case(exp)
|
151
147
|
end
|
152
148
|
|
153
149
|
def process_resbody(exp)
|
154
|
-
|
155
|
-
process_default(exp)
|
150
|
+
process_when(exp)
|
156
151
|
end
|
157
152
|
|
158
153
|
def process_case(exp)
|
@@ -209,8 +204,7 @@ module Reek
|
|
209
204
|
end
|
210
205
|
|
211
206
|
def check_smells(type)
|
212
|
-
|
213
|
-
listeners.each {|smell| smell.examine(@element, @report) } if listeners
|
207
|
+
@sniffer.examine(@element, type)
|
214
208
|
end
|
215
209
|
|
216
210
|
def push(context)
|
data/lib/reek/object_source.rb
CHANGED
data/lib/reek/report.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
require 'set'
|
2
|
+
require 'reek/sniffer'
|
2
3
|
require 'reek/smells/smell_detector'
|
3
4
|
|
4
5
|
module Reek
|
5
6
|
class Report
|
6
7
|
include Enumerable
|
7
8
|
|
8
|
-
def initialize # :nodoc:
|
9
|
+
def initialize(sniffer = nil) # :nodoc:
|
10
|
+
@masked_smells = SortedSet.new
|
9
11
|
@report = SortedSet.new
|
12
|
+
sniffer.report_on(self) if sniffer
|
10
13
|
end
|
11
14
|
|
12
15
|
#
|
@@ -20,6 +23,14 @@ module Reek
|
|
20
23
|
@report << smell
|
21
24
|
true
|
22
25
|
end
|
26
|
+
|
27
|
+
def record_masked_smell(smell)
|
28
|
+
@masked_smells << smell
|
29
|
+
end
|
30
|
+
|
31
|
+
def num_masked_smells
|
32
|
+
@masked_smells.length
|
33
|
+
end
|
23
34
|
|
24
35
|
def empty?
|
25
36
|
@report.empty?
|
@@ -38,13 +49,22 @@ module Reek
|
|
38
49
|
# Creates a formatted report of all the +Smells::SmellWarning+ objects recorded in
|
39
50
|
# this report, with a heading.
|
40
51
|
def full_report(desc)
|
41
|
-
|
52
|
+
result = header(desc, @report.length)
|
53
|
+
result += ":\n#{to_s}\n" if length > 0
|
54
|
+
result
|
55
|
+
end
|
56
|
+
|
57
|
+
def header(desc, num_smells)
|
58
|
+
result = "\"#{desc}\" -- #{num_smells} warning"
|
59
|
+
result += 's' unless num_smells == 1
|
60
|
+
result += " (+#{@masked_smells.length} masked)" unless @masked_smells.empty?
|
61
|
+
result
|
42
62
|
end
|
43
63
|
|
44
64
|
# Creates a formatted report of all the +Smells::SmellWarning+ objects recorded in
|
45
65
|
# this report.
|
46
66
|
def to_s
|
47
|
-
@report.map {|smell| smell.report}.join("\n")
|
67
|
+
@report.map {|smell| " #{smell.report}"}.join("\n")
|
48
68
|
end
|
49
69
|
end
|
50
70
|
|
@@ -75,7 +95,7 @@ module Reek
|
|
75
95
|
end
|
76
96
|
|
77
97
|
def to_s
|
78
|
-
|
98
|
+
@sources.map { |src| src.full_report }.join("\n")
|
79
99
|
end
|
80
100
|
end
|
81
101
|
end
|
@@ -49,12 +49,11 @@ module Reek
|
|
49
49
|
|
50
50
|
#
|
51
51
|
# Checks whether the given conditional statement relies on a control couple.
|
52
|
-
#
|
52
|
+
# Remembers any smells found.
|
53
53
|
#
|
54
|
-
def examine_context(cond
|
54
|
+
def examine_context(cond)
|
55
55
|
return unless cond.tests_a_parameter?
|
56
|
-
|
57
|
-
"is controlled by argument #{SexpFormatter.format(cond.if_expr)}")
|
56
|
+
found(cond, "is controlled by argument #{SexpFormatter.format(cond.if_expr)}")
|
58
57
|
end
|
59
58
|
end
|
60
59
|
end
|
@@ -33,10 +33,9 @@ module Reek
|
|
33
33
|
@max_calls = config[MAX_ALLOWED_CALLS_KEY]
|
34
34
|
end
|
35
35
|
|
36
|
-
def examine_context(method
|
36
|
+
def examine_context(method)
|
37
37
|
smelly_calls(method).each do |call|
|
38
|
-
|
39
|
-
"calls #{SexpFormatter.format(call)} multiple times")
|
38
|
+
found(method, "calls #{SexpFormatter.format(call)} multiple times")
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
@@ -45,12 +45,11 @@ module Reek
|
|
45
45
|
#
|
46
46
|
# Checks whether the given +context+ includes any code fragment that
|
47
47
|
# might "belong" on another class.
|
48
|
-
#
|
48
|
+
# Remembers any smells found.
|
49
49
|
#
|
50
|
-
def examine_context(context
|
50
|
+
def examine_context(context)
|
51
51
|
context.envious_receivers.each do |ref|
|
52
|
-
|
53
|
-
"refers to #{SexpFormatter.format(ref)} more than self")
|
52
|
+
found(context, "refers to #{SexpFormatter.format(ref)} more than self")
|
54
53
|
end
|
55
54
|
end
|
56
55
|
end
|
@@ -42,27 +42,25 @@ module Reek
|
|
42
42
|
@max_instance_variables = config[MAX_ALLOWED_IVARS_KEY]
|
43
43
|
end
|
44
44
|
|
45
|
-
def check_num_methods(klass
|
45
|
+
def check_num_methods(klass) # :nodoc:
|
46
46
|
count = klass.num_methods
|
47
47
|
return if count <= @max_methods
|
48
|
-
|
49
|
-
"has at least #{count} methods")
|
48
|
+
found(klass, "has at least #{count} methods")
|
50
49
|
end
|
51
50
|
|
52
|
-
def check_num_ivars(klass
|
51
|
+
def check_num_ivars(klass) # :nodoc:
|
53
52
|
count = klass.variable_names.length
|
54
53
|
return if count <= @max_instance_variables
|
55
|
-
|
56
|
-
"has at least #{count} instance variables")
|
54
|
+
found(klass, "has at least #{count} instance variables")
|
57
55
|
end
|
58
56
|
|
59
57
|
#
|
60
58
|
# Checks +klass+ for too many methods or too many instance variables.
|
61
|
-
#
|
59
|
+
# Remembers any smells found.
|
62
60
|
#
|
63
|
-
def examine_context(klass
|
64
|
-
check_num_methods(klass
|
65
|
-
check_num_ivars(klass
|
61
|
+
def examine_context(klass)
|
62
|
+
check_num_methods(klass)
|
63
|
+
check_num_ivars(klass)
|
66
64
|
end
|
67
65
|
end
|
68
66
|
end
|
@@ -30,13 +30,12 @@ module Reek
|
|
30
30
|
|
31
31
|
#
|
32
32
|
# Checks the length of the given +method+.
|
33
|
-
#
|
33
|
+
# Remembers any smells found.
|
34
34
|
#
|
35
|
-
def examine_context(method
|
35
|
+
def examine_context(method)
|
36
36
|
num = method.num_statements
|
37
37
|
return false if num <= @max_statements
|
38
|
-
|
39
|
-
"has approx #{num} statements")
|
38
|
+
found(method, "has approx #{num} statements")
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
@@ -30,13 +30,12 @@ module Reek
|
|
30
30
|
|
31
31
|
#
|
32
32
|
# Checks the number of parameters in the given scope.
|
33
|
-
#
|
33
|
+
# Remembers any smells found.
|
34
34
|
#
|
35
|
-
def examine_context(ctx
|
35
|
+
def examine_context(ctx)
|
36
36
|
num_params = ctx.parameters.length
|
37
37
|
return false if num_params <= @max_params
|
38
|
-
|
39
|
-
"#{@action} #{num_params} parameters")
|
38
|
+
found(ctx, "#{@action} #{num_params} parameters")
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
@@ -17,11 +17,11 @@ module Reek
|
|
17
17
|
|
18
18
|
#
|
19
19
|
# Checks whether the given +block+ is inside another.
|
20
|
-
#
|
20
|
+
# Remembers any smells found.
|
21
21
|
#
|
22
|
-
def examine_context(block
|
22
|
+
def examine_context(block)
|
23
23
|
return false unless block.nested_block?
|
24
|
-
|
24
|
+
found(block, 'is nested')
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -37,20 +37,27 @@ module Reek
|
|
37
37
|
def self.listen(hooks, config)
|
38
38
|
detector = new(config[class_name])
|
39
39
|
contexts.each { |ctx| hooks[ctx] << detector }
|
40
|
+
detector
|
40
41
|
end
|
41
42
|
|
42
43
|
def initialize(config)
|
43
44
|
@enabled = config[ENABLED_KEY]
|
44
45
|
@exceptions = config[EXCLUDE_KEY]
|
46
|
+
@smells_found = []
|
47
|
+
@masked = false
|
45
48
|
end
|
46
49
|
|
47
|
-
def
|
48
|
-
|
49
|
-
examine_context(context, report) if @enabled and !exception?(context)
|
50
|
-
report.length > before
|
50
|
+
def be_masked
|
51
|
+
@masked = true
|
51
52
|
end
|
52
53
|
|
53
|
-
def
|
54
|
+
def examine(context)
|
55
|
+
before = @smells_found.size
|
56
|
+
examine_context(context) if @enabled and !exception?(context)
|
57
|
+
@smells_found.length > before
|
58
|
+
end
|
59
|
+
|
60
|
+
def examine_context(context)
|
54
61
|
end
|
55
62
|
|
56
63
|
def exception?(context)
|
@@ -58,6 +65,22 @@ module Reek
|
|
58
65
|
context.matches?(@exceptions)
|
59
66
|
end
|
60
67
|
|
68
|
+
def found(scope, warning)
|
69
|
+
smell = SmellWarning.new(self, scope, warning)
|
70
|
+
@smells_found << smell
|
71
|
+
smell
|
72
|
+
end
|
73
|
+
|
74
|
+
def report_on(report)
|
75
|
+
@smells_found.each do |smell|
|
76
|
+
if @masked
|
77
|
+
report.record_masked_smell(smell)
|
78
|
+
else
|
79
|
+
report << smell
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
61
84
|
def smell_name
|
62
85
|
self.class.name_words.join(' ')
|
63
86
|
end
|
@@ -47,27 +47,25 @@ module Reek
|
|
47
47
|
|
48
48
|
#
|
49
49
|
# Checks the given +context+ for uncommunicative names.
|
50
|
-
#
|
50
|
+
# Remembers any smells found.
|
51
51
|
#
|
52
|
-
def examine_context(context
|
53
|
-
consider_name(context
|
54
|
-
consider_variables(context
|
52
|
+
def examine_context(context)
|
53
|
+
consider_name(context)
|
54
|
+
consider_variables(context)
|
55
55
|
end
|
56
56
|
|
57
|
-
def consider_variables(context
|
57
|
+
def consider_variables(context) # :nodoc:
|
58
58
|
context.variable_names.each do |name|
|
59
59
|
next unless is_bad_name?(name)
|
60
|
-
|
61
|
-
"has the variable name '#{name}'")
|
60
|
+
found(context, "has the variable name '#{name}'")
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
65
|
-
def consider_name(context
|
64
|
+
def consider_name(context) # :nodoc:
|
66
65
|
name = context.name
|
67
66
|
return false if @accept.include?(context.to_s) # TODO: fq_name() ?
|
68
67
|
return false unless is_bad_name?(name)
|
69
|
-
|
70
|
-
"has the name '#{name}'")
|
68
|
+
found(context, "has the name '#{name}'")
|
71
69
|
end
|
72
70
|
|
73
71
|
def is_bad_name?(name) # :nodoc:
|
@@ -20,14 +20,13 @@ module Reek
|
|
20
20
|
|
21
21
|
#
|
22
22
|
# Checks whether the given +method+ is a utility function.
|
23
|
-
#
|
23
|
+
# Remembers any smells found.
|
24
24
|
#
|
25
|
-
def examine_context(method
|
25
|
+
def examine_context(method)
|
26
26
|
return false if method.calls.keys.length == 0 or
|
27
27
|
method.num_statements == 0 or
|
28
28
|
method.depends_on_instance?
|
29
|
-
|
30
|
-
"doesn't depend on instance state")
|
29
|
+
found(method, "doesn't depend on instance state")
|
31
30
|
end
|
32
31
|
end
|
33
32
|
end
|
@@ -37,7 +37,7 @@ class Hash
|
|
37
37
|
end
|
38
38
|
|
39
39
|
module Reek
|
40
|
-
class
|
40
|
+
class Sniffer
|
41
41
|
|
42
42
|
SMELL_CLASSES = [
|
43
43
|
Smells::ControlCouple,
|
@@ -53,22 +53,53 @@ module Reek
|
|
53
53
|
]
|
54
54
|
|
55
55
|
def initialize
|
56
|
-
defaults_file = File.join(File.dirname(__FILE__), '..', '..', '
|
56
|
+
defaults_file = File.join(File.dirname(__FILE__), '..', '..', 'config', 'defaults.reek')
|
57
57
|
@config = YAML.load_file(defaults_file)
|
58
|
+
@detectors = nil
|
59
|
+
@listeners = []
|
58
60
|
end
|
59
61
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
#
|
63
|
+
# Configures this sniffer using any *.reek config files found
|
64
|
+
# on the path to the named file. Config files are applied in order,
|
65
|
+
# "root-first", so that config files closer to the named file override
|
66
|
+
# those further up the path.
|
67
|
+
#
|
68
|
+
def configure_along_path(filename)
|
69
|
+
path = File.expand_path(File.dirname(filename))
|
70
|
+
all_reekfiles(path).each { |rfile| configure_with(rfile) }
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Overrides this sniffer's current settings with those in the named
|
76
|
+
# +config_file+.
|
77
|
+
#
|
78
|
+
def configure_with(config_file)
|
79
|
+
YAML.load_file(config_file).push_keys(@config)
|
80
|
+
end
|
81
|
+
|
82
|
+
def disable(smell)
|
83
|
+
@config[smell].adopt!({Reek::Smells::SmellDetector::ENABLED_KEY => false})
|
84
|
+
end
|
85
|
+
|
86
|
+
def report_on(report)
|
87
|
+
@listeners.each {|smell| smell.report_on(report)}
|
64
88
|
end
|
65
89
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
90
|
+
def examine(scope, type)
|
91
|
+
listeners = smell_listeners[type]
|
92
|
+
listeners.each {|smell| smell.examine(scope) } if listeners
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def smell_listeners()
|
98
|
+
unless @detectors
|
99
|
+
@detectors = Hash.new {|hash,key| hash[key] = [] }
|
100
|
+
SMELL_CLASSES.each { |smell| @listeners << smell.listen(@detectors, @config) }
|
70
101
|
end
|
71
|
-
|
102
|
+
@detectors
|
72
103
|
end
|
73
104
|
|
74
105
|
def all_reekfiles(path)
|
@@ -77,9 +108,5 @@ module Reek
|
|
77
108
|
return [] if path == parent
|
78
109
|
all_reekfiles(parent) + Dir["#{path}/*.reek"]
|
79
110
|
end
|
80
|
-
|
81
|
-
def disable(smell)
|
82
|
-
@config[smell].adopt!({'enabled' => false})
|
83
|
-
end
|
84
111
|
end
|
85
112
|
end
|
data/lib/reek/source.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'reek/code_parser'
|
2
2
|
require 'reek/report'
|
3
|
-
require 'reek/
|
3
|
+
require 'reek/sniffer'
|
4
4
|
require 'ruby_parser'
|
5
5
|
|
6
6
|
module Reek
|
@@ -46,7 +46,8 @@ module Reek
|
|
46
46
|
#
|
47
47
|
def self.from_path(filename)
|
48
48
|
code = IO.readlines(filename).join
|
49
|
-
|
49
|
+
sniffer = Sniffer.new.configure_along_path(filename)
|
50
|
+
return new(code, filename, sniffer)
|
50
51
|
end
|
51
52
|
|
52
53
|
#
|
@@ -58,11 +59,10 @@ module Reek
|
|
58
59
|
SourceList.new(sources)
|
59
60
|
end
|
60
61
|
|
61
|
-
def initialize(code, desc,
|
62
|
+
def initialize(code, desc, sniffer = Sniffer.new) # :nodoc:
|
62
63
|
@source = code
|
63
64
|
@desc = desc
|
64
|
-
@
|
65
|
-
@cf = @cf.load_local(dir) if dir
|
65
|
+
@sniffer = sniffer
|
66
66
|
end
|
67
67
|
|
68
68
|
def generate_syntax_tree
|
@@ -76,9 +76,9 @@ module Reek
|
|
76
76
|
#
|
77
77
|
def report
|
78
78
|
unless @report
|
79
|
-
|
80
|
-
parser = CodeParser.new(@report, @cf.smell_listeners)
|
79
|
+
parser = CodeParser.new(@sniffer)
|
81
80
|
parser.process(generate_syntax_tree)
|
81
|
+
@report = Report.new(@sniffer)
|
82
82
|
end
|
83
83
|
@report
|
84
84
|
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.3"
|
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-06-
|
9
|
+
s.date = %q{2009-06-17}
|
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", "README.txt"]
|
15
|
-
s.files = ["History.txt", "README.txt", "Rakefile", "bin/reek", "config/defaults.reek", "lib/reek.rb", "lib/reek/block_context.rb", "lib/reek/class_context.rb", "lib/reek/code_context.rb", "lib/reek/code_parser.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/object_source.rb", "lib/reek/options.rb", "lib/reek/rake_task.rb", "lib/reek/report.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/smell_detector.rb", "lib/reek/smells/
|
15
|
+
s.files = ["History.txt", "README.txt", "Rakefile", "bin/reek", "config/defaults.reek", "lib/reek.rb", "lib/reek/block_context.rb", "lib/reek/class_context.rb", "lib/reek/code_context.rb", "lib/reek/code_parser.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/object_source.rb", "lib/reek/options.rb", "lib/reek/rake_task.rb", "lib/reek/report.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/smell_detector.rb", "lib/reek/smells/uncommunicative_name.rb", "lib/reek/smells/utility_function.rb", "lib/reek/sniffer.rb", "lib/reek/source.rb", "lib/reek/spec.rb", "lib/reek/stop_context.rb", "lib/reek/yield_call_context.rb", "reek.gemspec", "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/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/options_spec.rb", "spec/reek/report_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/smell_detector_spec.rb", "spec/reek/smells/uncommunicative_name_spec.rb", "spec/reek/smells/utility_function_spec.rb", "spec/slow/inline_spec.rb", "spec/slow/optparse_spec.rb", "spec/slow/redcloth_spec.rb", "spec/slow/reek_source_spec.rb", "spec/slow/samples/inline.rb", "spec/slow/samples/optparse.rb", "spec/slow/samples/redcloth.rb", "spec/slow/script_spec.rb", "spec/slow/source_list_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/reek.rake", "tasks/rspec.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
|
@@ -20,7 +20,7 @@ For more information on reek, see http://wiki.github.com/kevinrutherford/reek
|
|
20
20
|
s.rdoc_options = ["--main", "README.txt"]
|
21
21
|
s.require_paths = ["lib"]
|
22
22
|
s.rubyforge_project = %q{reek}
|
23
|
-
s.rubygems_version = %q{1.3.
|
23
|
+
s.rubygems_version = %q{1.3.4}
|
24
24
|
s.summary = %q{Code smell detector for Ruby}
|
25
25
|
|
26
26
|
if s.respond_to? :specification_version then
|
data/spec/reek/report_spec.rb
CHANGED
@@ -27,11 +27,8 @@ describe Report, "to_s" do
|
|
27
27
|
@report = rpt.to_s.split("\n")
|
28
28
|
end
|
29
29
|
|
30
|
-
it 'should place each detailed report on a separate line' do
|
31
|
-
@report.should have_at_least(2).lines
|
32
|
-
end
|
33
|
-
|
34
30
|
it 'should mention every smell name' do
|
31
|
+
@report.should have_at_least(2).lines
|
35
32
|
@report[0].should match(/[Utility Function]/)
|
36
33
|
@report[1].should match(/[Feature Envy]/)
|
37
34
|
end
|
@@ -51,17 +51,17 @@ describe Duplication, '#examine' do
|
|
51
51
|
|
52
52
|
it 'should return true when reporting a smell' do
|
53
53
|
@mc.calls = {s(:call, nil, :other, s(:arglist)) => 47}
|
54
|
-
@dup.examine(@mc
|
54
|
+
@dup.examine(@mc).should == true
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'should return false when not reporting a smell' do
|
58
58
|
@mc.calls = []
|
59
|
-
@dup.examine(@mc
|
59
|
+
@dup.examine(@mc).should == false
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'should return false when not reporting calls to new' do
|
63
63
|
@mc.calls = {[:call, :Set, :new] => 4}
|
64
|
-
@dup.examine(@mc
|
64
|
+
@dup.examine(@mc).should == false
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -69,13 +69,11 @@ describe Duplication, 'when disabled' do
|
|
69
69
|
before :each do
|
70
70
|
@ctx = MethodContext.new(StopContext.new, [0, :double_thing])
|
71
71
|
@dup = Duplication.new({SmellDetector::ENABLED_KEY => false})
|
72
|
-
@rpt = Report.new
|
73
72
|
end
|
74
73
|
|
75
74
|
it 'should not report repeated call' do
|
76
75
|
@ctx.record_call_to([:fred])
|
77
76
|
@ctx.record_call_to([:fred])
|
78
|
-
@dup.examine(@ctx
|
79
|
-
@rpt.length.should == 0
|
77
|
+
@dup.examine(@ctx).should == false
|
80
78
|
end
|
81
79
|
end
|
@@ -133,22 +133,6 @@ describe FeatureEnvy do
|
|
133
133
|
end'.should_not reek
|
134
134
|
end
|
135
135
|
|
136
|
-
it 'reports the most-used ivar' do
|
137
|
-
pending('bug')
|
138
|
-
'def func
|
139
|
-
@other.a
|
140
|
-
@other.b
|
141
|
-
@nother.c
|
142
|
-
end'.should reek_of(:FeatureEnvy, /@other/)
|
143
|
-
#
|
144
|
-
# def other.func(me)
|
145
|
-
# a
|
146
|
-
# b
|
147
|
-
# me.nother_c
|
148
|
-
# end
|
149
|
-
#
|
150
|
-
end
|
151
|
-
|
152
136
|
it 'ignores multiple ivars' do
|
153
137
|
'def func
|
154
138
|
@other.a
|
@@ -212,10 +196,10 @@ describe FeatureEnvy, '#examine' do
|
|
212
196
|
it 'should return true when reporting a smell' do
|
213
197
|
@context.refs.record_ref([:lvar, :thing])
|
214
198
|
@context.refs.record_ref([:lvar, :thing])
|
215
|
-
@fe.examine(@context
|
199
|
+
@fe.examine(@context).should == true
|
216
200
|
end
|
217
201
|
|
218
202
|
it 'should return false when not reporting a smell' do
|
219
|
-
@fe.examine(@context
|
203
|
+
@fe.examine(@context).should == false
|
220
204
|
end
|
221
205
|
end
|
@@ -55,7 +55,6 @@ end
|
|
55
55
|
describe LargeClass, 'when exceptions are listed' do
|
56
56
|
|
57
57
|
before(:each) do
|
58
|
-
@rpt = Report.new
|
59
58
|
@ctx = ClassContext.create(StopContext.new, [0, :Humungous])
|
60
59
|
30.times { |num| @ctx.record_method("method#{num}") }
|
61
60
|
@config = LargeClass.default_config
|
@@ -64,43 +63,35 @@ describe LargeClass, 'when exceptions are listed' do
|
|
64
63
|
it 'should ignore first excepted name' do
|
65
64
|
@config[LargeClass::EXCLUDE_KEY] = ['Humungous']
|
66
65
|
lc = LargeClass.new(@config)
|
67
|
-
lc.examine(@ctx
|
68
|
-
@rpt.length.should == 0
|
66
|
+
lc.examine(@ctx).should == false
|
69
67
|
end
|
70
68
|
|
71
69
|
it 'should ignore second excepted name' do
|
72
70
|
@config[LargeClass::EXCLUDE_KEY] = ['Oversized', 'Humungous']
|
73
71
|
lc = LargeClass.new(@config)
|
74
|
-
lc.examine(@ctx
|
75
|
-
@rpt.length.should == 0
|
72
|
+
lc.examine(@ctx).should == false
|
76
73
|
end
|
77
74
|
|
78
75
|
it 'should report non-excepted name' do
|
79
76
|
@config[LargeClass::EXCLUDE_KEY] = ['SmellMe']
|
80
77
|
lc = LargeClass.new(@config)
|
81
|
-
lc.examine(@ctx
|
82
|
-
@rpt.length.should == 1
|
78
|
+
lc.examine(@ctx).should == true
|
83
79
|
end
|
84
80
|
end
|
85
81
|
|
86
82
|
describe LargeClass, 'checking source code' do
|
87
83
|
|
88
|
-
def process_class(src)
|
89
|
-
source = Source.from_s(src)
|
90
|
-
CodeParser.new(nil, {}).process_class(source.generate_syntax_tree)
|
91
|
-
end
|
92
|
-
|
93
84
|
describe 'counting instance variables' do
|
94
85
|
it 'should not report empty class' do
|
95
|
-
|
86
|
+
ClassContext.from_s('class Empty;end').should have(0).variable_names
|
96
87
|
end
|
97
88
|
|
98
89
|
it 'should count ivars in one method' do
|
99
|
-
|
90
|
+
ClassContext.from_s('class Empty;def ivars() @aa=@ab=@ac=@ad; end;end').should have(4).variable_names
|
100
91
|
end
|
101
92
|
|
102
93
|
it 'should count ivars in 2 methods' do
|
103
|
-
|
94
|
+
ClassContext.from_s('class Empty;def iv1() @aa=@ab; end;def iv2() @aa=@ac; end;end').should have(3).variable_names
|
104
95
|
end
|
105
96
|
|
106
97
|
it 'should not report 9 ivars' do
|
@@ -122,15 +113,15 @@ EOS
|
|
122
113
|
|
123
114
|
describe 'counting methods' do
|
124
115
|
it 'should not report empty class' do
|
125
|
-
|
116
|
+
ClassContext.from_s('class Empty;end').num_methods.should == 0
|
126
117
|
end
|
127
118
|
|
128
119
|
it 'should count 1 method' do
|
129
|
-
|
120
|
+
ClassContext.from_s('class Empty;def ivars() @aa=@ab; end;end').num_methods.should == 1
|
130
121
|
end
|
131
122
|
|
132
123
|
it 'should count 2 methods' do
|
133
|
-
|
124
|
+
ClassContext.from_s('class Empty;def meth1() @aa=@ab;end;def meth2() @aa=@ab;end;end').num_methods.should == 2
|
134
125
|
end
|
135
126
|
|
136
127
|
it 'should not report 25 methods' do
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'reek/report'
|
4
|
+
require 'reek/smells/duplication'
|
5
|
+
|
6
|
+
include Reek
|
7
|
+
include Reek::Smells
|
8
|
+
|
9
|
+
describe SmellDetector, 'when masked' do
|
10
|
+
before(:each) do
|
11
|
+
@detector = Duplication.new
|
12
|
+
@detector.be_masked
|
13
|
+
@detector.found(nil, 'help')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'reports smells as masked' do
|
17
|
+
rpt = Report.new
|
18
|
+
@detector.report_on(rpt)
|
19
|
+
rpt.length.should == 0
|
20
|
+
rpt.num_masked_smells.should == 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -107,17 +107,16 @@ end
|
|
107
107
|
|
108
108
|
describe UncommunicativeName, '#examine' do
|
109
109
|
before :each do
|
110
|
-
@report = Report.new
|
111
110
|
@uc = UncommunicativeName.new
|
112
111
|
end
|
113
112
|
|
114
113
|
it 'should return true when reporting a smell' do
|
115
114
|
mc = MethodContext.new(StopContext.new, [:defn, :x, nil])
|
116
|
-
@uc.examine(mc
|
115
|
+
@uc.examine(mc).should == true
|
117
116
|
end
|
118
117
|
|
119
118
|
it 'should return false when not reporting a smell' do
|
120
119
|
mc = MethodContext.new(StopContext.new, [:defn, :not_bad, nil])
|
121
|
-
@uc.examine(mc
|
120
|
+
@uc.examine(mc).should == false
|
122
121
|
end
|
123
122
|
end
|
@@ -39,20 +39,6 @@ describe UtilityFunction do
|
|
39
39
|
end
|
40
40
|
Son.should_not reek
|
41
41
|
end
|
42
|
-
|
43
|
-
it 'should not report class method' do
|
44
|
-
pending('bug')
|
45
|
-
source = <<EOS
|
46
|
-
class Cache
|
47
|
-
class << self
|
48
|
-
def create_unless_known(attributes)
|
49
|
-
Cache.create(attributes) unless Cache.known?
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
EOS
|
54
|
-
source.should_not reek
|
55
|
-
end
|
56
42
|
|
57
43
|
it 'should recognise a deep call' do
|
58
44
|
src = <<EOS
|
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.3
|
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-06-
|
12
|
+
date: 2009-06-17 00:00:00 -07:00
|
13
13
|
default_executable: reek
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -85,9 +85,9 @@ files:
|
|
85
85
|
- lib/reek/smells/long_yield_list.rb
|
86
86
|
- lib/reek/smells/nested_iterators.rb
|
87
87
|
- lib/reek/smells/smell_detector.rb
|
88
|
-
- lib/reek/smells/smells.rb
|
89
88
|
- lib/reek/smells/uncommunicative_name.rb
|
90
89
|
- lib/reek/smells/utility_function.rb
|
90
|
+
- lib/reek/sniffer.rb
|
91
91
|
- lib/reek/source.rb
|
92
92
|
- lib/reek/spec.rb
|
93
93
|
- lib/reek/stop_context.rb
|
@@ -106,6 +106,7 @@ files:
|
|
106
106
|
- spec/reek/options_spec.rb
|
107
107
|
- spec/reek/report_spec.rb
|
108
108
|
- spec/reek/singleton_method_context_spec.rb
|
109
|
+
- spec/reek/smell_warning_spec.rb
|
109
110
|
- spec/reek/smells/control_couple_spec.rb
|
110
111
|
- spec/reek/smells/duplication_spec.rb
|
111
112
|
- spec/reek/smells/feature_envy_spec.rb
|
@@ -113,7 +114,7 @@ files:
|
|
113
114
|
- spec/reek/smells/long_method_spec.rb
|
114
115
|
- spec/reek/smells/long_parameter_list_spec.rb
|
115
116
|
- spec/reek/smells/nested_iterators_spec.rb
|
116
|
-
- spec/reek/smells/
|
117
|
+
- spec/reek/smells/smell_detector_spec.rb
|
117
118
|
- spec/reek/smells/uncommunicative_name_spec.rb
|
118
119
|
- spec/reek/smells/utility_function_spec.rb
|
119
120
|
- spec/slow/inline_spec.rb
|