reek 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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