reek 1.2.7.3 → 1.2.8
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +17 -0
- data/README.md +32 -48
- data/config/defaults.reek +7 -1
- data/features/api.feature +20 -0
- data/features/masking_smells.feature +41 -0
- data/features/options.feature +4 -0
- data/features/rake_task.feature +14 -0
- data/features/yaml.feature +8 -8
- data/lib/reek.rb +1 -1
- data/lib/reek/cli/command_line.rb +9 -2
- data/lib/reek/cli/reek_command.rb +5 -4
- data/lib/reek/cli/yaml_command.rb +2 -2
- data/lib/reek/core/code_context.rb +10 -1
- data/lib/reek/core/method_context.rb +2 -2
- data/lib/reek/core/sniffer.rb +3 -1
- data/lib/reek/core/stop_context.rb +4 -0
- data/lib/reek/examiner.rb +2 -2
- data/lib/reek/rake/task.rb +16 -0
- data/lib/reek/smell_warning.rb +3 -2
- data/lib/reek/smells/attribute.rb +13 -9
- data/lib/reek/smells/boolean_parameter.rb +14 -9
- data/lib/reek/smells/class_variable.rb +16 -5
- data/lib/reek/smells/control_couple.rb +11 -6
- data/lib/reek/smells/data_clump.rb +33 -30
- data/lib/reek/smells/duplication.rb +39 -8
- data/lib/reek/smells/feature_envy.rb +7 -8
- data/lib/reek/smells/irresponsible_module.rb +12 -3
- data/lib/reek/smells/large_class.rb +31 -15
- data/lib/reek/smells/long_method.rb +15 -5
- data/lib/reek/smells/long_parameter_list.rb +14 -7
- data/lib/reek/smells/long_yield_list.rb +12 -9
- data/lib/reek/smells/nested_iterators.rb +46 -11
- data/lib/reek/smells/simulated_polymorphism.rb +16 -8
- data/lib/reek/smells/smell_detector.rb +13 -13
- data/lib/reek/smells/uncommunicative_method_name.rb +12 -20
- data/lib/reek/smells/uncommunicative_module_name.rb +17 -19
- data/lib/reek/smells/uncommunicative_parameter_name.rb +22 -15
- data/lib/reek/smells/uncommunicative_variable_name.rb +24 -18
- data/lib/reek/smells/utility_function.rb +6 -6
- data/lib/reek/source/code_comment.rb +19 -1
- data/lib/reek/source/tree_dresser.rb +40 -22
- data/reek.gemspec +6 -4
- data/spec/matchers/smell_of_matcher.rb +58 -0
- data/spec/reek/core/code_context_spec.rb +4 -2
- data/spec/reek/core/code_parser_spec.rb +2 -1
- data/spec/reek/core/method_context_spec.rb +5 -5
- data/spec/reek/smells/attribute_spec.rb +2 -4
- data/spec/reek/smells/boolean_parameter_spec.rb +32 -42
- data/spec/reek/smells/class_variable_spec.rb +22 -6
- data/spec/reek/smells/control_couple_spec.rb +15 -14
- data/spec/reek/smells/data_clump_spec.rb +29 -111
- data/spec/reek/smells/duplication_spec.rb +79 -49
- data/spec/reek/smells/feature_envy_spec.rb +1 -2
- data/spec/reek/smells/irresponsible_module_spec.rb +43 -22
- data/spec/reek/smells/large_class_spec.rb +34 -59
- data/spec/reek/smells/long_method_spec.rb +15 -10
- data/spec/reek/smells/long_parameter_list_spec.rb +24 -24
- data/spec/reek/smells/long_yield_list_spec.rb +13 -14
- data/spec/reek/smells/nested_iterators_spec.rb +93 -76
- data/spec/reek/smells/smell_detector_shared.rb +4 -2
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +10 -27
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +22 -23
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +36 -26
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +45 -48
- data/spec/reek/smells/utility_function_spec.rb +14 -13
- data/spec/reek/source/code_comment_spec.rb +61 -3
- data/spec/reek/source/tree_dresser_spec.rb +96 -1
- data/spec/samples/config/allow_duplication.reek +3 -0
- data/spec/samples/config/deeper_nested_iterators.reek +3 -0
- data/spec/samples/demo/demo.rb +8 -0
- data/spec/samples/inline_config/dirty.rb +16 -0
- data/spec/samples/inline_config/masked.reek +7 -0
- data/spec/samples/mask_some/dirty.rb +8 -0
- data/spec/samples/mask_some/some.reek +8 -0
- data/spec/spec_helper.rb +2 -0
- metadata +15 -5
@@ -19,12 +19,16 @@ module Reek
|
|
19
19
|
#
|
20
20
|
class UncommunicativeParameterName < SmellDetector
|
21
21
|
|
22
|
+
SMELL_CLASS = 'UncommunicativeName'
|
23
|
+
SMELL_SUBCLASS = self.name.split(/::/)[-1]
|
24
|
+
PARAMETER_NAME_KEY = 'parameter_name'
|
25
|
+
|
22
26
|
# The name of the config field that lists the regexps of
|
23
27
|
# smelly names to be reported.
|
24
28
|
REJECT_KEY = 'reject'
|
25
29
|
|
26
30
|
DEFAULT_REJECT_SET = [/^.$/, /[0-9]$/, /[A-Z]/]
|
27
|
-
|
31
|
+
|
28
32
|
# The name of the config field that lists the specific names that are
|
29
33
|
# to be treated as exceptions; these names will not be reported as
|
30
34
|
# uncommunicative.
|
@@ -34,8 +38,8 @@ module Reek
|
|
34
38
|
|
35
39
|
def self.default_config
|
36
40
|
super.adopt(
|
37
|
-
|
38
|
-
|
41
|
+
REJECT_KEY => DEFAULT_REJECT_SET,
|
42
|
+
ACCEPT_KEY => DEFAULT_ACCEPT_SET
|
39
43
|
)
|
40
44
|
end
|
41
45
|
|
@@ -49,23 +53,26 @@ module Reek
|
|
49
53
|
|
50
54
|
#
|
51
55
|
# Checks the given +context+ for uncommunicative names.
|
52
|
-
# Remembers any smells found.
|
53
56
|
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
57
|
+
# @return [Array<SmellWarning>]
|
58
|
+
#
|
59
|
+
def examine_context(ctx)
|
60
|
+
@reject_names = value(REJECT_KEY, ctx, DEFAULT_REJECT_SET)
|
61
|
+
@accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
|
62
|
+
ctx.exp.parameter_names.select do |name|
|
63
|
+
is_bad_name?(name, ctx)
|
64
|
+
end.map do |name|
|
65
|
+
smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
|
66
|
+
"has the parameter name '#{name}'",
|
67
|
+
@source, SMELL_SUBCLASS, {PARAMETER_NAME_KEY => name.to_s})
|
68
|
+
smell
|
62
69
|
end
|
63
70
|
end
|
64
71
|
|
65
|
-
def is_bad_name?(name,
|
72
|
+
def is_bad_name?(name, ctx)
|
66
73
|
var = name.to_s.gsub(/^[@\*\&]*/, '')
|
67
|
-
return false if var == '*' or
|
68
|
-
|
74
|
+
return false if var == '*' or @accept_names.include?(var)
|
75
|
+
@reject_names.detect {|patt| patt === var}
|
69
76
|
end
|
70
77
|
end
|
71
78
|
end
|
@@ -19,12 +19,16 @@ module Reek
|
|
19
19
|
#
|
20
20
|
class UncommunicativeVariableName < SmellDetector
|
21
21
|
|
22
|
+
SMELL_CLASS = 'UncommunicativeName'
|
23
|
+
SMELL_SUBCLASS = self.name.split(/::/)[-1]
|
24
|
+
VARIABLE_NAME_KEY = 'variable_name'
|
25
|
+
|
22
26
|
# The name of the config field that lists the regexps of
|
23
27
|
# smelly names to be reported.
|
24
28
|
REJECT_KEY = 'reject'
|
25
29
|
|
26
30
|
DEFAULT_REJECT_SET = [/^.$/, /[0-9]$/, /[A-Z]/]
|
27
|
-
|
31
|
+
|
28
32
|
# The name of the config field that lists the specific names that are
|
29
33
|
# to be treated as exceptions; these names will not be reported as
|
30
34
|
# uncommunicative.
|
@@ -34,8 +38,8 @@ module Reek
|
|
34
38
|
|
35
39
|
def self.default_config
|
36
40
|
super.adopt(
|
37
|
-
|
38
|
-
|
41
|
+
REJECT_KEY => DEFAULT_REJECT_SET,
|
42
|
+
ACCEPT_KEY => DEFAULT_ACCEPT_SET
|
39
43
|
)
|
40
44
|
end
|
41
45
|
|
@@ -49,32 +53,34 @@ module Reek
|
|
49
53
|
|
50
54
|
#
|
51
55
|
# Checks the given +context+ for uncommunicative names.
|
52
|
-
# Remembers any smells found.
|
53
56
|
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
57
|
+
# @return [Array<SmellWarning>]
|
58
|
+
#
|
59
|
+
def examine_context(ctx)
|
60
|
+
@reject_names = value(REJECT_KEY, ctx, DEFAULT_REJECT_SET)
|
61
|
+
@accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
|
62
|
+
variable_names(ctx.exp).select do |name, lines|
|
63
|
+
is_bad_name?(name, ctx)
|
64
|
+
end.map do |name, lines|
|
65
|
+
SmellWarning.new(SMELL_CLASS, ctx.full_name, lines,
|
66
|
+
"has the variable name '#{name}'",
|
67
|
+
@source, SMELL_SUBCLASS, {VARIABLE_NAME_KEY => name.to_s})
|
62
68
|
end
|
63
69
|
end
|
64
70
|
|
65
|
-
def is_bad_name?(name,
|
71
|
+
def is_bad_name?(name, ctx)
|
66
72
|
var = name.to_s.gsub(/^[@\*\&]*/, '')
|
67
|
-
return false if
|
68
|
-
|
73
|
+
return false if @accept_names.include?(var)
|
74
|
+
@reject_names.detect {|patt| patt === var}
|
69
75
|
end
|
70
76
|
|
71
77
|
def variable_names(exp)
|
72
78
|
assignment_nodes = exp.each_node(:lasgn, [:class, :module, :defs, :defn])
|
73
79
|
case exp.first
|
74
|
-
|
75
|
-
|
80
|
+
when :class, :module
|
81
|
+
assignment_nodes += exp.each_node(:iasgn, [:class, :module])
|
76
82
|
end
|
77
|
-
result = Hash.new {|hash,key| hash[key] = []}
|
83
|
+
result = Hash.new {|hash, key| hash[key] = []}
|
78
84
|
assignment_nodes.each {|asgn| result[asgn[1]].push(asgn.line) }
|
79
85
|
result
|
80
86
|
end
|
@@ -61,18 +61,18 @@ module Reek
|
|
61
61
|
|
62
62
|
#
|
63
63
|
# Checks whether the given +method+ is a utility function.
|
64
|
-
#
|
64
|
+
#
|
65
|
+
# @return [Array<SmellWarning>]
|
65
66
|
#
|
66
67
|
def examine_context(method_ctx)
|
67
|
-
return
|
68
|
-
return
|
69
|
-
return
|
68
|
+
return [] if method_ctx.num_statements == 0
|
69
|
+
return [] if depends_on_instance?(method_ctx.exp)
|
70
|
+
return [] if num_helper_methods(method_ctx) <= value(HELPER_CALLS_LIMIT_KEY, method_ctx, DEFAULT_HELPER_CALLS_LIMIT)
|
70
71
|
# SMELL: loads of calls to value{} with the above pattern
|
71
72
|
smell = SmellWarning.new(SMELL_CLASS, method_ctx.full_name, [method_ctx.exp.line],
|
72
73
|
"doesn't depend on instance state",
|
73
74
|
@source, SMELL_SUBCLASS)
|
74
|
-
|
75
|
-
#SMELL: serious duplication
|
75
|
+
[smell]
|
76
76
|
end
|
77
77
|
|
78
78
|
private
|
@@ -7,13 +7,31 @@ module Reek
|
|
7
7
|
# module, class and method definitions.
|
8
8
|
#
|
9
9
|
class CodeComment
|
10
|
+
CONFIG_REGEX = /:reek:(\w+)(:\s*\{.*?\})?/
|
10
11
|
|
11
12
|
def initialize(text)
|
12
|
-
@
|
13
|
+
@config = Hash.new { |hash,key| hash[key] = {} }
|
14
|
+
@text = text.gsub(CONFIG_REGEX) do |m|
|
15
|
+
add_to_config($1, $2)
|
16
|
+
''
|
17
|
+
end.gsub(/#/, '').gsub(/\n/, '').strip
|
13
18
|
end
|
19
|
+
|
20
|
+
def config
|
21
|
+
@config
|
22
|
+
end
|
23
|
+
|
14
24
|
def is_descriptive?
|
15
25
|
@text.split(/\s+/).length >= 2
|
16
26
|
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
def add_to_config(smell, options)
|
30
|
+
options ||= ': { enabled: false }'
|
31
|
+
@config.merge! YAML.load(smell.gsub(/(?:^|_)(.)/) { $1.upcase } + options)
|
32
|
+
# extend this to all configs --------------------------^
|
33
|
+
# extend to allow configuration of whole smell class, not just subclass
|
34
|
+
end
|
17
35
|
end
|
18
36
|
end
|
19
37
|
end
|
@@ -6,6 +6,17 @@ module Reek
|
|
6
6
|
# syntax tree more easily.
|
7
7
|
#
|
8
8
|
module SexpNode
|
9
|
+
def self.format(expr)
|
10
|
+
case expr
|
11
|
+
when Sexp then expr.format_ruby
|
12
|
+
else expr.to_s
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def hash
|
17
|
+
self.inspect.hash
|
18
|
+
end
|
19
|
+
|
9
20
|
def is_language_node?
|
10
21
|
first.class == Symbol
|
11
22
|
end
|
@@ -37,7 +48,7 @@ module Reek
|
|
37
48
|
end
|
38
49
|
blk.call(self) if first == target_type
|
39
50
|
end
|
40
|
-
def
|
51
|
+
def format_ruby
|
41
52
|
return self[0].to_s unless Array === self
|
42
53
|
Ruby2Ruby.new.process(deep_copy)
|
43
54
|
end
|
@@ -64,15 +75,6 @@ module Reek
|
|
64
75
|
end
|
65
76
|
end
|
66
77
|
|
67
|
-
module ClassNode
|
68
|
-
def name() self[1] end
|
69
|
-
def superclass() self[2] end
|
70
|
-
def full_name(outer)
|
71
|
-
prefix = outer == '' ? '' : "#{outer}::"
|
72
|
-
"#{prefix}#{name}"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
78
|
module CvarNode
|
77
79
|
def name() self[1] end
|
78
80
|
end
|
@@ -80,24 +82,29 @@ module Reek
|
|
80
82
|
CvasgnNode = CvarNode
|
81
83
|
CvdeclNode = CvarNode
|
82
84
|
|
83
|
-
module
|
84
|
-
def name() self[1] end
|
85
|
+
module MethodNode
|
85
86
|
def arg_names
|
86
87
|
unless @args
|
87
|
-
@args =
|
88
|
+
@args = argslist[1..-1].reject {|param| Sexp === param or param.to_s =~ /^&/}
|
88
89
|
end
|
89
90
|
@args
|
90
91
|
end
|
91
92
|
def parameters()
|
92
93
|
unless @params
|
93
|
-
@params =
|
94
|
+
@params = argslist.reject {|param| Sexp === param}
|
94
95
|
end
|
95
96
|
@params
|
96
97
|
end
|
97
98
|
def parameter_names
|
98
99
|
parameters[1..-1]
|
99
100
|
end
|
101
|
+
end
|
102
|
+
|
103
|
+
module DefnNode
|
104
|
+
def name() self[1] end
|
105
|
+
def argslist() self[2] end
|
100
106
|
def body() self[3] end
|
107
|
+
include MethodNode
|
101
108
|
def full_name(outer)
|
102
109
|
prefix = outer == '' ? '' : "#{outer}#"
|
103
110
|
"#{prefix}#{name}"
|
@@ -107,16 +114,12 @@ module Reek
|
|
107
114
|
module DefsNode
|
108
115
|
def receiver() self[1] end
|
109
116
|
def name() self[2] end
|
110
|
-
def
|
111
|
-
self[3].reject {|param| Sexp === param}
|
112
|
-
end
|
113
|
-
def parameter_names
|
114
|
-
parameters[1..-1]
|
115
|
-
end
|
117
|
+
def argslist() self[3] end
|
116
118
|
def body() self[4] end
|
119
|
+
include MethodNode
|
117
120
|
def full_name(outer)
|
118
121
|
prefix = outer == '' ? '' : "#{outer}#"
|
119
|
-
"#{prefix}#{
|
122
|
+
"#{prefix}#{SexpNode.format(receiver)}.#{name}"
|
120
123
|
end
|
121
124
|
end
|
122
125
|
|
@@ -148,12 +151,27 @@ module Reek
|
|
148
151
|
|
149
152
|
module ModuleNode
|
150
153
|
def name() self[1] end
|
154
|
+
def simple_name
|
155
|
+
expr = name
|
156
|
+
while Sexp === expr and expr[0] == :colon2
|
157
|
+
expr = expr[2]
|
158
|
+
end
|
159
|
+
expr
|
160
|
+
end
|
151
161
|
def full_name(outer)
|
152
162
|
prefix = outer == '' ? '' : "#{outer}::"
|
153
|
-
"#{prefix}#{
|
163
|
+
"#{prefix}#{text_name}"
|
164
|
+
end
|
165
|
+
def text_name
|
166
|
+
SexpNode.format(name)
|
154
167
|
end
|
155
168
|
end
|
156
169
|
|
170
|
+
module ClassNode
|
171
|
+
include ModuleNode
|
172
|
+
def superclass() self[2] end
|
173
|
+
end
|
174
|
+
|
157
175
|
module YieldNode
|
158
176
|
def args() self[1..-1] end
|
159
177
|
def arg_names
|
data/reek.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
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.8"
|
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{2010-
|
9
|
+
s.date = %q{2010-04-26}
|
10
10
|
s.default_executable = %q{reek}
|
11
11
|
s.description = %q{Reek is a tool that examines Ruby classes, modules and methods
|
12
12
|
and reports any code smells it finds.
|
@@ -14,10 +14,12 @@ and reports any code smells it finds.
|
|
14
14
|
s.email = ["kevin@rutherford-software.com"]
|
15
15
|
s.executables = ["reek"]
|
16
16
|
s.extra_rdoc_files = ["History.txt", "License.txt"]
|
17
|
-
s.files = [".yardopts", "History.txt", "License.txt", "README.md", "Rakefile", "bin/reek", "config/defaults.reek", "features/masking_smells.feature", "features/options.feature", "features/rake_task.feature", "features/reports.feature", "features/samples.feature", "features/stdin.feature", "features/step_definitions/reek_steps.rb", "features/support/env.rb", "features/yaml.feature", "lib/reek.rb", "lib/reek/cli/application.rb", "lib/reek/cli/command_line.rb", "lib/reek/cli/help_command.rb", "lib/reek/cli/reek_command.rb", "lib/reek/cli/report.rb", "lib/reek/cli/version_command.rb", "lib/reek/cli/yaml_command.rb", "lib/reek/core/code_context.rb", "lib/reek/core/code_parser.rb", "lib/reek/core/method_context.rb", "lib/reek/core/module_context.rb", "lib/reek/core/object_refs.rb", "lib/reek/core/singleton_method_context.rb", "lib/reek/core/smell_configuration.rb", "lib/reek/core/sniffer.rb", "lib/reek/core/stop_context.rb", "lib/reek/core/warning_collector.rb", "lib/reek/examiner.rb", "lib/reek/rake/task.rb", "lib/reek/smell_warning.rb", "lib/reek/smells.rb", "lib/reek/smells/attribute.rb", "lib/reek/smells/boolean_parameter.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/irresponsible_module.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_method_name.rb", "lib/reek/smells/uncommunicative_module_name.rb", "lib/reek/smells/uncommunicative_parameter_name.rb", "lib/reek/smells/uncommunicative_variable_name.rb", "lib/reek/smells/utility_function.rb", "lib/reek/source.rb", "lib/reek/source/code_comment.rb", "lib/reek/source/config_file.rb", "lib/reek/source/core_extras.rb", "lib/reek/source/reference_collector.rb", "lib/reek/source/sexp_formatter.rb", "lib/reek/source/source_code.rb", "lib/reek/source/source_file.rb", "lib/reek/source/source_locator.rb", "lib/reek/source/tree_dresser.rb", "lib/reek/spec.rb", "lib/reek/spec/should_reek.rb", "lib/reek/spec/should_reek_of.rb", "lib/reek/spec/should_reek_only_of.rb", "reek.gemspec", "spec/reek/cli/help_command_spec.rb", "spec/reek/cli/reek_command_spec.rb", "spec/reek/cli/report_spec.rb", "spec/reek/cli/version_command_spec.rb", "spec/reek/cli/yaml_command_spec.rb", "spec/reek/core/code_context_spec.rb", "spec/reek/core/code_parser_spec.rb", "spec/reek/core/config_spec.rb", "spec/reek/core/method_context_spec.rb", "spec/reek/core/module_context_spec.rb", "spec/reek/core/object_refs_spec.rb", "spec/reek/core/singleton_method_context_spec.rb", "spec/reek/core/smell_configuration_spec.rb", "spec/reek/core/stop_context_spec.rb", "spec/reek/core/warning_collector_spec.rb", "spec/reek/examiner_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/boolean_parameter_spec.rb", "spec/reek/smells/class_variable_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/data_clump_spec.rb", "spec/reek/smells/duplication_spec.rb", "spec/reek/smells/feature_envy_spec.rb", "spec/reek/smells/irresponsible_module_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/long_yield_list_spec.rb", "spec/reek/smells/nested_iterators_spec.rb", "spec/reek/smells/simulated_polymorphism_spec.rb", "spec/reek/smells/smell_detector_shared.rb", "spec/reek/smells/uncommunicative_method_name_spec.rb", "spec/reek/smells/uncommunicative_module_name_spec.rb", "spec/reek/smells/uncommunicative_parameter_name_spec.rb", "spec/reek/smells/uncommunicative_variable_name_spec.rb", "spec/reek/smells/utility_function_spec.rb", "spec/reek/source/code_comment_spec.rb", "spec/reek/source/object_source_spec.rb", "spec/reek/source/reference_collector_spec.rb", "spec/reek/source/source_code_spec.rb", "spec/reek/source/tree_dresser_spec.rb", "spec/reek/spec/should_reek_of_spec.rb", "spec/reek/spec/should_reek_only_of_spec.rb", "spec/reek/spec/should_reek_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"]
|
17
|
+
s.files = [".yardopts", "History.txt", "License.txt", "README.md", "Rakefile", "bin/reek", "config/defaults.reek", "features/api.feature", "features/masking_smells.feature", "features/options.feature", "features/rake_task.feature", "features/reports.feature", "features/samples.feature", "features/stdin.feature", "features/step_definitions/reek_steps.rb", "features/support/env.rb", "features/yaml.feature", "lib/reek.rb", "lib/reek/cli/application.rb", "lib/reek/cli/command_line.rb", "lib/reek/cli/help_command.rb", "lib/reek/cli/reek_command.rb", "lib/reek/cli/report.rb", "lib/reek/cli/version_command.rb", "lib/reek/cli/yaml_command.rb", "lib/reek/core/code_context.rb", "lib/reek/core/code_parser.rb", "lib/reek/core/method_context.rb", "lib/reek/core/module_context.rb", "lib/reek/core/object_refs.rb", "lib/reek/core/singleton_method_context.rb", "lib/reek/core/smell_configuration.rb", "lib/reek/core/sniffer.rb", "lib/reek/core/stop_context.rb", "lib/reek/core/warning_collector.rb", "lib/reek/examiner.rb", "lib/reek/rake/task.rb", "lib/reek/smell_warning.rb", "lib/reek/smells.rb", "lib/reek/smells/attribute.rb", "lib/reek/smells/boolean_parameter.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/irresponsible_module.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_method_name.rb", "lib/reek/smells/uncommunicative_module_name.rb", "lib/reek/smells/uncommunicative_parameter_name.rb", "lib/reek/smells/uncommunicative_variable_name.rb", "lib/reek/smells/utility_function.rb", "lib/reek/source.rb", "lib/reek/source/code_comment.rb", "lib/reek/source/config_file.rb", "lib/reek/source/core_extras.rb", "lib/reek/source/reference_collector.rb", "lib/reek/source/sexp_formatter.rb", "lib/reek/source/source_code.rb", "lib/reek/source/source_file.rb", "lib/reek/source/source_locator.rb", "lib/reek/source/tree_dresser.rb", "lib/reek/spec.rb", "lib/reek/spec/should_reek.rb", "lib/reek/spec/should_reek_of.rb", "lib/reek/spec/should_reek_only_of.rb", "reek.gemspec", "spec/matchers/smell_of_matcher.rb", "spec/reek/cli/help_command_spec.rb", "spec/reek/cli/reek_command_spec.rb", "spec/reek/cli/report_spec.rb", "spec/reek/cli/version_command_spec.rb", "spec/reek/cli/yaml_command_spec.rb", "spec/reek/core/code_context_spec.rb", "spec/reek/core/code_parser_spec.rb", "spec/reek/core/config_spec.rb", "spec/reek/core/method_context_spec.rb", "spec/reek/core/module_context_spec.rb", "spec/reek/core/object_refs_spec.rb", "spec/reek/core/singleton_method_context_spec.rb", "spec/reek/core/smell_configuration_spec.rb", "spec/reek/core/stop_context_spec.rb", "spec/reek/core/warning_collector_spec.rb", "spec/reek/examiner_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/boolean_parameter_spec.rb", "spec/reek/smells/class_variable_spec.rb", "spec/reek/smells/control_couple_spec.rb", "spec/reek/smells/data_clump_spec.rb", "spec/reek/smells/duplication_spec.rb", "spec/reek/smells/feature_envy_spec.rb", "spec/reek/smells/irresponsible_module_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/long_yield_list_spec.rb", "spec/reek/smells/nested_iterators_spec.rb", "spec/reek/smells/simulated_polymorphism_spec.rb", "spec/reek/smells/smell_detector_shared.rb", "spec/reek/smells/uncommunicative_method_name_spec.rb", "spec/reek/smells/uncommunicative_module_name_spec.rb", "spec/reek/smells/uncommunicative_parameter_name_spec.rb", "spec/reek/smells/uncommunicative_variable_name_spec.rb", "spec/reek/smells/utility_function_spec.rb", "spec/reek/source/code_comment_spec.rb", "spec/reek/source/object_source_spec.rb", "spec/reek/source/reference_collector_spec.rb", "spec/reek/source/source_code_spec.rb", "spec/reek/source/tree_dresser_spec.rb", "spec/reek/spec/should_reek_of_spec.rb", "spec/reek/spec/should_reek_only_of_spec.rb", "spec/reek/spec/should_reek_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/config/allow_duplication.reek", "spec/samples/config/deeper_nested_iterators.reek", "spec/samples/corrupt_config_file/corrupt.reek", "spec/samples/corrupt_config_file/dirty.rb", "spec/samples/demo/demo.rb", "spec/samples/empty_config_file/dirty.rb", "spec/samples/empty_config_file/empty.reek", "spec/samples/exceptions.reek", "spec/samples/inline_config/dirty.rb", "spec/samples/inline_config/masked.reek", "spec/samples/inline.rb", "spec/samples/mask_some/dirty.rb", "spec/samples/mask_some/some.reek", "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"]
|
18
18
|
s.homepage = %q{http://wiki.github.com/kevinrutherford/reek}
|
19
19
|
s.post_install_message = %q{
|
20
|
-
|
20
|
+
Thank you for downloading Reek. For info:
|
21
|
+
- see the reek wiki http://wiki.github.com/kevinrutherford/reek
|
22
|
+
- follow @rubyreek on twitter
|
21
23
|
}
|
22
24
|
s.rdoc_options = ["--main", "README.md"]
|
23
25
|
s.require_paths = ["lib"]
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module SmellOfMatcher
|
2
|
+
class SmellOf
|
3
|
+
def initialize(klass, *expected_smells)
|
4
|
+
@klass = klass
|
5
|
+
@expected_smells = expected_smells
|
6
|
+
@config = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def failure_message_for_should
|
10
|
+
"Expected #{@source.desc} to smell of #{@klass}, but it didn't: #{@reason}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def failure_message_for_should_not
|
14
|
+
"Expected #{@source.desc} not to smell of #{@klass}, but it did"
|
15
|
+
end
|
16
|
+
|
17
|
+
def matches?(src)
|
18
|
+
@source = src.to_reek_source
|
19
|
+
ctx = MethodContext.new(nil, @source.syntax_tree)
|
20
|
+
detector = @klass.new(@source.desc, @klass.default_config.merge(@config))
|
21
|
+
detector.examine(ctx)
|
22
|
+
actual_smells = detector.smells_found.to_a
|
23
|
+
if actual_smells.empty?
|
24
|
+
@reason = 'no smells found by detector'
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
return false if actual_smells.any? do |expected_smell|
|
28
|
+
@reason = "Found #{expected_smell.smell_class}/#{expected_smell.subclass}" &&
|
29
|
+
expected_smell.smell_class != @klass::SMELL_CLASS &&
|
30
|
+
expected_smell.subclass != @klass::SMELL_SUBCLASS
|
31
|
+
end
|
32
|
+
return actual_smells.length == 1 if @expected_smells.empty?
|
33
|
+
return false unless @expected_smells.length == actual_smells.length
|
34
|
+
@expected_smells.each_with_index do |expected_smell,index|
|
35
|
+
expected_smell.each do |(key,value)|
|
36
|
+
if actual_smells[index].smell[key] != value
|
37
|
+
@reason = "#{key} != #{value}"
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
true
|
43
|
+
end
|
44
|
+
|
45
|
+
def with_config(options)
|
46
|
+
@config = options
|
47
|
+
self
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def smell_of(klass, *smells)
|
52
|
+
SmellOf.new(klass, *smells)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Spec::Runner.configure do |config|
|
57
|
+
config.include(SmellOfMatcher)
|
58
|
+
end
|
@@ -13,6 +13,7 @@ describe CodeContext do
|
|
13
13
|
@exp = mock('exp')
|
14
14
|
@exp.should_receive(:name).any_number_of_times.and_return(@exp_name)
|
15
15
|
@exp.should_receive(:full_name).any_number_of_times.and_return(@full_name)
|
16
|
+
@exp.should_receive(:comments).any_number_of_times.and_return('')
|
16
17
|
@ctx = CodeContext.new(nil, @exp)
|
17
18
|
end
|
18
19
|
it 'gets its short name from the exp' do
|
@@ -36,6 +37,7 @@ describe CodeContext do
|
|
36
37
|
@outer_name = 'another_random sting'
|
37
38
|
outer = mock('outer')
|
38
39
|
outer.should_receive(:full_name).at_least(:once).and_return(@outer_name)
|
40
|
+
outer.should_receive(:config).and_return({})
|
39
41
|
@ctx = CodeContext.new(outer, @exp)
|
40
42
|
end
|
41
43
|
it 'creates the correct full name' do
|
@@ -54,8 +56,8 @@ describe CodeContext do
|
|
54
56
|
it 'should pass unknown method calls down the stack' do
|
55
57
|
stop = StopContext.new
|
56
58
|
def stop.bananas(arg1, arg2) arg1 + arg2 + 43 end
|
57
|
-
element = ModuleContext.new(stop, 'mod',
|
58
|
-
element = MethodContext.new(element,
|
59
|
+
element = ModuleContext.new(stop, 'mod', ast(:module, :mod, nil))
|
60
|
+
element = MethodContext.new(element, ast(:defn, :bad))
|
59
61
|
element.bananas(17, -5).should == 55
|
60
62
|
end
|
61
63
|
end
|