reek 1.2.7.3 → 1.2.8
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 +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
|