reek 3.5.0 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/CHANGELOG.md +19 -12
  4. data/CONTRIBUTING.md +7 -7
  5. data/README.md +91 -28
  6. data/ataru_setup.rb +13 -0
  7. data/{config/defaults.reek → defaults.reek} +0 -0
  8. data/docs/API.md +32 -31
  9. data/docs/Attribute.md +1 -1
  10. data/docs/Basic-Smell-Options.md +2 -1
  11. data/docs/Boolean-Parameter.md +1 -1
  12. data/docs/Class-Variable.md +2 -2
  13. data/docs/Command-Line-Options.md +2 -2
  14. data/docs/Control-Couple.md +3 -3
  15. data/docs/Control-Parameter.md +2 -2
  16. data/docs/Data-Clump.md +2 -2
  17. data/docs/Duplicate-Method-Call.md +4 -4
  18. data/docs/Feature-Envy.md +2 -2
  19. data/docs/How-reek-works-internally.md +2 -2
  20. data/docs/Irresponsible-Module.md +2 -2
  21. data/docs/Large-Class.md +2 -2
  22. data/docs/Long-Parameter-List.md +1 -1
  23. data/docs/Long-Yield-List.md +2 -2
  24. data/docs/Module-Initialize.md +3 -3
  25. data/docs/Nested-Iterators.md +1 -1
  26. data/docs/Nil-Check.md +2 -2
  27. data/docs/Prima-Donna-Method.md +4 -4
  28. data/docs/RSpec-matchers.md +7 -7
  29. data/docs/Rake-Task.md +2 -2
  30. data/docs/Reek-Driven-Development.md +4 -4
  31. data/docs/Repeated-Conditional.md +2 -2
  32. data/docs/Simulated-Polymorphism.md +2 -2
  33. data/docs/Smell-Suppression.md +3 -3
  34. data/docs/Too-Many-Instance-Variables.md +4 -4
  35. data/docs/Too-Many-Methods.md +5 -5
  36. data/docs/Too-Many-Statements.md +2 -2
  37. data/docs/Uncommunicative-Method-Name.md +4 -4
  38. data/docs/Uncommunicative-Module-Name.md +4 -4
  39. data/docs/Uncommunicative-Name.md +2 -2
  40. data/docs/Uncommunicative-Parameter-Name.md +4 -4
  41. data/docs/Uncommunicative-Variable-Name.md +3 -3
  42. data/docs/Unused-Parameters.md +2 -2
  43. data/docs/Utility-Function.md +4 -4
  44. data/docs/Versioning-Policy.md +2 -2
  45. data/features/command_line_interface/options.feature +1 -1
  46. data/features/configuration_files/directory_specific_directives.feature +4 -4
  47. data/features/configuration_loading.feature +10 -24
  48. data/features/programmatic_access.feature +3 -3
  49. data/features/reports/json.feature +1 -1
  50. data/features/reports/reports.feature +2 -2
  51. data/features/reports/yaml.feature +1 -1
  52. data/lib/reek/ast/sexp_extensions.rb +17 -498
  53. data/lib/reek/ast/sexp_extensions/arguments.rb +101 -0
  54. data/lib/reek/ast/sexp_extensions/attribute_assignments.rb +12 -0
  55. data/lib/reek/ast/sexp_extensions/block.rb +36 -0
  56. data/lib/reek/ast/sexp_extensions/case.rb +20 -0
  57. data/lib/reek/ast/sexp_extensions/constant.rb +12 -0
  58. data/lib/reek/ast/sexp_extensions/if.rb +16 -0
  59. data/lib/reek/ast/sexp_extensions/literal.rb +12 -0
  60. data/lib/reek/ast/sexp_extensions/logical_operators.rb +26 -0
  61. data/lib/reek/ast/sexp_extensions/methods.rb +114 -0
  62. data/lib/reek/ast/sexp_extensions/module.rb +85 -0
  63. data/lib/reek/ast/sexp_extensions/nested_assignables.rb +23 -0
  64. data/lib/reek/ast/sexp_extensions/send.rb +60 -0
  65. data/lib/reek/ast/sexp_extensions/super.rb +14 -0
  66. data/lib/reek/ast/sexp_extensions/symbols.rb +16 -0
  67. data/lib/reek/ast/sexp_extensions/variables.rb +38 -0
  68. data/lib/reek/ast/sexp_extensions/when.rb +16 -0
  69. data/lib/reek/ast/sexp_extensions/yield.rb +16 -0
  70. data/lib/reek/cli/application.rb +0 -4
  71. data/lib/reek/cli/options.rb +2 -4
  72. data/lib/reek/configuration/app_configuration.rb +37 -9
  73. data/lib/reek/configuration/configuration_file_finder.rb +8 -5
  74. data/lib/reek/configuration/directory_directives.rb +2 -2
  75. data/lib/reek/context/attribute_context.rb +21 -0
  76. data/lib/reek/context/code_context.rb +5 -9
  77. data/lib/reek/rake/task.rb +5 -5
  78. data/lib/reek/smells/nested_iterators.rb +73 -26
  79. data/lib/reek/smells/smell_warning.rb +1 -38
  80. data/lib/reek/source/source_code.rb +1 -1
  81. data/lib/reek/spec.rb +2 -2
  82. data/lib/reek/spec/should_reek_of.rb +8 -3
  83. data/lib/reek/spec/should_reek_only_of.rb +2 -1
  84. data/lib/reek/spec/smell_matcher.rb +59 -0
  85. data/lib/reek/tree_walker.rb +4 -3
  86. data/lib/reek/version.rb +1 -1
  87. data/logo/reek.bw.png +0 -0
  88. data/logo/reek.bw.svg +77 -0
  89. data/logo/reek.png +0 -0
  90. data/logo/reek.svg +621 -0
  91. data/logo/reek.text.png +0 -0
  92. data/logo/reek.text.svg +628 -0
  93. data/reek.gemspec +1 -1
  94. data/spec/factories/factories.rb +0 -1
  95. data/spec/reek/ast/sexp_extensions_spec.rb +0 -7
  96. data/spec/reek/cli/options_spec.rb +1 -2
  97. data/spec/reek/configuration/app_configuration_spec.rb +30 -14
  98. data/spec/reek/configuration/configuration_file_finder_spec.rb +23 -5
  99. data/spec/reek/smells/attribute_spec.rb +11 -2
  100. data/spec/reek/smells/boolean_parameter_spec.rb +14 -12
  101. data/spec/reek/smells/class_variable_spec.rb +18 -15
  102. data/spec/reek/smells/control_parameter_spec.rb +1 -2
  103. data/spec/reek/smells/duplicate_method_call_spec.rb +1 -2
  104. data/spec/reek/smells/feature_envy_spec.rb +8 -29
  105. data/spec/reek/smells/irresponsible_module_spec.rb +1 -2
  106. data/spec/reek/smells/long_parameter_list_spec.rb +1 -2
  107. data/spec/reek/smells/long_yield_list_spec.rb +1 -2
  108. data/spec/reek/smells/nested_iterators_spec.rb +1 -2
  109. data/spec/reek/smells/nil_check_spec.rb +1 -1
  110. data/spec/reek/smells/prima_donna_method_spec.rb +1 -1
  111. data/spec/reek/smells/repeated_conditional_spec.rb +1 -2
  112. data/spec/reek/smells/smell_detector_shared.rb +1 -1
  113. data/spec/reek/smells/smell_warning_spec.rb +2 -4
  114. data/spec/reek/smells/too_many_instance_variables_spec.rb +20 -19
  115. data/spec/reek/smells/too_many_statements_spec.rb +1 -1
  116. data/spec/reek/smells/uncommunicative_method_name_spec.rb +1 -4
  117. data/spec/reek/smells/uncommunicative_module_name_spec.rb +1 -4
  118. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +1 -4
  119. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +3 -3
  120. data/spec/reek/smells/utility_function_spec.rb +1 -3
  121. data/spec/reek/spec/should_reek_of_spec.rb +5 -5
  122. data/spec/reek/spec/smell_matcher_spec.rb +92 -0
  123. data/tasks/configuration.rake +15 -0
  124. metadata +37 -5
  125. data/config/cucumber.yml +0 -3
  126. data/tasks/develop.rake +0 -21
@@ -0,0 +1,101 @@
1
+ module Reek
2
+ module AST
3
+ module SexpExtensions
4
+ # Base module for utility methods for argument nodes.
5
+ module ArgNodeBase
6
+ def name
7
+ children.first
8
+ end
9
+
10
+ # Other is a symbol?
11
+ def ==(other)
12
+ name == other
13
+ end
14
+
15
+ def marked_unused?
16
+ plain_name.start_with?('_')
17
+ end
18
+
19
+ def plain_name
20
+ name.to_s
21
+ end
22
+
23
+ def block?
24
+ false
25
+ end
26
+
27
+ def optional_argument?
28
+ false
29
+ end
30
+
31
+ def anonymous_splat?
32
+ false
33
+ end
34
+
35
+ def components
36
+ [self]
37
+ end
38
+ end
39
+
40
+ # Utility methods for :arg nodes.
41
+ module ArgNode
42
+ include ArgNodeBase
43
+ end
44
+
45
+ # Utility methods for :kwarg nodes.
46
+ module KwargNode
47
+ include ArgNodeBase
48
+ end
49
+
50
+ # Utility methods for :optarg nodes.
51
+ module OptargNode
52
+ include ArgNodeBase
53
+
54
+ def optional_argument?
55
+ true
56
+ end
57
+ end
58
+
59
+ # Utility methods for :kwoptarg nodes.
60
+ module KwoptargNode
61
+ include ArgNodeBase
62
+
63
+ def optional_argument?
64
+ true
65
+ end
66
+ end
67
+
68
+ # Utility methods for :blockarg nodes.
69
+ module BlockargNode
70
+ include ArgNodeBase
71
+
72
+ def block?
73
+ true
74
+ end
75
+ end
76
+
77
+ # Utility methods for :restarg nodes.
78
+ module RestargNode
79
+ include ArgNodeBase
80
+
81
+ def anonymous_splat?
82
+ !name
83
+ end
84
+ end
85
+
86
+ # Utility methods for :kwrestarg nodes.
87
+ module KwrestargNode
88
+ include ArgNodeBase
89
+
90
+ def anonymous_splat?
91
+ !name
92
+ end
93
+ end
94
+
95
+ # Utility methods for :shadowarg nodes.
96
+ module ShadowargNode
97
+ include ArgNodeBase
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,12 @@
1
+ module Reek
2
+ module AST
3
+ module SexpExtensions
4
+ # Utility methods for :attrasgn nodes.
5
+ module AttrasgnNode
6
+ def args
7
+ children[2]
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ module Reek
2
+ module AST
3
+ module SexpExtensions
4
+ # Utility methods for :block nodes.
5
+ module BlockNode
6
+ def call
7
+ children.first
8
+ end
9
+
10
+ def args
11
+ children[1]
12
+ end
13
+
14
+ def block
15
+ children[2]
16
+ end
17
+
18
+ def parameters
19
+ children[1] || []
20
+ end
21
+
22
+ def parameter_names
23
+ parameters.children
24
+ end
25
+
26
+ def simple_name
27
+ :block
28
+ end
29
+
30
+ def without_block_arguments?
31
+ args.components.empty?
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ module Reek
2
+ module AST
3
+ module SexpExtensions
4
+ # Utility methods for :case nodes.
5
+ module CaseNode
6
+ def condition
7
+ children.first
8
+ end
9
+
10
+ def body_nodes(type, ignoring = [])
11
+ children[1..-1].compact.flat_map { |child| child.find_nodes(type, ignoring) }
12
+ end
13
+
14
+ def else_body
15
+ children.last
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ module Reek
2
+ module AST
3
+ module SexpExtensions
4
+ # Utility methods for :const nodes.
5
+ module ConstNode
6
+ def simple_name
7
+ children.last
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module Reek
2
+ module AST
3
+ module SexpExtensions
4
+ # Utility methods for :if nodes.
5
+ module IfNode
6
+ def condition
7
+ children.first
8
+ end
9
+
10
+ def body_nodes(type, ignoring = [])
11
+ children[1..-1].compact.flat_map { |child| child.find_nodes(type, ignoring) }
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module Reek
2
+ module AST
3
+ module SexpExtensions
4
+ # Utility methods for :lit nodes.
5
+ module LitNode
6
+ def value
7
+ children.first
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,26 @@
1
+ module Reek
2
+ module AST
3
+ module SexpExtensions
4
+ # Base module for utility methods for :and and :or nodes.
5
+ module LogicOperatorBase
6
+ def condition
7
+ children.first
8
+ end
9
+
10
+ def body_nodes(type, ignoring = [])
11
+ children[1].find_nodes type, ignoring
12
+ end
13
+ end
14
+
15
+ # Utility methods for :and nodes.
16
+ module AndNode
17
+ include LogicOperatorBase
18
+ end
19
+
20
+ # Utility methods for :or nodes.
21
+ module OrNode
22
+ include LogicOperatorBase
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,114 @@
1
+ module Reek
2
+ module AST
3
+ module SexpExtensions
4
+ # Base module for utility methods for :def and :defs nodes.
5
+ module MethodNodeBase
6
+ def arguments
7
+ parameters.reject(&:block?)
8
+ end
9
+
10
+ def arg_names
11
+ arguments.map(&:name)
12
+ end
13
+
14
+ def parameters
15
+ argslist.components
16
+ end
17
+
18
+ def parameter_names
19
+ parameters.map(&:name)
20
+ end
21
+
22
+ def name_without_bang
23
+ name.to_s.chop
24
+ end
25
+
26
+ def ends_with_bang?
27
+ name[-1] == '!'
28
+ end
29
+
30
+ def body_nodes(types, ignoring = [])
31
+ if body
32
+ body.find_nodes(types, ignoring)
33
+ else
34
+ []
35
+ end
36
+ end
37
+ end
38
+
39
+ # Checking if a method is a singleton method.
40
+ module SingletonMethod
41
+ def singleton_method?
42
+ singleton_method_via_class_self_notation?
43
+ end
44
+
45
+ # Ruby allows us to make a method a singleton_method using the
46
+ # class << self syntax.
47
+ #
48
+ # To check for this we check if the parent node is of type :sclass.
49
+ #
50
+ # @return [Boolean]
51
+ def singleton_method_via_class_self_notation?
52
+ return unless parent
53
+ parent.type == :sclass
54
+ end
55
+ end
56
+
57
+ # Utility methods for :def nodes.
58
+ module DefNode
59
+ include MethodNodeBase
60
+ include SingletonMethod
61
+
62
+ def name
63
+ children.first
64
+ end
65
+
66
+ def argslist
67
+ children[1]
68
+ end
69
+
70
+ def body
71
+ children[2]
72
+ end
73
+
74
+ def full_name(outer)
75
+ [outer, name].reject(&:empty?).join('#')
76
+ end
77
+
78
+ def depends_on_instance?
79
+ ReferenceCollector.new(self).num_refs_to_self > 0
80
+ end
81
+ end
82
+
83
+ # Utility methods for :defs nodes.
84
+ module DefsNode
85
+ include MethodNodeBase
86
+
87
+ def receiver
88
+ children.first
89
+ end
90
+
91
+ def name
92
+ children[1]
93
+ end
94
+
95
+ def argslist
96
+ children[2]
97
+ end
98
+
99
+ def body
100
+ children[3]
101
+ end
102
+
103
+ def full_name(outer)
104
+ prefix = outer == '' ? '' : "#{outer}#"
105
+ "#{prefix}#{SexpFormatter.format(receiver)}.#{name}"
106
+ end
107
+
108
+ def depends_on_instance?
109
+ false
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,85 @@
1
+ module Reek
2
+ module AST
3
+ module SexpExtensions
4
+ # Base module for utility methods for module nodes.
5
+ module ModuleNodeBase
6
+ # The full name of the module or class, including the name of any
7
+ # module or class it is nested inside of.
8
+ #
9
+ # For example, given code like this:
10
+ #
11
+ # module Foo
12
+ # class Bar::Baz
13
+ # end
14
+ # end
15
+ #
16
+ # The full name for the inner class will be 'Foo::Bar::Baz'. To return
17
+ # the correct name, the name of the outer context has to be passed into this method.
18
+ #
19
+ # @param outer [String] full name of the wrapping module or class
20
+ # @return the module's full name
21
+ def full_name(outer)
22
+ [outer, name].reject(&:empty?).join('::')
23
+ end
24
+
25
+ # The final section of the module or class name. For example, for a
26
+ # module with name 'Foo::Bar' this will return 'Bar'; for a module with
27
+ # name 'Foo' this will return 'Foo'.
28
+ #
29
+ # @return [String] the final section of the name
30
+ def simple_name
31
+ name.split('::').last
32
+ end
33
+
34
+ def name
35
+ SexpFormatter.format(children.first)
36
+ end
37
+ end
38
+
39
+ # Utility methods for :module nodes.
40
+ module ModuleNode
41
+ include ModuleNodeBase
42
+ end
43
+
44
+ # Utility methods for :class nodes.
45
+ module ClassNode
46
+ include ModuleNodeBase
47
+ def superclass() children[1] end
48
+ end
49
+
50
+ # Utility methods for :casgn nodes.
51
+ module CasgnNode
52
+ include ModuleNodeBase
53
+
54
+ def defines_module?
55
+ return false unless value
56
+ call = case value.type
57
+ when :block
58
+ value.call
59
+ when :send
60
+ value
61
+ end
62
+ call && call.module_creation_call?
63
+ end
64
+
65
+ def name
66
+ SexpFormatter.format(children[1])
67
+ end
68
+
69
+ # there are two valid forms of the casgn sexp
70
+ # (casgn <namespace> <name> <value>) and
71
+ # (casgn <namespace> <name>) used in or-asgn and mlhs
72
+ #
73
+ # source = "class Hi; THIS ||= 3; end"
74
+ # (class
75
+ # (const nil :Hi) nil
76
+ # (or-asgn
77
+ # (casgn nil :THIS)
78
+ # (int 3)))
79
+ def value
80
+ children[2]
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end