reek 2.1.0 → 2.2.0

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.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -21
  3. data/.travis.yml +1 -0
  4. data/.yardopts +3 -6
  5. data/CHANGELOG +6 -0
  6. data/CONTRIBUTING.md +8 -3
  7. data/README.md +94 -42
  8. data/config/defaults.reek +0 -1
  9. data/docs/API.md +50 -0
  10. data/docs/Attribute.md +43 -0
  11. data/docs/Basic-Smell-Options.md +44 -0
  12. data/docs/Boolean-Parameter.md +52 -0
  13. data/docs/Class-Variable.md +40 -0
  14. data/docs/Code-Smells.md +34 -0
  15. data/docs/Command-Line-Options.md +84 -0
  16. data/docs/Configuration-Files.md +38 -0
  17. data/docs/Control-Couple.md +22 -0
  18. data/docs/Control-Parameter.md +29 -0
  19. data/docs/Data-Clump.md +44 -0
  20. data/docs/Duplicate-Method-Call.md +49 -0
  21. data/docs/Feature-Envy.md +29 -0
  22. data/docs/How-reek-works-internally.md +44 -0
  23. data/docs/Irresponsible-Module.md +39 -0
  24. data/docs/Large-Class.md +20 -0
  25. data/docs/Long-Parameter-List.md +38 -0
  26. data/docs/Long-Yield-List.md +36 -0
  27. data/docs/Module-Initialize.md +62 -0
  28. data/docs/Nested-Iterators.md +38 -0
  29. data/docs/Nil-Check.md +39 -0
  30. data/docs/Prima-Donna-Method.md +53 -0
  31. data/docs/RSpec-matchers.md +133 -0
  32. data/docs/Rake-Task.md +58 -0
  33. data/docs/Reek-Driven-Development.md +45 -0
  34. data/docs/Repeated-Conditional.md +44 -0
  35. data/docs/Simulated-Polymorphism.md +16 -0
  36. data/docs/Smell-Suppression.md +32 -0
  37. data/docs/Too-Many-Instance-Variables.md +43 -0
  38. data/docs/Too-Many-Methods.md +55 -0
  39. data/docs/Too-Many-Statements.md +50 -0
  40. data/docs/Uncommunicative-Method-Name.md +24 -0
  41. data/docs/Uncommunicative-Module-Name.md +23 -0
  42. data/docs/Uncommunicative-Name.md +16 -0
  43. data/docs/Uncommunicative-Parameter-Name.md +24 -0
  44. data/docs/Uncommunicative-Variable-Name.md +24 -0
  45. data/docs/Unused-Parameters.md +27 -0
  46. data/docs/Utility-Function.md +46 -0
  47. data/docs/Versioning-Policy.md +7 -0
  48. data/docs/YAML-Reports.md +111 -0
  49. data/docs/yard_plugin.rb +14 -0
  50. data/features/command_line_interface/options.feature +1 -0
  51. data/features/programmatic_access.feature +1 -1
  52. data/features/samples.feature +3 -3
  53. data/lib/reek.rb +2 -2
  54. data/lib/reek/cli/input.rb +2 -2
  55. data/lib/reek/cli/option_interpreter.rb +2 -0
  56. data/lib/reek/cli/options.rb +10 -4
  57. data/lib/reek/cli/reek_command.rb +2 -2
  58. data/lib/reek/cli/report/report.rb +60 -0
  59. data/lib/reek/cli/silencer.rb +13 -0
  60. data/lib/reek/{source → core}/ast_node.rb +1 -1
  61. data/lib/reek/{source → core}/ast_node_class_map.rb +10 -11
  62. data/lib/reek/{source → core}/code_comment.rb +1 -1
  63. data/lib/reek/core/code_context.rb +1 -1
  64. data/lib/reek/core/examiner.rb +85 -0
  65. data/lib/reek/core/method_context.rb +1 -1
  66. data/lib/reek/core/module_context.rb +2 -2
  67. data/lib/reek/core/reference_collector.rb +31 -0
  68. data/lib/reek/core/singleton_method_context.rb +0 -4
  69. data/lib/reek/core/smell_repository.rb +4 -2
  70. data/lib/reek/{source → core}/tree_dresser.rb +1 -1
  71. data/lib/reek/{source → sexp}/sexp_extensions.rb +5 -5
  72. data/lib/reek/sexp/sexp_formatter.rb +29 -0
  73. data/lib/reek/sexp/sexp_node.rb +91 -0
  74. data/lib/reek/smells.rb +4 -2
  75. data/lib/reek/smells/attribute.rb +35 -7
  76. data/lib/reek/smells/boolean_parameter.rb +1 -1
  77. data/lib/reek/smells/class_variable.rb +1 -1
  78. data/lib/reek/smells/control_parameter.rb +1 -1
  79. data/lib/reek/smells/data_clump.rb +1 -1
  80. data/lib/reek/smells/duplicate_method_call.rb +12 -4
  81. data/lib/reek/smells/feature_envy.rb +1 -1
  82. data/lib/reek/smells/irresponsible_module.rb +3 -3
  83. data/lib/reek/smells/long_parameter_list.rb +1 -1
  84. data/lib/reek/smells/long_yield_list.rb +1 -1
  85. data/lib/reek/smells/module_initialize.rb +1 -1
  86. data/lib/reek/smells/nested_iterators.rb +1 -1
  87. data/lib/reek/smells/nil_check.rb +3 -2
  88. data/lib/reek/smells/prima_donna_method.rb +18 -11
  89. data/lib/reek/smells/repeated_conditional.rb +3 -3
  90. data/lib/reek/smells/smell_detector.rb +5 -1
  91. data/lib/reek/smells/smell_warning.rb +99 -0
  92. data/lib/reek/smells/too_many_instance_variables.rb +1 -1
  93. data/lib/reek/smells/too_many_methods.rb +1 -1
  94. data/lib/reek/smells/too_many_statements.rb +1 -1
  95. data/lib/reek/smells/uncommunicative_method_name.rb +1 -1
  96. data/lib/reek/smells/uncommunicative_module_name.rb +1 -1
  97. data/lib/reek/smells/uncommunicative_parameter_name.rb +1 -1
  98. data/lib/reek/smells/uncommunicative_variable_name.rb +1 -1
  99. data/lib/reek/smells/unused_parameters.rb +1 -1
  100. data/lib/reek/smells/utility_function.rb +3 -16
  101. data/lib/reek/source/source_code.rb +31 -13
  102. data/lib/reek/source/source_locator.rb +16 -17
  103. data/lib/reek/source/source_repository.rb +10 -11
  104. data/lib/reek/spec/should_reek.rb +2 -2
  105. data/lib/reek/spec/should_reek_of.rb +2 -2
  106. data/lib/reek/spec/should_reek_only_of.rb +2 -2
  107. data/lib/reek/version.rb +1 -1
  108. data/reek.gemspec +3 -4
  109. data/spec/factories/factories.rb +1 -1
  110. data/spec/gem/yard_spec.rb +1 -1
  111. data/spec/quality/reek_source_spec.rb +2 -2
  112. data/spec/reek/cli/html_report_spec.rb +3 -3
  113. data/spec/reek/cli/json_report_spec.rb +3 -3
  114. data/spec/reek/cli/{option_interperter_spec.rb → option_interpreter_spec.rb} +1 -1
  115. data/spec/reek/cli/options_spec.rb +19 -0
  116. data/spec/reek/cli/text_report_spec.rb +7 -7
  117. data/spec/reek/cli/xml_report_spec.rb +34 -0
  118. data/spec/reek/cli/yaml_report_spec.rb +3 -3
  119. data/spec/reek/configuration/app_configuration_spec.rb +1 -1
  120. data/spec/reek/configuration/configuration_file_finder_spec.rb +22 -1
  121. data/spec/reek/{source → core}/code_comment_spec.rb +14 -14
  122. data/spec/reek/core/code_context_spec.rb +1 -1
  123. data/spec/reek/{examiner_spec.rb → core/examiner_spec.rb} +12 -12
  124. data/spec/reek/core/method_context_spec.rb +27 -22
  125. data/spec/reek/core/module_context_spec.rb +2 -2
  126. data/spec/reek/core/object_refs_spec.rb +1 -1
  127. data/spec/reek/{source → core}/object_source_spec.rb +1 -1
  128. data/spec/reek/{source → core}/reference_collector_spec.rb +25 -16
  129. data/spec/reek/core/singleton_method_context_spec.rb +12 -2
  130. data/spec/reek/core/smell_configuration_spec.rb +1 -1
  131. data/spec/reek/core/smell_repository_spec.rb +12 -1
  132. data/spec/reek/core/stop_context_spec.rb +1 -1
  133. data/spec/reek/core/tree_dresser_spec.rb +16 -0
  134. data/spec/reek/core/tree_walker_spec.rb +3 -3
  135. data/spec/reek/core/warning_collector_spec.rb +6 -6
  136. data/spec/reek/{source → sexp}/sexp_extensions_spec.rb +8 -8
  137. data/spec/reek/{source → sexp}/sexp_formatter_spec.rb +11 -5
  138. data/spec/reek/{source → sexp}/sexp_node_spec.rb +3 -3
  139. data/spec/reek/smells/attribute_spec.rb +89 -85
  140. data/spec/reek/smells/behaves_like_variable_detector.rb +1 -1
  141. data/spec/reek/smells/boolean_parameter_spec.rb +1 -1
  142. data/spec/reek/smells/class_variable_spec.rb +1 -1
  143. data/spec/reek/smells/control_parameter_spec.rb +1 -1
  144. data/spec/reek/smells/data_clump_spec.rb +2 -2
  145. data/spec/reek/smells/duplicate_method_call_spec.rb +1 -1
  146. data/spec/reek/smells/feature_envy_spec.rb +2 -2
  147. data/spec/reek/smells/irresponsible_module_spec.rb +1 -1
  148. data/spec/reek/smells/long_parameter_list_spec.rb +2 -2
  149. data/spec/reek/smells/long_yield_list_spec.rb +1 -1
  150. data/spec/reek/smells/module_initialize_spec.rb +1 -1
  151. data/spec/reek/smells/nested_iterators_spec.rb +2 -2
  152. data/spec/reek/smells/nil_check_spec.rb +1 -1
  153. data/spec/reek/smells/prima_donna_method_spec.rb +1 -1
  154. data/spec/reek/smells/repeated_conditional_spec.rb +1 -1
  155. data/spec/reek/smells/smell_detector_shared.rb +2 -2
  156. data/spec/reek/{smell_warning_spec.rb → smells/smell_warning_spec.rb} +7 -7
  157. data/spec/reek/smells/too_many_instance_variables_spec.rb +1 -1
  158. data/spec/reek/smells/too_many_methods_spec.rb +1 -1
  159. data/spec/reek/smells/too_many_statements_spec.rb +4 -4
  160. data/spec/reek/smells/uncommunicative_method_name_spec.rb +1 -1
  161. data/spec/reek/smells/uncommunicative_module_name_spec.rb +1 -1
  162. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +1 -1
  163. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +1 -1
  164. data/spec/reek/smells/unused_parameters_spec.rb +1 -1
  165. data/spec/reek/smells/utility_function_spec.rb +1 -1
  166. data/spec/reek/source/source_code_spec.rb +1 -1
  167. data/spec/reek/spec/should_reek_of_spec.rb +1 -1
  168. data/spec/reek/spec/should_reek_only_of_spec.rb +1 -1
  169. data/spec/reek/spec/should_reek_spec.rb +1 -1
  170. data/spec/samples/checkstyle.xml +2 -0
  171. data/spec/spec_helper.rb +15 -3
  172. metadata +68 -38
  173. data/.ruby-gemset +0 -1
  174. data/lib/reek/examiner.rb +0 -79
  175. data/lib/reek/smell_warning.rb +0 -87
  176. data/lib/reek/source/reference_collector.rb +0 -27
  177. data/lib/reek/source/sexp_formatter.rb +0 -22
  178. data/lib/reek/source/sexp_node.rb +0 -79
  179. data/spec/reek/source/tree_dresser_spec.rb +0 -16
data/.ruby-gemset DELETED
@@ -1 +0,0 @@
1
- reek
data/lib/reek/examiner.rb DELETED
@@ -1,79 +0,0 @@
1
- require_relative 'source/source_repository'
2
- require_relative 'core/warning_collector'
3
- require_relative 'core/smell_repository'
4
- require_relative 'core/tree_walker'
5
-
6
- module Reek
7
- #
8
- # Applies all available smell detectors to a source.
9
- #
10
- class Examiner
11
- #
12
- # A simple description of the source being analysed for smells.
13
- # If the source is a single File, this will be the file's path.
14
- #
15
- attr_accessor :description
16
-
17
- #
18
- # Creates an Examiner which scans the given +source+ for code smells.
19
- #
20
- # @param [Source::SourceCode, Array<String>, #to_reek_source]
21
- # If +source+ is a String it is assumed to be Ruby source code;
22
- # if it is a File, the file is opened and parsed for Ruby source code;
23
- # and if it is an Array, it is assumed to be a list of file paths,
24
- # each of which is opened and parsed for source code.
25
- #
26
- def initialize(source, smell_types_to_filter_by = [])
27
- @sources = Source::SourceRepository.parse(source)
28
- @description = @sources.description
29
- @collector = Core::WarningCollector.new
30
- @smell_types = eligible_smell_types(smell_types_to_filter_by)
31
-
32
- run
33
- end
34
-
35
- #
36
- # List the smells found in the source.
37
- #
38
- # @return [Array<SmellWarning>]
39
- #
40
- def smells
41
- @smells ||= @collector.warnings
42
- end
43
-
44
- #
45
- # Returns the number of smells found in the source
46
- #
47
- def smells_count
48
- smells.length
49
- end
50
-
51
- #
52
- # True if and only if there are code smells in the source.
53
- #
54
- def smelly?
55
- !smells.empty?
56
- end
57
-
58
- private
59
-
60
- def run
61
- @sources.each do |source|
62
- smell_repository = Core::SmellRepository.new(source.desc, @smell_types)
63
- syntax_tree = source.syntax_tree
64
- Core::TreeWalker.new(smell_repository).process(syntax_tree) if syntax_tree
65
- smell_repository.report_on(@collector)
66
- end
67
- end
68
-
69
- def eligible_smell_types(smell_types_to_filter_by = [])
70
- if smell_types_to_filter_by.any?
71
- Core::SmellRepository.smell_types.select do |klass|
72
- smell_types_to_filter_by.include? klass.smell_type
73
- end
74
- else
75
- Core::SmellRepository.smell_types
76
- end
77
- end
78
- end
79
- end
@@ -1,87 +0,0 @@
1
- require 'forwardable'
2
-
3
- module Reek
4
- #
5
- # Reports a warning that a smell has been found.
6
- #
7
- class SmellWarning
8
- include Comparable
9
- extend Forwardable
10
- attr_accessor :smell_detector, :context, :lines, :message, :parameters
11
- def_delegators :smell_detector, :smell_category, :smell_type, :source
12
-
13
- def initialize(smell_detector, options = {})
14
- self.smell_detector = smell_detector
15
- self.context = options.fetch(:context, '').to_s
16
- self.lines = options.fetch(:lines)
17
- self.message = options.fetch(:message)
18
- self.parameters = options.fetch(:parameters, {})
19
- end
20
-
21
- def smell_classes
22
- [smell_detector.smell_category, smell_detector.smell_type]
23
- end
24
-
25
- def hash
26
- sort_key.hash
27
- end
28
-
29
- def <=>(other)
30
- sort_key <=> other.sort_key
31
- end
32
-
33
- def eql?(other)
34
- (self <=> other) == 0
35
- end
36
-
37
- def matches?(klass, other_parameters = {})
38
- smell_classes.include?(klass.to_s) && common_parameters_equal?(other_parameters)
39
- end
40
-
41
- def report_on(listener)
42
- listener.found_smell(self)
43
- end
44
-
45
- def yaml_hash(warning_formatter = nil)
46
- result = {
47
- 'smell_category' => smell_detector.smell_category,
48
- 'smell_type' => smell_detector.smell_type,
49
- 'source' => smell_detector.source,
50
- 'context' => context,
51
- 'lines' => lines,
52
- 'message' => message
53
- }
54
- if warning_formatter.respond_to?(:explanatory_link)
55
- result.merge!('wiki_link' => warning_formatter.explanatory_link(smell_detector))
56
- end
57
- parameters.each do |key, value|
58
- result[key.to_s] = value
59
- end
60
- result
61
- end
62
-
63
- protected
64
-
65
- def sort_key
66
- [context, message, smell_category]
67
- end
68
-
69
- def common_parameters_equal?(other_parameters)
70
- other_parameters.keys.each do |key|
71
- unless parameters.key?(key)
72
- raise ArgumentError, "The parameter #{key} you want to check for doesn't exist"
73
- end
74
- end
75
-
76
- # Why not check for strict parameter equality instead of just the common ones?
77
- #
78
- # In `self`, `parameters` might look like this: {:name=>"@other.thing", :count=>2}
79
- # Coming from specs, 'other_parameters' might look like this, e.g.:
80
- # {:name=>"@other.thing"}
81
- # So in this spec we are just specifying the "name" parameter but not the "count".
82
- # In order to allow for this kind of leniency we just test for common parameter equality,
83
- # not for a strict one.
84
- parameters.values_at(*other_parameters.keys) == other_parameters.values
85
- end
86
- end
87
- end
@@ -1,27 +0,0 @@
1
-
2
- module Reek
3
- module Source
4
- #
5
- # Locates references to the current object within a portion
6
- # of an abstract syntax tree.
7
- #
8
- class ReferenceCollector
9
- STOP_NODES = [:class, :module, :def, :defs]
10
-
11
- def initialize(ast)
12
- @ast = ast
13
- end
14
-
15
- def num_refs_to_self
16
- result = 0
17
- [:self, :zsuper, :ivar, :ivasgn].each do |node_type|
18
- @ast.look_for(node_type, STOP_NODES) { result += 1 }
19
- end
20
- @ast.look_for(:send, STOP_NODES) do |call|
21
- result += 1 unless call.receiver
22
- end
23
- result
24
- end
25
- end
26
- end
27
- end
@@ -1,22 +0,0 @@
1
- old_verbose, $VERBOSE = $VERBOSE, nil
2
- require 'unparser'
3
- $VERBOSE = old_verbose
4
-
5
- module Reek
6
- module Source
7
- #
8
- # Formats snippets of syntax tree back into Ruby source code.
9
- #
10
- class SexpFormatter
11
- def self.format(sexp)
12
- return sexp.to_s unless sexp.is_a? AST::Node
13
- lines = Unparser.unparse(sexp).split "\n"
14
- if lines.length > 1
15
- "#{lines.first} ... #{lines.last}"
16
- else
17
- lines.first
18
- end
19
- end
20
- end
21
- end
22
- end
@@ -1,79 +0,0 @@
1
- module Reek
2
- module Source
3
- #
4
- # Extensions to +Sexp+ to allow +TreeWalker+ to navigate the abstract
5
- # syntax tree more easily.
6
- #
7
- module SexpNode
8
- def self.format(expr)
9
- case expr
10
- when AST::Node then expr.format_ruby
11
- else expr.to_s
12
- end
13
- end
14
-
15
- def hash
16
- inspect.hash
17
- end
18
-
19
- def each_node(type, ignoring = [], &blk)
20
- if block_given?
21
- look_for(type, ignoring, &blk)
22
- else
23
- result = []
24
- look_for(type, ignoring) { |exp| result << exp }
25
- result
26
- end
27
- end
28
-
29
- def find_nodes(types, ignoring = [])
30
- result = []
31
- look_for_alt(types, ignoring) { |exp| result << exp }
32
- result
33
- end
34
-
35
- def each_sexp
36
- children.each { |elem| yield elem if elem.is_a? AST::Node }
37
- end
38
-
39
- #
40
- # Carries out a depth-first traversal of this syntax tree, yielding
41
- # every Sexp of type +target_type+. The traversal ignores any node
42
- # whose type is listed in the Array +ignoring+.
43
- #
44
- def look_for(target_type, ignoring = [], &blk)
45
- each_sexp do |elem|
46
- elem.look_for(target_type, ignoring, &blk) unless ignoring.include?(elem.type)
47
- end
48
- blk.call(self) if type == target_type
49
- end
50
-
51
- #
52
- # Carries out a depth-first traversal of this syntax tree, yielding
53
- # every Sexp of type +target_type+. The traversal ignores any node
54
- # whose type is listed in the Array +ignoring+, includeing the top node.
55
- #
56
- # Also, doesn't nest
57
- #
58
- def look_for_alt(target_types, ignoring = [], &blk)
59
- return if ignoring.include?(type)
60
- if target_types.include? type
61
- blk.call(self)
62
- else
63
- each_sexp do |elem|
64
- elem.look_for_alt(target_types, ignoring, &blk)
65
- end
66
- end
67
- end
68
-
69
- def contains_nested_node?(target_type)
70
- look_for(target_type) { |_elem| return true }
71
- false
72
- end
73
-
74
- def format_ruby
75
- SexpFormatter.format(self)
76
- end
77
- end
78
- end
79
- end
@@ -1,16 +0,0 @@
1
- require_relative '../../spec_helper'
2
- require_relative '../../../lib/reek/source/tree_dresser'
3
-
4
- describe Reek::Source::TreeDresser do
5
- let(:ifnode) { Parser::AST::Node.new(:if) }
6
- let(:sendnode) { Parser::AST::Node.new(:send) }
7
- let(:dresser) { Reek::Source::TreeDresser.new }
8
-
9
- it 'dresses :if sexp with IfNode' do
10
- expect(dresser.dress(ifnode, {})).to be_a Reek::Source::SexpExtensions::IfNode
11
- end
12
-
13
- it 'dresses :send sexp with SendNode' do
14
- expect(dresser.dress(sendnode, {})).to be_a Reek::Source::SexpExtensions::SendNode
15
- end
16
- end