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.
Files changed (76) hide show
  1. data/History.txt +17 -0
  2. data/README.md +32 -48
  3. data/config/defaults.reek +7 -1
  4. data/features/api.feature +20 -0
  5. data/features/masking_smells.feature +41 -0
  6. data/features/options.feature +4 -0
  7. data/features/rake_task.feature +14 -0
  8. data/features/yaml.feature +8 -8
  9. data/lib/reek.rb +1 -1
  10. data/lib/reek/cli/command_line.rb +9 -2
  11. data/lib/reek/cli/reek_command.rb +5 -4
  12. data/lib/reek/cli/yaml_command.rb +2 -2
  13. data/lib/reek/core/code_context.rb +10 -1
  14. data/lib/reek/core/method_context.rb +2 -2
  15. data/lib/reek/core/sniffer.rb +3 -1
  16. data/lib/reek/core/stop_context.rb +4 -0
  17. data/lib/reek/examiner.rb +2 -2
  18. data/lib/reek/rake/task.rb +16 -0
  19. data/lib/reek/smell_warning.rb +3 -2
  20. data/lib/reek/smells/attribute.rb +13 -9
  21. data/lib/reek/smells/boolean_parameter.rb +14 -9
  22. data/lib/reek/smells/class_variable.rb +16 -5
  23. data/lib/reek/smells/control_couple.rb +11 -6
  24. data/lib/reek/smells/data_clump.rb +33 -30
  25. data/lib/reek/smells/duplication.rb +39 -8
  26. data/lib/reek/smells/feature_envy.rb +7 -8
  27. data/lib/reek/smells/irresponsible_module.rb +12 -3
  28. data/lib/reek/smells/large_class.rb +31 -15
  29. data/lib/reek/smells/long_method.rb +15 -5
  30. data/lib/reek/smells/long_parameter_list.rb +14 -7
  31. data/lib/reek/smells/long_yield_list.rb +12 -9
  32. data/lib/reek/smells/nested_iterators.rb +46 -11
  33. data/lib/reek/smells/simulated_polymorphism.rb +16 -8
  34. data/lib/reek/smells/smell_detector.rb +13 -13
  35. data/lib/reek/smells/uncommunicative_method_name.rb +12 -20
  36. data/lib/reek/smells/uncommunicative_module_name.rb +17 -19
  37. data/lib/reek/smells/uncommunicative_parameter_name.rb +22 -15
  38. data/lib/reek/smells/uncommunicative_variable_name.rb +24 -18
  39. data/lib/reek/smells/utility_function.rb +6 -6
  40. data/lib/reek/source/code_comment.rb +19 -1
  41. data/lib/reek/source/tree_dresser.rb +40 -22
  42. data/reek.gemspec +6 -4
  43. data/spec/matchers/smell_of_matcher.rb +58 -0
  44. data/spec/reek/core/code_context_spec.rb +4 -2
  45. data/spec/reek/core/code_parser_spec.rb +2 -1
  46. data/spec/reek/core/method_context_spec.rb +5 -5
  47. data/spec/reek/smells/attribute_spec.rb +2 -4
  48. data/spec/reek/smells/boolean_parameter_spec.rb +32 -42
  49. data/spec/reek/smells/class_variable_spec.rb +22 -6
  50. data/spec/reek/smells/control_couple_spec.rb +15 -14
  51. data/spec/reek/smells/data_clump_spec.rb +29 -111
  52. data/spec/reek/smells/duplication_spec.rb +79 -49
  53. data/spec/reek/smells/feature_envy_spec.rb +1 -2
  54. data/spec/reek/smells/irresponsible_module_spec.rb +43 -22
  55. data/spec/reek/smells/large_class_spec.rb +34 -59
  56. data/spec/reek/smells/long_method_spec.rb +15 -10
  57. data/spec/reek/smells/long_parameter_list_spec.rb +24 -24
  58. data/spec/reek/smells/long_yield_list_spec.rb +13 -14
  59. data/spec/reek/smells/nested_iterators_spec.rb +93 -76
  60. data/spec/reek/smells/smell_detector_shared.rb +4 -2
  61. data/spec/reek/smells/uncommunicative_method_name_spec.rb +10 -27
  62. data/spec/reek/smells/uncommunicative_module_name_spec.rb +22 -23
  63. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +36 -26
  64. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +45 -48
  65. data/spec/reek/smells/utility_function_spec.rb +14 -13
  66. data/spec/reek/source/code_comment_spec.rb +61 -3
  67. data/spec/reek/source/tree_dresser_spec.rb +96 -1
  68. data/spec/samples/config/allow_duplication.reek +3 -0
  69. data/spec/samples/config/deeper_nested_iterators.reek +3 -0
  70. data/spec/samples/demo/demo.rb +8 -0
  71. data/spec/samples/inline_config/dirty.rb +16 -0
  72. data/spec/samples/inline_config/masked.reek +7 -0
  73. data/spec/samples/mask_some/dirty.rb +8 -0
  74. data/spec/samples/mask_some/some.reek +8 -0
  75. data/spec/spec_helper.rb +2 -0
  76. 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
- # Remembers any smells found.
24
+ #
25
+ # @return [Array<SmellWarning>]
21
26
  #
22
27
  def examine_context(ctx)
23
28
  comment = Source::CodeComment.new(ctx.exp.comments)
24
- found(ctx, "has no descriptive comment") unless comment.is_descriptive?
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
- def check_num_methods(klass) # :nodoc:
50
- actual = klass.local_nodes(:defn).length
51
- return if actual <= value(MAX_ALLOWED_METHODS_KEY, klass, DEFAULT_MAX_METHODS)
52
- found(klass, "has at least #{actual} methods", SUBCLASS_TOO_MANY_METHODS, {'method_count' => actual})
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
- def check_num_ivars(klass) # :nodoc:
56
- count = klass.local_nodes(:iasgn).map {|iasgn| iasgn[1]}.uniq.length
57
- return if count <= value(MAX_ALLOWED_IVARS_KEY, klass, DEFAULT_MAX_IVARS)
58
- found(klass, "has at least #{count} instance variables", SUBCLASS_TOO_MANY_IVARS, {'ivar_count' => count})
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
- # Checks +klass+ for too many methods or too many instance variables.
63
- # Remembers any smells found.
64
- #
65
- def examine_context(klass)
66
- check_num_methods(klass)
67
- check_num_ivars(klass)
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
- def examine_context(method)
38
- num = method.num_statements
39
- return false if num <= value(MAX_ALLOWED_STATEMENTS_KEY, method, DEFAULT_MAX_STATEMENTS)
40
- found(method, "has approx #{num} statements", SUBCLASS_TOO_MANY_STATEMENTS, {'statement_count' => num})
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 scope.
44
- # Remembers any smells found.
45
+ # Checks the number of parameters in the given method.
46
+ #
47
+ # @return [Array<SmellWarning>]
45
48
  #
46
- def examine_context(method_ctx)
47
- num_params = method_ctx.parameters.length
48
- return false if num_params <= value(MAX_ALLOWED_PARAMS_KEY, method_ctx, DEFAULT_MAX_ALLOWED_PARAMS)
49
- found(method_ctx, "has #{num_params} parameters",
50
- SMELL_SUBCLASS, {'parameter_count' => num_params})
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
- MAX_ALLOWED_PARAMS_KEY => DEFAULT_MAX_ALLOWED_PARAMS
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
- # Remembers any smells found.
38
+ #
39
+ # @return [Array<SmellWarning>]
37
40
  #
38
41
  def examine_context(method_ctx)
39
- method_ctx.local_nodes(:yield).each do |yield_node|
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
- next if num_params <= value(MAX_ALLOWED_PARAMS_KEY, method_ctx, DEFAULT_MAX_ALLOWED_PARAMS)
42
- smell = SmellWarning.new(SMELL_CLASS, method_ctx.full_name, [yield_node.line],
43
- "yields #{num_params} parameters",
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
- def examine_context(method_ctx)
20
- find_deepest_iterators(method_ctx).each do |iter|
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
- found(method_ctx, "contains iterators nested #{depth} deep", '',
23
- {'depth' => depth}, [iter[0].line])
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
- def find_deepest_iterators(method_ctx)
60
+ private
61
+
62
+ def find_deepest_iterators(ctx)
30
63
  result = []
31
- find_iters(method_ctx.exp, 1, result)
32
- result.select {|item| item[1] >= 2}
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
- find_iters([elem.block], depth+1, result)
43
- result << [elem, depth] if result.length == current
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
- def examine_context(klass)
49
- conditional_counts(klass).each do |key, lines|
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
- next unless occurs > value(MAX_IDENTICAL_IFS_KEY, klass, DEFAULT_MAX_IFS)
52
- expr = key.format
53
- found(klass, "tests #{expr} at least #{occurs} times",
54
- 'RepeatedConditional', {'expression' => expr, 'occurrences' => occurs}, lines)
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 # :nodoc:
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 = Set.new
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
- examine_context(context) if @config.enabled? and !exception?(context)
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
- def examine_context(method_ctx)
59
- name = method_ctx.name
60
- return false if accept?(method_ctx)
61
- return false unless is_bad_name?(name, method_ctx)
62
- smell = SmellWarning.new('UncommunicativeName', method_ctx.full_name, [method_ctx.exp.line],
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
- @smells_found << smell
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
- def examine_context(module_ctx)
55
- name = module_ctx.name
56
- return false if accept?(module_ctx)
57
- return false unless is_bad_name?(name, module_ctx)
58
- smell = SmellWarning.new('UncommunicativeName', module_ctx.full_name, [module_ctx.exp.line],
59
- "has the name '#{name}'",
60
- @source, 'UncommunicativeModuleName', {'module_name' => name.to_s})
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 false if value(ACCEPT_KEY, context, DEFAULT_ACCEPT_SET).include?(var)
72
- value(REJECT_KEY, context, DEFAULT_REJECT_SET).detect {|patt| patt === var}
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