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
@@ -1,7 +1,6 @@
|
|
1
1
|
require File.join( File.dirname( File.expand_path(__FILE__)), 'smell_detector')
|
2
2
|
require File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'source')
|
3
3
|
|
4
|
-
# Part of Reek's core
|
5
4
|
module Reek
|
6
5
|
module Smells
|
7
6
|
|
@@ -11,17 +10,27 @@ module Reek
|
|
11
10
|
#
|
12
11
|
class IrresponsibleModule < SmellDetector
|
13
12
|
|
13
|
+
SMELL_CLASS = self.name.split(/::/)[-1]
|
14
|
+
SMELL_SUBCLASS = SMELL_CLASS
|
15
|
+
|
16
|
+
MODULE_NAME_KEY = 'module_name'
|
17
|
+
|
14
18
|
def self.contexts # :nodoc:
|
15
19
|
[:class]
|
16
20
|
end
|
17
21
|
|
18
22
|
#
|
19
23
|
# Checks the given class or module for a descriptive comment.
|
20
|
-
#
|
24
|
+
#
|
25
|
+
# @return [Array<SmellWarning>]
|
21
26
|
#
|
22
27
|
def examine_context(ctx)
|
23
28
|
comment = Source::CodeComment.new(ctx.exp.comments)
|
24
|
-
|
29
|
+
return [] if comment.is_descriptive?
|
30
|
+
smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
|
31
|
+
'has no descriptive comment',
|
32
|
+
@source, SMELL_SUBCLASS, {MODULE_NAME_KEY => ctx.exp.text_name})
|
33
|
+
[smell]
|
25
34
|
end
|
26
35
|
end
|
27
36
|
end
|
@@ -15,8 +15,12 @@ module Reek
|
|
15
15
|
# included modules.
|
16
16
|
#
|
17
17
|
class LargeClass < SmellDetector
|
18
|
+
|
19
|
+
SMELL_CLASS = self.name.split(/::/)[-1]
|
18
20
|
SUBCLASS_TOO_MANY_METHODS = 'TooManyMethods'
|
19
21
|
SUBCLASS_TOO_MANY_IVARS = 'TooManyInstanceVariables'
|
22
|
+
METHOD_COUNT_KEY = 'method_count'
|
23
|
+
IVAR_COUNT_KEY = 'ivar_count'
|
20
24
|
|
21
25
|
# The name of the config field that sets the maximum number of methods
|
22
26
|
# permitted in a class.
|
@@ -46,25 +50,37 @@ module Reek
|
|
46
50
|
super(source, config)
|
47
51
|
end
|
48
52
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
+
#
|
54
|
+
# Checks +klass+ for too many methods or too many instance variables.
|
55
|
+
#
|
56
|
+
# @return [Array<SmellWarning>]
|
57
|
+
#
|
58
|
+
def examine_context(ctx)
|
59
|
+
@max_allowed_ivars = value(MAX_ALLOWED_IVARS_KEY, ctx, DEFAULT_MAX_IVARS)
|
60
|
+
@max_allowed_methods = value(MAX_ALLOWED_METHODS_KEY, ctx, DEFAULT_MAX_METHODS)
|
61
|
+
check_num_methods(ctx) + check_num_ivars(ctx)
|
53
62
|
end
|
54
63
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
64
|
+
private
|
65
|
+
|
66
|
+
def check_num_methods(ctx) # :nodoc:
|
67
|
+
actual = ctx.local_nodes(:defn).length
|
68
|
+
return [] if actual <= @max_allowed_methods
|
69
|
+
smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
|
70
|
+
"has at least #{actual} methods",
|
71
|
+
@source, SUBCLASS_TOO_MANY_METHODS,
|
72
|
+
{METHOD_COUNT_KEY => actual})
|
73
|
+
[smell]
|
59
74
|
end
|
60
75
|
|
61
|
-
#
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
76
|
+
def check_num_ivars(ctx) # :nodoc:
|
77
|
+
count = ctx.local_nodes(:iasgn).map {|iasgn| iasgn[1]}.uniq.length
|
78
|
+
return [] if count <= @max_allowed_ivars
|
79
|
+
smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
|
80
|
+
"has at least #{count} instance variables",
|
81
|
+
@source, SUBCLASS_TOO_MANY_IVARS,
|
82
|
+
{IVAR_COUNT_KEY => count})
|
83
|
+
[smell]
|
68
84
|
end
|
69
85
|
end
|
70
86
|
end
|
@@ -11,8 +11,12 @@ module Reek
|
|
11
11
|
# 5 statements.
|
12
12
|
#
|
13
13
|
class LongMethod < SmellDetector
|
14
|
+
|
15
|
+
SMELL_CLASS = self.name.split(/::/)[-1]
|
14
16
|
SUBCLASS_TOO_MANY_STATEMENTS = 'TooManyStatements'
|
15
17
|
|
18
|
+
STATEMENT_COUNT_KEY = 'statement_count'
|
19
|
+
|
16
20
|
# The name of the config field that sets the maximum number of
|
17
21
|
# statements permitted in any method.
|
18
22
|
MAX_ALLOWED_STATEMENTS_KEY = 'max_statements'
|
@@ -32,12 +36,18 @@ module Reek
|
|
32
36
|
|
33
37
|
#
|
34
38
|
# Checks the length of the given +method+.
|
35
|
-
# Remembers any smells found.
|
36
39
|
#
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
# @return [Array<SmellWarning>]
|
41
|
+
#
|
42
|
+
def examine_context(ctx)
|
43
|
+
@max_allowed_statements = value(MAX_ALLOWED_STATEMENTS_KEY, ctx, DEFAULT_MAX_STATEMENTS)
|
44
|
+
num = ctx.num_statements
|
45
|
+
return [] if num <= @max_allowed_statements
|
46
|
+
smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
|
47
|
+
"has approx #{num} statements",
|
48
|
+
@source, SUBCLASS_TOO_MANY_STATEMENTS,
|
49
|
+
{STATEMENT_COUNT_KEY => num})
|
50
|
+
[smell]
|
41
51
|
end
|
42
52
|
end
|
43
53
|
end
|
@@ -18,6 +18,8 @@ module Reek
|
|
18
18
|
SMELL_CLASS = self.name.split(/::/)[-1]
|
19
19
|
SMELL_SUBCLASS = 'LongParameterList'
|
20
20
|
|
21
|
+
PARAMETER_COUNT_KEY = 'parameter_count'
|
22
|
+
|
21
23
|
# The name of the config field that sets the maximum number of
|
22
24
|
# parameters permitted in any method or block.
|
23
25
|
MAX_ALLOWED_PARAMS_KEY = 'max_params'
|
@@ -40,14 +42,19 @@ module Reek
|
|
40
42
|
end
|
41
43
|
|
42
44
|
#
|
43
|
-
# Checks the number of parameters in the given
|
44
|
-
#
|
45
|
+
# Checks the number of parameters in the given method.
|
46
|
+
#
|
47
|
+
# @return [Array<SmellWarning>]
|
45
48
|
#
|
46
|
-
def examine_context(
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
def examine_context(ctx)
|
50
|
+
@max_allowed_params = value(MAX_ALLOWED_PARAMS_KEY, ctx, DEFAULT_MAX_ALLOWED_PARAMS)
|
51
|
+
num_params = ctx.exp.arg_names.length
|
52
|
+
return [] if num_params <= @max_allowed_params
|
53
|
+
smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
|
54
|
+
"has #{num_params} parameters",
|
55
|
+
@source, SMELL_SUBCLASS,
|
56
|
+
{PARAMETER_COUNT_KEY => num_params})
|
57
|
+
[smell]
|
51
58
|
end
|
52
59
|
end
|
53
60
|
end
|
@@ -21,9 +21,11 @@ module Reek
|
|
21
21
|
# value.
|
22
22
|
DEFAULT_MAX_ALLOWED_PARAMS = 3
|
23
23
|
|
24
|
+
PARAMETER_COUNT_KEY = 'parameter_count'
|
25
|
+
|
24
26
|
def self.default_config
|
25
27
|
super.adopt(
|
26
|
-
|
28
|
+
MAX_ALLOWED_PARAMS_KEY => DEFAULT_MAX_ALLOWED_PARAMS
|
27
29
|
)
|
28
30
|
end
|
29
31
|
|
@@ -33,17 +35,18 @@ module Reek
|
|
33
35
|
|
34
36
|
#
|
35
37
|
# Checks the number of parameters in the given scope.
|
36
|
-
#
|
38
|
+
#
|
39
|
+
# @return [Array<SmellWarning>]
|
37
40
|
#
|
38
41
|
def examine_context(method_ctx)
|
39
|
-
|
42
|
+
@max_allowed_params = value(MAX_ALLOWED_PARAMS_KEY, method_ctx, DEFAULT_MAX_ALLOWED_PARAMS)
|
43
|
+
method_ctx.local_nodes(:yield).select do |yield_node|
|
44
|
+
yield_node.args.length > @max_allowed_params
|
45
|
+
end.map do |yield_node|
|
40
46
|
num_params = yield_node.args.length
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@source, SMELL_SUBCLASS, {'parameter_count' => num_params})
|
45
|
-
@smells_found << smell
|
46
|
-
#SMELL: serious duplication
|
47
|
+
SmellWarning.new(SMELL_CLASS, method_ctx.full_name, [yield_node.line],
|
48
|
+
"yields #{num_params} parameters",
|
49
|
+
@source, SMELL_SUBCLASS, {PARAMETER_COUNT_KEY => num_params})
|
47
50
|
end
|
48
51
|
end
|
49
52
|
end
|
@@ -10,26 +10,59 @@ module Reek
|
|
10
10
|
# +NestedIterators+ reports failing methods only once.
|
11
11
|
#
|
12
12
|
class NestedIterators < SmellDetector
|
13
|
+
|
14
|
+
SMELL_CLASS = self.name.split(/::/)[-1]
|
15
|
+
SMELL_SUBCLASS = SMELL_CLASS
|
13
16
|
# SMELL: should be a subclass of UnnecessaryComplexity
|
17
|
+
NESTING_DEPTH_KEY = 'depth'
|
18
|
+
|
19
|
+
# The name of the config field that sets the maximum depth
|
20
|
+
# of nested iterators to be permitted within any single method.
|
21
|
+
MAX_ALLOWED_NESTING_KEY = 'max_allowed_nesting'
|
22
|
+
|
23
|
+
DEFAULT_MAX_ALLOWED_NESTING = 1
|
24
|
+
|
25
|
+
# The name of the config field that sets the names of any
|
26
|
+
# methods for which nesting should not be considered
|
27
|
+
IGNORE_ITERATORS_KEY = 'ignore_iterators'
|
28
|
+
|
29
|
+
DEFAULT_IGNORE_ITERATORS = []
|
30
|
+
|
31
|
+
def self.default_config
|
32
|
+
super.adopt(
|
33
|
+
MAX_ALLOWED_NESTING_KEY => DEFAULT_MAX_ALLOWED_NESTING,
|
34
|
+
IGNORE_ITERATORS_KEY => DEFAULT_IGNORE_ITERATORS
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(source, config = NestedIterators.default_config)
|
39
|
+
super(source, config)
|
40
|
+
end
|
14
41
|
|
15
42
|
#
|
16
43
|
# Checks whether the given +block+ is inside another.
|
17
|
-
# Remembers any smells found.
|
18
44
|
#
|
19
|
-
|
20
|
-
|
45
|
+
# @return [Array<SmellWarning>]
|
46
|
+
#
|
47
|
+
def examine_context(ctx)
|
48
|
+
@ignore_iterators = value(IGNORE_ITERATORS_KEY, ctx, DEFAULT_IGNORE_ITERATORS)
|
49
|
+
@max_allowed_nesting = value(MAX_ALLOWED_NESTING_KEY, ctx, DEFAULT_MAX_ALLOWED_NESTING)
|
50
|
+
find_deepest_iterators(ctx).map do |iter|
|
21
51
|
depth = iter[1]
|
22
|
-
|
23
|
-
|
52
|
+
SmellWarning.new(SMELL_CLASS, ctx.full_name, [iter[0].line],
|
53
|
+
"contains iterators nested #{depth} deep",
|
54
|
+
@source, SMELL_SUBCLASS,
|
55
|
+
{NESTING_DEPTH_KEY => depth})
|
24
56
|
end
|
25
|
-
# TODO: report the nesting depth and the innermost line
|
26
57
|
# BUG: no longer reports nesting outside methods (eg. in Optparse)
|
27
58
|
end
|
28
59
|
|
29
|
-
|
60
|
+
private
|
61
|
+
|
62
|
+
def find_deepest_iterators(ctx)
|
30
63
|
result = []
|
31
|
-
find_iters(
|
32
|
-
result.select {|item| item[1]
|
64
|
+
find_iters(ctx.exp, 1, result)
|
65
|
+
result.select {|item| item[1] > @max_allowed_nesting}
|
33
66
|
end
|
34
67
|
|
35
68
|
def find_iters(exp, depth, result)
|
@@ -39,8 +72,10 @@ module Reek
|
|
39
72
|
when :iter
|
40
73
|
find_iters([elem.call], depth, result)
|
41
74
|
current = result.length
|
42
|
-
|
43
|
-
|
75
|
+
call = Source::SexpFormatter.format(elem.call)
|
76
|
+
ignored = @ignore_iterators.any? { |ignore| /#{ignore}/ === call }
|
77
|
+
find_iters([elem.block], depth + (ignored ? 0 : 1), result)
|
78
|
+
result << [elem, depth] if result.length == current unless ignored
|
44
79
|
when :class, :defn, :defs, :module
|
45
80
|
next
|
46
81
|
else
|
@@ -23,6 +23,9 @@ module Reek
|
|
23
23
|
#
|
24
24
|
class SimulatedPolymorphism < SmellDetector
|
25
25
|
|
26
|
+
SMELL_CLASS = self.name.split(/::/)[-1]
|
27
|
+
SMELL_SUBCLASS = 'RepeatedConditional'
|
28
|
+
|
26
29
|
def self.contexts # :nodoc:
|
27
30
|
[:class]
|
28
31
|
end
|
@@ -43,15 +46,20 @@ module Reek
|
|
43
46
|
|
44
47
|
#
|
45
48
|
# Checks the given class for multiple identical conditional tests.
|
46
|
-
# Remembers any smells found.
|
47
49
|
#
|
48
|
-
|
49
|
-
|
50
|
+
# @return [Array<SmellWarning>]
|
51
|
+
#
|
52
|
+
def examine_context(ctx)
|
53
|
+
@max_identical_ifs = value(MAX_IDENTICAL_IFS_KEY, ctx, DEFAULT_MAX_IFS)
|
54
|
+
conditional_counts(ctx).select do |key, lines|
|
55
|
+
lines.length > @max_identical_ifs
|
56
|
+
end.map do |key, lines|
|
50
57
|
occurs = lines.length
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
58
|
+
expr = key.format_ruby
|
59
|
+
SmellWarning.new(SMELL_CLASS, ctx.full_name, lines,
|
60
|
+
"tests #{expr} at least #{occurs} times",
|
61
|
+
@source, SMELL_SUBCLASS,
|
62
|
+
{'expression' => expr, 'occurrences' => occurs})
|
55
63
|
end
|
56
64
|
end
|
57
65
|
|
@@ -61,7 +69,7 @@ module Reek
|
|
61
69
|
# occurs. Ignores nested classes and modules.
|
62
70
|
#
|
63
71
|
def conditional_counts(sexp)
|
64
|
-
result = Hash.new {|hash,key| hash[key] = []}
|
72
|
+
result = Hash.new {|hash, key| hash[key] = []}
|
65
73
|
collector = proc { |node|
|
66
74
|
condition = node.condition
|
67
75
|
next if condition.nil? or condition == s(:call, nil, :block_given?, s(:arglist))
|
@@ -29,7 +29,7 @@ module Reek
|
|
29
29
|
DEFAULT_EXCLUDE_SET = []
|
30
30
|
|
31
31
|
class << self
|
32
|
-
def contexts
|
32
|
+
def contexts
|
33
33
|
[:defn, :defs]
|
34
34
|
end
|
35
35
|
|
@@ -46,7 +46,7 @@ module Reek
|
|
46
46
|
def initialize(source, config = self.class.default_config)
|
47
47
|
@source = source
|
48
48
|
@config = Core::SmellConfiguration.new(config)
|
49
|
-
@smells_found =
|
49
|
+
@smells_found = []
|
50
50
|
end
|
51
51
|
|
52
52
|
def register(hooks)
|
@@ -64,7 +64,11 @@ module Reek
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def examine(context)
|
67
|
-
|
67
|
+
enabled = @config.enabled? && config_for(context)[Core::SmellConfiguration::ENABLED_KEY] != false
|
68
|
+
if enabled && !exception?(context)
|
69
|
+
sm = examine_context(context)
|
70
|
+
@smells_found += sm
|
71
|
+
end
|
68
72
|
end
|
69
73
|
|
70
74
|
def examine_context(context)
|
@@ -74,21 +78,17 @@ module Reek
|
|
74
78
|
context.matches?(value(EXCLUDE_KEY, context, DEFAULT_EXCLUDE_SET))
|
75
79
|
end
|
76
80
|
|
77
|
-
def found(context, message, subclass = '', parameters = {}, lines = nil)
|
78
|
-
lines ||= [context.exp.line] # SMELL: nil?!?!?! Yuk
|
79
|
-
smell = SmellWarning.new(self.class.name.split(/::/)[-1], context.full_name,
|
80
|
-
lines, message,
|
81
|
-
@source, subclass, parameters)
|
82
|
-
@smells_found << smell
|
83
|
-
smell
|
84
|
-
end
|
85
|
-
|
86
81
|
def report_on(report)
|
87
82
|
@smells_found.each { |smell| smell.report_on(report) }
|
88
83
|
end
|
89
84
|
|
90
85
|
def value(key, ctx, fall_back)
|
91
|
-
@config.value(key, ctx, fall_back)
|
86
|
+
config_for(ctx)[key] || @config.value(key, ctx, fall_back)
|
87
|
+
end
|
88
|
+
|
89
|
+
def config_for(ctx)
|
90
|
+
ctx.config[self.class.name.split(/::/)[-1]] || {}
|
91
|
+
# BUG: needs to consider smell class AND subclass
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|
@@ -53,29 +53,21 @@ module Reek
|
|
53
53
|
|
54
54
|
#
|
55
55
|
# Checks the given +context+ for uncommunicative names.
|
56
|
-
# Remembers any smells found.
|
57
56
|
#
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
+
name = ctx.name
|
63
|
+
return [] if @accept_names.include?(ctx.full_name)
|
64
|
+
var = name.to_s.gsub(/^[@\*\&]*/, '')
|
65
|
+
return [] if @accept_names.include?(var)
|
66
|
+
return [] unless @reject_names.detect {|patt| patt === var}
|
67
|
+
smell = SmellWarning.new('UncommunicativeName', ctx.full_name, [ctx.exp.line],
|
63
68
|
"has the name '#{name}'",
|
64
69
|
@source, 'UncommunicativeMethodName', {METHOD_NAME_KEY => name.to_s})
|
65
|
-
|
66
|
-
#SMELL: serious duplication
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def accept?(context)
|
72
|
-
value(ACCEPT_KEY, context, DEFAULT_ACCEPT_SET).include?(context.full_name)
|
73
|
-
end
|
74
|
-
|
75
|
-
def is_bad_name?(name, context) # :nodoc:
|
76
|
-
var = name.to_s.gsub(/^[@\*\&]*/, '')
|
77
|
-
return false if value(ACCEPT_KEY, context, DEFAULT_ACCEPT_SET).include?(var)
|
78
|
-
value(REJECT_KEY, context, DEFAULT_REJECT_SET).detect {|patt| patt === var}
|
70
|
+
[smell]
|
79
71
|
end
|
80
72
|
end
|
81
73
|
end
|
@@ -19,6 +19,10 @@ module Reek
|
|
19
19
|
#
|
20
20
|
class UncommunicativeModuleName < SmellDetector
|
21
21
|
|
22
|
+
SMELL_CLASS = 'UncommunicativeName'
|
23
|
+
SMELL_SUBCLASS = self.name.split(/::/)[-1]
|
24
|
+
MODULE_NAME_KEY = 'module_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'
|
@@ -49,27 +53,21 @@ 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
|
-
@smells_found << smell
|
62
|
-
#SMELL: serious duplication
|
63
|
-
end
|
64
|
-
|
65
|
-
def accept?(context)
|
66
|
-
value(ACCEPT_KEY, context, DEFAULT_ACCEPT_SET).include?(context.full_name)
|
67
|
-
end
|
68
|
-
|
69
|
-
def is_bad_name?(name, context) # :nodoc:
|
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
|
+
name = ctx.exp.simple_name
|
63
|
+
return [] if @accept_names.include?(ctx.full_name)
|
70
64
|
var = name.to_s.gsub(/^[@\*\&]*/, '')
|
71
|
-
return
|
72
|
-
|
65
|
+
return [] if @accept_names.include?(var)
|
66
|
+
return [] unless @reject_names.detect {|patt| patt === var}
|
67
|
+
smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
|
68
|
+
"has the name '#{name}'",
|
69
|
+
@source, SMELL_SUBCLASS, {MODULE_NAME_KEY => name.to_s})
|
70
|
+
[smell]
|
73
71
|
end
|
74
72
|
end
|
75
73
|
end
|