reek 1.3.8 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +11 -0
  3. data/README.md +22 -14
  4. data/Rakefile +2 -15
  5. data/assets/html_output.html.erb +103 -0
  6. data/features/command_line_interface/options.feature +3 -0
  7. data/features/command_line_interface/smell_selection.feature +19 -0
  8. data/features/rake_task/rake_task.feature +1 -1
  9. data/features/reports/reports.feature +16 -0
  10. data/features/reports/yaml.feature +26 -23
  11. data/features/samples.feature +2 -1
  12. data/features/step_definitions/reek_steps.rb +15 -15
  13. data/features/support/env.rb +7 -9
  14. data/lib/reek/cli/application.rb +2 -4
  15. data/lib/reek/cli/command.rb +12 -0
  16. data/lib/reek/cli/help_command.rb +3 -6
  17. data/lib/reek/cli/options.rb +147 -0
  18. data/lib/reek/cli/reek_command.rb +18 -14
  19. data/lib/reek/cli/report/formatter.rb +56 -0
  20. data/lib/reek/cli/report/report.rb +106 -0
  21. data/lib/reek/cli/report/strategy.rb +63 -0
  22. data/lib/reek/cli/version_command.rb +3 -6
  23. data/lib/reek/config_file_exception.rb +0 -1
  24. data/lib/reek/core/code_context.rb +1 -3
  25. data/lib/reek/core/code_parser.rb +13 -12
  26. data/lib/reek/core/method_context.rb +13 -2
  27. data/lib/reek/core/module_context.rb +0 -4
  28. data/lib/reek/core/object_refs.rb +2 -3
  29. data/lib/reek/core/singleton_method_context.rb +0 -2
  30. data/lib/reek/core/smell_configuration.rb +3 -5
  31. data/lib/reek/core/smell_repository.rb +7 -8
  32. data/lib/reek/core/sniffer.rb +4 -10
  33. data/lib/reek/core/stop_context.rb +2 -4
  34. data/lib/reek/core/warning_collector.rb +0 -1
  35. data/lib/reek/examiner.rb +19 -17
  36. data/lib/reek/rake/task.rb +7 -10
  37. data/lib/reek/smell_warning.rb +4 -8
  38. data/lib/reek/smells.rb +0 -1
  39. data/lib/reek/smells/attribute.rb +8 -11
  40. data/lib/reek/smells/boolean_parameter.rb +5 -7
  41. data/lib/reek/smells/class_variable.rb +6 -7
  42. data/lib/reek/smells/control_parameter.rb +78 -45
  43. data/lib/reek/smells/data_clump.rb +13 -16
  44. data/lib/reek/smells/duplicate_method_call.rb +13 -11
  45. data/lib/reek/smells/feature_envy.rb +6 -7
  46. data/lib/reek/smells/irresponsible_module.rb +4 -6
  47. data/lib/reek/smells/long_parameter_list.rb +5 -7
  48. data/lib/reek/smells/long_yield_list.rb +2 -4
  49. data/lib/reek/smells/nested_iterators.rb +12 -22
  50. data/lib/reek/smells/nil_check.rb +35 -46
  51. data/lib/reek/smells/prima_donna_method.rb +24 -16
  52. data/lib/reek/smells/repeated_conditional.rb +8 -10
  53. data/lib/reek/smells/smell_detector.rb +9 -7
  54. data/lib/reek/smells/too_many_instance_variables.rb +7 -9
  55. data/lib/reek/smells/too_many_methods.rb +6 -8
  56. data/lib/reek/smells/too_many_statements.rb +4 -6
  57. data/lib/reek/smells/uncommunicative_method_name.rb +5 -7
  58. data/lib/reek/smells/uncommunicative_module_name.rb +5 -7
  59. data/lib/reek/smells/uncommunicative_parameter_name.rb +7 -9
  60. data/lib/reek/smells/uncommunicative_variable_name.rb +15 -18
  61. data/lib/reek/smells/unused_parameters.rb +5 -45
  62. data/lib/reek/smells/utility_function.rb +9 -10
  63. data/lib/reek/source.rb +0 -1
  64. data/lib/reek/source/code_comment.rb +7 -8
  65. data/lib/reek/source/config_file.rb +2 -4
  66. data/lib/reek/source/core_extras.rb +1 -1
  67. data/lib/reek/source/reference_collector.rb +1 -2
  68. data/lib/reek/source/sexp_extensions.rb +93 -10
  69. data/lib/reek/source/sexp_formatter.rb +2 -3
  70. data/lib/reek/source/sexp_node.rb +19 -15
  71. data/lib/reek/source/source_code.rb +4 -14
  72. data/lib/reek/source/source_file.rb +3 -5
  73. data/lib/reek/source/source_locator.rb +5 -6
  74. data/lib/reek/source/source_repository.rb +3 -3
  75. data/lib/reek/source/tree_dresser.rb +2 -2
  76. data/lib/reek/spec.rb +1 -2
  77. data/lib/reek/spec/should_reek.rb +8 -5
  78. data/lib/reek/spec/should_reek_of.rb +6 -4
  79. data/lib/reek/spec/should_reek_only_of.rb +10 -6
  80. data/lib/reek/version.rb +1 -1
  81. data/reek.gemspec +34 -30
  82. data/spec/gem/updates_spec.rb +3 -4
  83. data/spec/gem/yard_spec.rb +1 -2
  84. data/spec/matchers/smell_of_matcher.rb +12 -14
  85. data/spec/quality/reek_source_spec.rb +42 -0
  86. data/spec/reek/cli/help_command_spec.rb +7 -5
  87. data/spec/reek/cli/report_spec.rb +89 -22
  88. data/spec/reek/cli/version_command_spec.rb +8 -6
  89. data/spec/reek/core/code_context_spec.rb +25 -26
  90. data/spec/reek/core/code_parser_spec.rb +6 -6
  91. data/spec/reek/core/method_context_spec.rb +18 -18
  92. data/spec/reek/core/module_context_spec.rb +5 -5
  93. data/spec/reek/core/object_refs_spec.rb +21 -22
  94. data/spec/reek/core/smell_configuration_spec.rb +22 -21
  95. data/spec/reek/core/stop_context_spec.rb +2 -2
  96. data/spec/reek/core/warning_collector_spec.rb +3 -3
  97. data/spec/reek/examiner_spec.rb +9 -9
  98. data/spec/reek/smell_warning_spec.rb +29 -29
  99. data/spec/reek/smells/attribute_spec.rb +6 -6
  100. data/spec/reek/smells/behaves_like_variable_detector.rb +6 -6
  101. data/spec/reek/smells/boolean_parameter_spec.rb +17 -17
  102. data/spec/reek/smells/class_variable_spec.rb +9 -9
  103. data/spec/reek/smells/control_parameter_spec.rb +161 -137
  104. data/spec/reek/smells/data_clump_spec.rb +22 -19
  105. data/spec/reek/smells/duplicate_method_call_spec.rb +71 -27
  106. data/spec/reek/smells/feature_envy_spec.rb +32 -32
  107. data/spec/reek/smells/irresponsible_module_spec.rb +21 -21
  108. data/spec/reek/smells/long_parameter_list_spec.rb +14 -14
  109. data/spec/reek/smells/long_yield_list_spec.rb +6 -6
  110. data/spec/reek/smells/nested_iterators_spec.rb +21 -21
  111. data/spec/reek/smells/nil_check_spec.rb +23 -15
  112. data/spec/reek/smells/prima_donna_method_spec.rb +5 -5
  113. data/spec/reek/smells/repeated_conditional_spec.rb +14 -14
  114. data/spec/reek/smells/smell_detector_shared.rb +9 -9
  115. data/spec/reek/smells/too_many_instance_variables_spec.rb +12 -12
  116. data/spec/reek/smells/too_many_methods_spec.rb +10 -10
  117. data/spec/reek/smells/too_many_statements_spec.rb +41 -41
  118. data/spec/reek/smells/uncommunicative_method_name_spec.rb +4 -4
  119. data/spec/reek/smells/uncommunicative_module_name_spec.rb +12 -12
  120. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +21 -21
  121. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +49 -49
  122. data/spec/reek/smells/unused_parameters_spec.rb +26 -16
  123. data/spec/reek/smells/utility_function_spec.rb +20 -20
  124. data/spec/reek/source/code_comment_spec.rb +37 -37
  125. data/spec/reek/source/object_source_spec.rb +5 -5
  126. data/spec/reek/source/reference_collector_spec.rb +9 -9
  127. data/spec/reek/source/sexp_extensions_spec.rb +73 -52
  128. data/spec/reek/source/sexp_formatter_spec.rb +3 -4
  129. data/spec/reek/source/sexp_node_spec.rb +3 -3
  130. data/spec/reek/source/source_code_spec.rb +16 -15
  131. data/spec/reek/source/tree_dresser_spec.rb +2 -2
  132. data/spec/reek/spec/should_reek_of_spec.rb +11 -11
  133. data/spec/reek/spec/should_reek_only_of_spec.rb +11 -11
  134. data/spec/reek/spec/should_reek_spec.rb +11 -11
  135. data/spec/samples/one_smelly_file/dirty.rb +3 -0
  136. data/spec/spec_helper.rb +0 -6
  137. data/tasks/develop.rake +8 -16
  138. data/tasks/reek.rake +5 -13
  139. data/tasks/test.rake +5 -22
  140. metadata +56 -34
  141. data/lib/reek/cli/command_line.rb +0 -126
  142. data/lib/reek/cli/report.rb +0 -138
@@ -3,7 +3,6 @@ require 'reek/smell_warning'
3
3
 
4
4
  module Reek
5
5
  module Smells
6
-
7
6
  #
8
7
  # Simulated Polymorphism occurs when
9
8
  # * code uses a case statement (especially on a type field);
@@ -22,9 +21,8 @@ module Reek
22
21
  # testing the same value throughout a single class.
23
22
  #
24
23
  class RepeatedConditional < SmellDetector
25
-
26
24
  SMELL_CLASS = 'SimulatedPolymorphism'
27
- SMELL_SUBCLASS = self.name.split(/::/)[-1]
25
+ SMELL_SUBCLASS = name.split(/::/)[-1]
28
26
 
29
27
  def self.contexts # :nodoc:
30
28
  [:class]
@@ -47,7 +45,7 @@ module Reek
47
45
  #
48
46
  def examine_context(ctx)
49
47
  @max_identical_ifs = value(MAX_IDENTICAL_IFS_KEY, ctx, DEFAULT_MAX_IFS)
50
- conditional_counts(ctx).select do |key, lines|
48
+ conditional_counts(ctx).select do |_key, lines|
51
49
  lines.length > @max_identical_ifs
52
50
  end.map do |key, lines|
53
51
  occurs = lines.length
@@ -55,7 +53,7 @@ module Reek
55
53
  SmellWarning.new(SMELL_CLASS, ctx.full_name, lines,
56
54
  "tests #{expr} at least #{occurs} times",
57
55
  @source, SMELL_SUBCLASS,
58
- {'expression' => expr, 'occurrences' => occurs})
56
+ 'expression' => expr, 'occurrences' => occurs)
59
57
  end
60
58
  end
61
59
 
@@ -65,13 +63,13 @@ module Reek
65
63
  # occurs. Ignores nested classes and modules.
66
64
  #
67
65
  def conditional_counts(sexp)
68
- result = Hash.new {|hash, key| hash[key] = []}
69
- collector = proc { |node|
66
+ result = Hash.new { |hash, key| hash[key] = [] }
67
+ collector = proc do |node|
70
68
  condition = node.condition
71
- next if condition.nil? or condition == s(:call, nil, :block_given?)
69
+ next if condition.nil? || condition == s(:call, nil, :block_given?)
72
70
  result[condition].push(condition.line)
73
- }
74
- [:if, :case].each {|stmt| sexp.local_nodes(stmt, &collector) }
71
+ end
72
+ [:if, :case].each { |stmt| sexp.local_nodes(stmt, &collector) }
75
73
  result
76
74
  end
77
75
  end
@@ -4,7 +4,6 @@ require 'reek/core/smell_configuration'
4
4
 
5
5
  module Reek
6
6
  module Smells
7
-
8
7
  module ExcludeInitialize
9
8
  def self.default_config
10
9
  super.merge(EXCLUDE_KEY => ['initialize'])
@@ -15,7 +14,6 @@ module Reek
15
14
  # Shared responsibilities of all smell detectors.
16
15
  #
17
16
  class SmellDetector
18
-
19
17
  # The name of the config field that lists the names of code contexts
20
18
  # that should not be checked. Add this field to the config for each
21
19
  # smell that should ignore this code element.
@@ -65,11 +63,15 @@ module Reek
65
63
  end
66
64
 
67
65
  def examine(context)
68
- enabled = @config.enabled? && config_for(context)[Core::SmellConfiguration::ENABLED_KEY] != false
69
- if enabled && !exception?(context)
70
- sm = examine_context(context)
71
- @smells_found += sm
72
- end
66
+ return unless enabled_for? context
67
+ return if exception?(context)
68
+
69
+ sm = examine_context(context)
70
+ @smells_found += sm
71
+ end
72
+
73
+ def enabled_for?(context)
74
+ enabled? && config_for(context)[Core::SmellConfiguration::ENABLED_KEY] != false
73
75
  end
74
76
 
75
77
  def exception?(context)
@@ -3,18 +3,16 @@ require 'reek/smell_warning'
3
3
 
4
4
  module Reek
5
5
  module Smells
6
-
7
6
  #
8
7
  # A Large Class is a class or module that has a large number of
9
8
  # instance variables, methods or lines of code.
10
- #
9
+ #
11
10
  # +TooManyInstanceVariables' reports classes having more than a
12
11
  # configurable number of instance variables.
13
12
  #
14
13
  class TooManyInstanceVariables < SmellDetector
15
-
16
14
  SMELL_CLASS = 'LargeClass'
17
- SMELL_SUBCLASS = self.name.split(/::/)[-1]
15
+ SMELL_SUBCLASS = name.split(/::/)[-1]
18
16
  IVAR_COUNT_KEY = 'ivar_count'
19
17
 
20
18
  # The name of the config field that sets the maximum number of instance
@@ -44,15 +42,15 @@ module Reek
44
42
  check_num_ivars(ctx)
45
43
  end
46
44
 
47
- private
45
+ private
48
46
 
49
47
  def check_num_ivars(ctx) # :nodoc:
50
- count = ctx.local_nodes(:iasgn).map {|iasgn| iasgn[1]}.uniq.length
48
+ count = ctx.local_nodes(:iasgn).map { |iasgn| iasgn[1] }.uniq.length
51
49
  return [] if count <= @max_allowed_ivars
52
50
  smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
53
- "has at least #{count} instance variables",
54
- @source, SMELL_SUBCLASS,
55
- {IVAR_COUNT_KEY => count})
51
+ "has at least #{count} instance variables",
52
+ @source, SMELL_SUBCLASS,
53
+ IVAR_COUNT_KEY => count)
56
54
  [smell]
57
55
  end
58
56
  end
@@ -3,20 +3,18 @@ require 'reek/smell_warning'
3
3
 
4
4
  module Reek
5
5
  module Smells
6
-
7
6
  #
8
7
  # A Large Class is a class or module that has a large number of
9
8
  # instance variables, methods or lines of code.
10
- #
9
+ #
11
10
  # +TooManyMethods+ reports classes having more than a configurable number
12
11
  # of methods. The method count includes public, protected and private
13
12
  # methods, and excludes methods inherited from superclasses or included
14
13
  # modules.
15
14
  #
16
15
  class TooManyMethods < SmellDetector
17
-
18
16
  SMELL_CLASS = 'LargeClass'
19
- SMELL_SUBCLASS = self.name.split(/::/)[-1]
17
+ SMELL_SUBCLASS = name.split(/::/)[-1]
20
18
  METHOD_COUNT_KEY = 'method_count'
21
19
 
22
20
  # The name of the config field that sets the maximum number of methods
@@ -46,15 +44,15 @@ module Reek
46
44
  check_num_methods(ctx)
47
45
  end
48
46
 
49
- private
47
+ private
50
48
 
51
49
  def check_num_methods(ctx) # :nodoc:
52
50
  actual = ctx.local_nodes(:defn).length
53
51
  return [] if actual <= @max_allowed_methods
54
52
  smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
55
- "has at least #{actual} methods",
56
- @source, SMELL_SUBCLASS,
57
- {METHOD_COUNT_KEY => actual})
53
+ "has at least #{actual} methods",
54
+ @source, SMELL_SUBCLASS,
55
+ METHOD_COUNT_KEY => actual)
58
56
  [smell]
59
57
  end
60
58
  end
@@ -3,16 +3,14 @@ require 'reek/smell_warning'
3
3
 
4
4
  module Reek
5
5
  module Smells
6
-
7
6
  #
8
7
  # A Long Method is any method that has a large number of lines.
9
8
  #
10
9
  # +TooManyStatements+ reports any method with more than 5 statements.
11
10
  #
12
11
  class TooManyStatements < SmellDetector
13
-
14
12
  SMELL_CLASS = 'LongMethod'
15
- SMELL_SUBCLASS = self.name.split(/::/)[-1]
13
+ SMELL_SUBCLASS = name.split(/::/)[-1]
16
14
 
17
15
  STATEMENT_COUNT_KEY = 'statement_count'
18
16
 
@@ -39,9 +37,9 @@ module Reek
39
37
  num = ctx.num_statements
40
38
  return [] if num <= @max_allowed_statements
41
39
  smell = SmellWarning.new(SMELL_CLASS, ctx.full_name, [ctx.exp.line],
42
- "has approx #{num} statements",
43
- @source, SMELL_SUBCLASS,
44
- {STATEMENT_COUNT_KEY => num})
40
+ "has approx #{num} statements",
41
+ @source, SMELL_SUBCLASS,
42
+ STATEMENT_COUNT_KEY => num)
45
43
  [smell]
46
44
  end
47
45
  end
@@ -3,11 +3,10 @@ require 'reek/smell_warning'
3
3
 
4
4
  module Reek
5
5
  module Smells
6
-
7
6
  #
8
7
  # An Uncommunicative Name is a name that doesn't communicate its intent
9
8
  # well enough.
10
- #
9
+ #
11
10
  # Poor names make it hard for the reader to build a mental picture
12
11
  # of what's going on in the code. They can also be mis-interpreted;
13
12
  # and they hurt the flow of reading, because the reader must slow
@@ -18,9 +17,8 @@ module Reek
18
17
  # * names ending with a number
19
18
  #
20
19
  class UncommunicativeMethodName < SmellDetector
21
-
22
20
  SMELL_CLASS = 'UncommunicativeName'
23
- SMELL_SUBCLASS = self.name.split(/::/)[-1]
21
+ SMELL_SUBCLASS = name.split(/::/)[-1]
24
22
  METHOD_NAME_KEY = 'method_name'
25
23
 
26
24
  # The name of the config field that lists the regexps of
@@ -59,10 +57,10 @@ module Reek
59
57
  return [] if @accept_names.include?(ctx.full_name)
60
58
  var = name.gsub(/^[@\*\&]*/, '')
61
59
  return [] if @accept_names.include?(var)
62
- return [] unless @reject_names.detect {|patt| patt === var}
60
+ return [] unless @reject_names.find { |patt| patt =~ var }
63
61
  smell = SmellWarning.new('UncommunicativeName', ctx.full_name, [ctx.exp.line],
64
- "has the name '#{name}'",
65
- @source, 'UncommunicativeMethodName', {METHOD_NAME_KEY => name})
62
+ "has the name '#{name}'",
63
+ @source, 'UncommunicativeMethodName', METHOD_NAME_KEY => name)
66
64
  [smell]
67
65
  end
68
66
  end
@@ -3,11 +3,10 @@ require 'reek/smell_warning'
3
3
 
4
4
  module Reek
5
5
  module Smells
6
-
7
6
  #
8
7
  # An Uncommunicative Name is a name that doesn't communicate its intent
9
8
  # well enough.
10
- #
9
+ #
11
10
  # Poor names make it hard for the reader to build a mental picture
12
11
  # of what's going on in the code. They can also be mis-interpreted;
13
12
  # and they hurt the flow of reading, because the reader must slow
@@ -18,9 +17,8 @@ module Reek
18
17
  # * names ending with a number
19
18
  #
20
19
  class UncommunicativeModuleName < SmellDetector
21
-
22
20
  SMELL_CLASS = 'UncommunicativeName'
23
- SMELL_SUBCLASS = self.name.split(/::/)[-1]
21
+ SMELL_SUBCLASS = name.split(/::/)[-1]
24
22
  MODULE_NAME_KEY = 'module_name'
25
23
 
26
24
  # The name of the config field that lists the regexps of
@@ -62,10 +60,10 @@ module Reek
62
60
  return [] if @accept_names.include?(full_name)
63
61
  var = name.gsub(/^[@\*\&]*/, '')
64
62
  return [] if @accept_names.include?(var)
65
- return [] unless @reject_names.detect {|patt| patt === var}
63
+ return [] unless @reject_names.find { |patt| patt =~ var }
66
64
  smell = SmellWarning.new(SMELL_CLASS, full_name, [exp.line],
67
- "has the name '#{name}'",
68
- @source, SMELL_SUBCLASS, {MODULE_NAME_KEY => name})
65
+ "has the name '#{name}'",
66
+ @source, SMELL_SUBCLASS, MODULE_NAME_KEY => name)
69
67
  [smell]
70
68
  end
71
69
  end
@@ -3,11 +3,10 @@ require 'reek/smell_warning'
3
3
 
4
4
  module Reek
5
5
  module Smells
6
-
7
6
  #
8
7
  # An Uncommunicative Name is a name that doesn't communicate its intent
9
8
  # well enough.
10
- #
9
+ #
11
10
  # Poor names make it hard for the reader to build a mental picture
12
11
  # of what's going on in the code. They can also be mis-interpreted;
13
12
  # and they hurt the flow of reading, because the reader must slow
@@ -18,9 +17,8 @@ module Reek
18
17
  # * names ending with a number
19
18
  #
20
19
  class UncommunicativeParameterName < SmellDetector
21
-
22
20
  SMELL_CLASS = 'UncommunicativeName'
23
- SMELL_SUBCLASS = self.name.split(/::/)[-1]
21
+ SMELL_SUBCLASS = name.split(/::/)[-1]
24
22
  PARAMETER_NAME_KEY = 'parameter_name'
25
23
 
26
24
  # The name of the config field that lists the regexps of
@@ -57,18 +55,18 @@ module Reek
57
55
  @accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
58
56
  context_expression = ctx.exp
59
57
  context_expression.parameter_names.select do |name|
60
- is_bad_name?(name) && ctx.uses_param?(name)
58
+ bad_name?(name) && ctx.uses_param?(name)
61
59
  end.map do |name|
62
60
  SmellWarning.new(SMELL_CLASS, ctx.full_name, [context_expression.line],
63
61
  "has the parameter name '#{name}'",
64
- @source, SMELL_SUBCLASS, {PARAMETER_NAME_KEY => name.to_s})
62
+ @source, SMELL_SUBCLASS, PARAMETER_NAME_KEY => name.to_s)
65
63
  end
66
64
  end
67
65
 
68
- def is_bad_name?(name)
66
+ def bad_name?(name)
69
67
  var = name.to_s.gsub(/^[@\*\&]*/, '')
70
- return false if var == '*' or @accept_names.include?(var)
71
- @reject_names.detect {|patt| patt === var}
68
+ return false if var == '*' || @accept_names.include?(var)
69
+ @reject_names.find { |patt| patt =~ var }
72
70
  end
73
71
  end
74
72
  end
@@ -3,11 +3,10 @@ require 'reek/smell_warning'
3
3
 
4
4
  module Reek
5
5
  module Smells
6
-
7
6
  #
8
7
  # An Uncommunicative Name is a name that doesn't communicate its intent
9
8
  # well enough.
10
- #
9
+ #
11
10
  # Poor names make it hard for the reader to build a mental picture
12
11
  # of what's going on in the code. They can also be mis-interpreted;
13
12
  # and they hurt the flow of reading, because the reader must slow
@@ -18,9 +17,8 @@ module Reek
18
17
  # * names ending with a number
19
18
  #
20
19
  class UncommunicativeVariableName < SmellDetector
21
-
22
20
  SMELL_CLASS = 'UncommunicativeName'
23
- SMELL_SUBCLASS = self.name.split(/::/)[-1]
21
+ SMELL_SUBCLASS = name.split(/::/)[-1]
24
22
  VARIABLE_NAME_KEY = 'variable_name'
25
23
 
26
24
  # The name of the config field that lists the regexps of
@@ -55,37 +53,37 @@ module Reek
55
53
  def examine_context(ctx)
56
54
  @reject_names = value(REJECT_KEY, ctx, DEFAULT_REJECT_SET)
57
55
  @accept_names = value(ACCEPT_KEY, ctx, DEFAULT_ACCEPT_SET)
58
- variable_names(ctx.exp).select do |name, lines|
59
- is_bad_name?(name, ctx)
56
+ variable_names(ctx.exp).select do |name, _lines|
57
+ bad_name?(name, ctx)
60
58
  end.map do |name, lines|
61
59
  SmellWarning.new(SMELL_CLASS, ctx.full_name, lines,
62
60
  "has the variable name '#{name}'",
63
- @source, SMELL_SUBCLASS, {VARIABLE_NAME_KEY => name.to_s})
61
+ @source, SMELL_SUBCLASS, VARIABLE_NAME_KEY => name.to_s)
64
62
  end
65
63
  end
66
64
 
67
- def is_bad_name?(name, ctx)
65
+ def bad_name?(name, _ctx)
68
66
  var = name.to_s.gsub(/^[@\*\&]*/, '')
69
67
  return false if @accept_names.include?(var)
70
- @reject_names.detect {|patt| patt === var}
68
+ @reject_names.find { |patt| patt =~ var }
71
69
  end
72
70
 
73
71
  def variable_names(exp)
74
- result = Hash.new {|hash, key| hash[key] = []}
72
+ result = Hash.new { |hash, key| hash[key] = [] }
75
73
  find_assignment_variable_names(exp, result)
76
74
  find_block_argument_variable_names(exp, result)
77
- result.to_a.sort_by {|name, _| name.to_s}
75
+ result.to_a.sort_by { |name, _| name.to_s }
78
76
  end
79
77
 
80
78
  def find_assignment_variable_names(exp, accumulator)
81
79
  assignment_nodes = exp.each_node(:lasgn, [:class, :module, :defs, :defn])
82
80
 
83
81
  case exp.first
84
- when :class, :module
85
- assignment_nodes += exp.each_node(:iasgn, [:class, :module])
82
+ when :class, :module
83
+ assignment_nodes += exp.each_node(:iasgn, [:class, :module])
86
84
  end
87
85
 
88
- assignment_nodes.each {|asgn| accumulator[asgn[1]].push(asgn.line) }
86
+ assignment_nodes.each { |asgn| accumulator[asgn[1]].push(asgn.line) }
89
87
  end
90
88
 
91
89
  def find_block_argument_variable_names(exp, accumulator)
@@ -115,10 +113,9 @@ module Reek
115
113
 
116
114
  def record_variable_name(exp, symbol, accumulator)
117
115
  varname = symbol.to_s.sub(/^\*/, '')
118
- if varname != ""
119
- var = varname.to_sym
120
- accumulator[var].push(exp.line)
121
- end
116
+ return if varname == ''
117
+ var = varname.to_sym
118
+ accumulator[var].push(exp.line)
122
119
  end
123
120
  end
124
121
  end
@@ -3,81 +3,41 @@ require 'reek/smell_warning'
3
3
 
4
4
  module Reek
5
5
  module Smells
6
-
7
6
  #
8
7
  # Methods should use their parameters.
9
8
  #
10
9
  class UnusedParameters < SmellDetector
11
-
12
10
  SMELL_CLASS = 'UnusedCode'
13
11
  SMELL_SUBCLASS = name.split(/::/)[-1]
14
12
 
15
13
  PARAMETER_KEY = 'parameter'
16
14
 
17
- EMPTY_ARRAY = [].freeze
18
- EMPTY_STRING = ''.freeze
19
- SPLAT_MATCH = /^\*/.freeze
20
- UNDERSCORE = '_'.freeze
21
-
22
15
  #
23
16
  # Checks whether the given method has any unused parameters.
24
17
  #
25
18
  # @return [Array<SmellWarning>]
26
19
  #
27
20
  def examine_context(method_ctx)
28
- return EMPTY_ARRAY if zsuper?(method_ctx)
29
- unused_params(method_ctx).map do |param|
21
+ return [] if method_ctx.uses_super_with_implicit_arguments?
22
+ method_ctx.unused_params.map do |param|
30
23
  smell_warning(method_ctx, param)
31
24
  end
32
25
  end
33
26
 
34
27
  private
35
28
 
36
- def unused_params(method_ctx)
37
- params(method_ctx).select do |param|
38
- param = sanitized_param(param)
39
- next if skip?(param)
40
- !method_ctx.uses_param?(param)
41
- end
42
- end
43
-
44
- def skip?(param)
45
- anonymous_splat?(param) || marked_unused?(param)
46
- end
47
-
48
- def params(method_ctx)
49
- method_ctx.exp.arg_names || EMPTY_ARRAY
50
- end
51
-
52
- def sanitized_param(param)
53
- param.to_s.sub(SPLAT_MATCH, EMPTY_STRING)
54
- end
55
-
56
- def marked_unused?(param)
57
- param.start_with?(UNDERSCORE)
58
- end
59
-
60
- def anonymous_splat?(param)
61
- param == EMPTY_STRING
62
- end
63
-
64
- def zsuper?(method_ctx)
65
- method_ctx.exp.body.has_nested_node? :zsuper
66
- end
67
-
68
29
  def smell_warning(method_ctx, param)
69
- param_name = param.to_s
30
+ param_name = param.name.to_s
70
31
  SmellWarning.new(
71
32
  SMELL_CLASS,
72
33
  method_ctx.full_name,
73
- [ method_ctx.exp.line ],
34
+ [method_ctx.exp.line],
74
35
  "has unused parameter '#{param_name}'",
75
36
  @source,
76
37
  SMELL_SUBCLASS,
77
- { PARAMETER_KEY => param_name }
38
+ PARAMETER_KEY => param_name
78
39
  )
79
40
  end
80
-
81
41
  end
82
42
  end
83
43
  end