reek 2.0.4 → 3.0.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 (275) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +13 -0
  3. data/.rubocop.yml +47 -0
  4. data/.travis.yml +31 -0
  5. data/.yardopts +3 -6
  6. data/CHANGELOG +24 -0
  7. data/CONTRIBUTING.md +111 -0
  8. data/Gemfile +16 -0
  9. data/README.md +112 -59
  10. data/bin/reek +2 -2
  11. data/config/cucumber.yml +3 -0
  12. data/config/defaults.reek +0 -1
  13. data/docs/API.md +79 -0
  14. data/docs/Attribute.md +43 -0
  15. data/docs/Basic-Smell-Options.md +44 -0
  16. data/docs/Boolean-Parameter.md +52 -0
  17. data/docs/Class-Variable.md +40 -0
  18. data/docs/Code-Smells.md +34 -0
  19. data/docs/Command-Line-Options.md +84 -0
  20. data/docs/Configuration-Files.md +49 -0
  21. data/docs/Control-Couple.md +22 -0
  22. data/docs/Control-Parameter.md +29 -0
  23. data/docs/Data-Clump.md +44 -0
  24. data/docs/Duplicate-Method-Call.md +49 -0
  25. data/docs/Feature-Envy.md +49 -0
  26. data/docs/How-reek-works-internally.md +114 -0
  27. data/docs/Irresponsible-Module.md +39 -0
  28. data/docs/Large-Class.md +20 -0
  29. data/docs/Long-Parameter-List.md +38 -0
  30. data/docs/Long-Yield-List.md +36 -0
  31. data/docs/Module-Initialize.md +62 -0
  32. data/docs/Nested-Iterators.md +38 -0
  33. data/docs/Nil-Check.md +39 -0
  34. data/docs/Prima-Donna-Method.md +53 -0
  35. data/docs/RSpec-matchers.md +137 -0
  36. data/docs/Rake-Task.md +58 -0
  37. data/docs/Reek-Driven-Development.md +37 -0
  38. data/docs/Repeated-Conditional.md +44 -0
  39. data/docs/Simulated-Polymorphism.md +16 -0
  40. data/docs/Smell-Suppression.md +32 -0
  41. data/docs/Too-Many-Instance-Variables.md +43 -0
  42. data/docs/Too-Many-Methods.md +55 -0
  43. data/docs/Too-Many-Statements.md +50 -0
  44. data/docs/Uncommunicative-Method-Name.md +24 -0
  45. data/docs/Uncommunicative-Module-Name.md +23 -0
  46. data/docs/Uncommunicative-Name.md +16 -0
  47. data/docs/Uncommunicative-Parameter-Name.md +24 -0
  48. data/docs/Uncommunicative-Variable-Name.md +24 -0
  49. data/docs/Unused-Parameters.md +27 -0
  50. data/docs/Utility-Function.md +44 -0
  51. data/docs/Versioning-Policy.md +7 -0
  52. data/docs/YAML-Reports.md +111 -0
  53. data/docs/yard_plugin.rb +14 -0
  54. data/features/{ruby_api/api.feature → command_line_interface/basic_usage.feature} +6 -5
  55. data/features/command_line_interface/options.feature +1 -0
  56. data/features/command_line_interface/smell_selection.feature +4 -8
  57. data/features/command_line_interface/smells_count.feature +25 -32
  58. data/features/command_line_interface/stdin.feature +2 -2
  59. data/features/configuration_files/masking_smells.feature +30 -41
  60. data/features/configuration_files/overrides_defaults.feature +5 -3
  61. data/features/configuration_loading.feature +26 -23
  62. data/features/programmatic_access.feature +43 -0
  63. data/features/rake_task/rake_task.feature +25 -22
  64. data/features/reports/json.feature +24 -26
  65. data/features/reports/reports.feature +77 -103
  66. data/features/reports/yaml.feature +26 -20
  67. data/features/samples.feature +26 -31
  68. data/features/step_definitions/.rubocop.yml +5 -0
  69. data/features/step_definitions/reek_steps.rb +16 -28
  70. data/features/step_definitions/sample_file_steps.rb +158 -0
  71. data/features/support/env.rb +16 -27
  72. data/lib/reek/{source → ast}/ast_node_class_map.rb +11 -12
  73. data/lib/reek/ast/node.rb +132 -0
  74. data/lib/reek/{core → ast}/object_refs.rb +2 -1
  75. data/lib/reek/ast/reference_collector.rb +32 -0
  76. data/lib/reek/{source → ast}/sexp_extensions.rb +43 -7
  77. data/lib/reek/ast/sexp_formatter.rb +31 -0
  78. data/lib/reek/cli/application.rb +5 -4
  79. data/lib/reek/cli/command.rb +2 -1
  80. data/lib/reek/cli/input.rb +6 -5
  81. data/lib/reek/cli/option_interpreter.rb +13 -9
  82. data/lib/reek/cli/options.rb +16 -8
  83. data/lib/reek/cli/reek_command.rb +4 -3
  84. data/lib/reek/cli/silencer.rb +14 -0
  85. data/lib/reek/{core → cli}/warning_collector.rb +2 -1
  86. data/lib/reek/code_comment.rb +36 -0
  87. data/lib/reek/configuration/app_configuration.rb +18 -3
  88. data/lib/reek/configuration/configuration_file_finder.rb +18 -32
  89. data/lib/reek/{core → context}/code_context.rb +8 -6
  90. data/lib/reek/{core → context}/method_context.rb +11 -5
  91. data/lib/reek/{core → context}/module_context.rb +9 -4
  92. data/lib/reek/{core/stop_context.rb → context/root_context.rb} +4 -2
  93. data/lib/reek/{core → context}/singleton_method_context.rb +3 -6
  94. data/lib/reek/examiner.rb +32 -29
  95. data/lib/reek/report/formatter.rb +70 -0
  96. data/lib/reek/report/heading_formatter.rb +45 -0
  97. data/lib/reek/report/location_formatter.rb +35 -0
  98. data/lib/reek/report/report.rb +198 -0
  99. data/lib/reek/smells/attribute.rb +41 -11
  100. data/lib/reek/smells/boolean_parameter.rb +4 -2
  101. data/lib/reek/smells/class_variable.rb +4 -2
  102. data/lib/reek/smells/control_parameter.rb +4 -2
  103. data/lib/reek/smells/data_clump.rb +4 -3
  104. data/lib/reek/smells/duplicate_method_call.rb +15 -5
  105. data/lib/reek/smells/feature_envy.rb +8 -2
  106. data/lib/reek/smells/irresponsible_module.rb +13 -8
  107. data/lib/reek/smells/long_parameter_list.rb +6 -4
  108. data/lib/reek/smells/long_yield_list.rb +4 -2
  109. data/lib/reek/smells/module_initialize.rb +4 -2
  110. data/lib/reek/smells/nested_iterators.rb +4 -2
  111. data/lib/reek/smells/nil_check.rb +6 -3
  112. data/lib/reek/smells/prima_donna_method.rb +21 -12
  113. data/lib/reek/smells/repeated_conditional.rb +7 -4
  114. data/lib/reek/{core → smells}/smell_configuration.rb +3 -1
  115. data/lib/reek/smells/smell_detector.rb +11 -5
  116. data/lib/reek/{core → smells}/smell_repository.rb +9 -5
  117. data/lib/reek/smells/smell_warning.rb +101 -0
  118. data/lib/reek/smells/too_many_instance_variables.rb +4 -2
  119. data/lib/reek/smells/too_many_methods.rb +4 -2
  120. data/lib/reek/smells/too_many_statements.rb +4 -2
  121. data/lib/reek/smells/uncommunicative_method_name.rb +4 -2
  122. data/lib/reek/smells/uncommunicative_module_name.rb +4 -2
  123. data/lib/reek/smells/uncommunicative_parameter_name.rb +4 -2
  124. data/lib/reek/smells/uncommunicative_variable_name.rb +4 -2
  125. data/lib/reek/smells/unused_parameters.rb +4 -2
  126. data/lib/reek/smells/utility_function.rb +11 -22
  127. data/lib/reek/smells.rb +24 -11
  128. data/lib/reek/source/source_code.rb +69 -12
  129. data/lib/reek/source/source_locator.rb +34 -19
  130. data/lib/reek/spec/should_reek.rb +4 -3
  131. data/lib/reek/spec/should_reek_of.rb +2 -1
  132. data/lib/reek/spec/should_reek_only_of.rb +4 -3
  133. data/lib/reek/spec.rb +3 -3
  134. data/lib/reek/tree_dresser.rb +32 -0
  135. data/lib/reek/tree_walker.rb +182 -0
  136. data/lib/reek/version.rb +1 -1
  137. data/lib/reek.rb +3 -3
  138. data/reek.gemspec +18 -25
  139. data/spec/factories/factories.rb +4 -2
  140. data/spec/gem/updates_spec.rb +1 -1
  141. data/spec/gem/yard_spec.rb +2 -2
  142. data/spec/quality/reek_source_spec.rb +3 -3
  143. data/spec/reek/{source/sexp_node_spec.rb → ast/node_spec.rb} +4 -6
  144. data/spec/reek/{core → ast}/object_refs_spec.rb +4 -6
  145. data/spec/reek/{source → ast}/reference_collector_spec.rb +27 -19
  146. data/spec/reek/{source → ast}/sexp_extensions_spec.rb +7 -19
  147. data/spec/reek/{source → ast}/sexp_formatter_spec.rb +13 -8
  148. data/spec/reek/cli/option_interpreter_spec.rb +15 -0
  149. data/spec/reek/cli/options_spec.rb +19 -0
  150. data/spec/reek/cli/warning_collector_spec.rb +28 -0
  151. data/spec/reek/{source/code_comment_spec.rb → code_comment_spec.rb} +19 -17
  152. data/spec/reek/configuration/app_configuration_spec.rb +37 -26
  153. data/spec/reek/configuration/configuration_file_finder_spec.rb +67 -21
  154. data/spec/reek/{core → context}/code_context_spec.rb +18 -21
  155. data/spec/reek/{core → context}/method_context_spec.rb +33 -27
  156. data/spec/reek/{core → context}/module_context_spec.rb +5 -7
  157. data/spec/reek/context/root_context_spec.rb +14 -0
  158. data/spec/reek/context/singleton_method_context_spec.rb +17 -0
  159. data/spec/reek/examiner_spec.rb +9 -50
  160. data/spec/reek/{cli → report}/html_report_spec.rb +6 -9
  161. data/spec/reek/report/json_report_spec.rb +20 -0
  162. data/spec/reek/{cli → report}/text_report_spec.rb +16 -19
  163. data/spec/reek/report/xml_report_spec.rb +34 -0
  164. data/spec/reek/report/yaml_report_spec.rb +20 -0
  165. data/spec/reek/smells/attribute_spec.rb +93 -88
  166. data/spec/reek/smells/behaves_like_variable_detector.rb +1 -1
  167. data/spec/reek/smells/boolean_parameter_spec.rb +31 -5
  168. data/spec/reek/smells/class_variable_spec.rb +10 -10
  169. data/spec/reek/smells/control_parameter_spec.rb +5 -5
  170. data/spec/reek/smells/data_clump_spec.rb +6 -6
  171. data/spec/reek/smells/duplicate_method_call_spec.rb +7 -7
  172. data/spec/reek/smells/feature_envy_spec.rb +12 -13
  173. data/spec/reek/smells/irresponsible_module_spec.rb +28 -32
  174. data/spec/reek/smells/long_parameter_list_spec.rb +7 -7
  175. data/spec/reek/smells/long_yield_list_spec.rb +6 -6
  176. data/spec/reek/smells/module_initialize_spec.rb +4 -4
  177. data/spec/reek/smells/nested_iterators_spec.rb +6 -6
  178. data/spec/reek/smells/nil_check_spec.rb +6 -6
  179. data/spec/reek/smells/prima_donna_method_spec.rb +8 -5
  180. data/spec/reek/smells/repeated_conditional_spec.rb +18 -17
  181. data/spec/reek/{core → smells}/smell_configuration_spec.rb +5 -7
  182. data/spec/reek/smells/smell_detector_shared.rb +6 -7
  183. data/spec/reek/smells/smell_repository_spec.rb +29 -0
  184. data/spec/reek/{smell_warning_spec.rb → smells/smell_warning_spec.rb} +7 -9
  185. data/spec/reek/smells/too_many_instance_variables_spec.rb +5 -5
  186. data/spec/reek/smells/too_many_methods_spec.rb +12 -8
  187. data/spec/reek/smells/too_many_statements_spec.rb +10 -9
  188. data/spec/reek/smells/uncommunicative_method_name_spec.rb +5 -5
  189. data/spec/reek/smells/uncommunicative_module_name_spec.rb +8 -8
  190. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +18 -6
  191. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +10 -7
  192. data/spec/reek/smells/unused_parameters_spec.rb +4 -4
  193. data/spec/reek/smells/utility_function_spec.rb +65 -39
  194. data/spec/reek/source/source_code_spec.rb +10 -10
  195. data/spec/reek/source/source_locator_spec.rb +30 -0
  196. data/spec/reek/spec/should_reek_of_spec.rb +9 -25
  197. data/spec/reek/spec/should_reek_only_of_spec.rb +4 -7
  198. data/spec/reek/spec/should_reek_spec.rb +4 -32
  199. data/spec/reek/tree_dresser_spec.rb +16 -0
  200. data/spec/reek/{core/tree_walker_spec.rb → tree_walker_spec.rb} +5 -7
  201. data/spec/samples/checkstyle.xml +2 -0
  202. data/spec/samples/configuration/with_excluded_paths.reek +4 -0
  203. data/spec/samples/{overrides/masked/lower.reek → masked_by_dotfile/.reek} +3 -1
  204. data/spec/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +5 -0
  205. data/spec/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +2 -0
  206. data/spec/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +6 -0
  207. data/spec/samples/{ruby20_syntax.rb → unusual_syntax.rb} +8 -0
  208. data/spec/spec_helper.rb +21 -10
  209. data/tasks/develop.rake +2 -2
  210. data/tasks/reek.rake +1 -1
  211. metadata +158 -141
  212. data/features/support/hooks.rb +0 -15
  213. data/lib/reek/cli/report/formatter.rb +0 -69
  214. data/lib/reek/cli/report/heading_formatter.rb +0 -45
  215. data/lib/reek/cli/report/location_formatter.rb +0 -34
  216. data/lib/reek/cli/report/report.rb +0 -131
  217. data/lib/reek/core/tree_walker.rb +0 -180
  218. data/lib/reek/smell_warning.rb +0 -87
  219. data/lib/reek/source/ast_node.rb +0 -38
  220. data/lib/reek/source/code_comment.rb +0 -37
  221. data/lib/reek/source/core_extras.rb +0 -46
  222. data/lib/reek/source/reference_collector.rb +0 -27
  223. data/lib/reek/source/sexp_formatter.rb +0 -22
  224. data/lib/reek/source/sexp_node.rb +0 -79
  225. data/lib/reek/source/source_file.rb +0 -16
  226. data/lib/reek/source/source_repository.rb +0 -45
  227. data/lib/reek/source/tree_dresser.rb +0 -24
  228. data/lib/reek/source.rb +0 -16
  229. data/spec/reek/cli/json_report_spec.rb +0 -20
  230. data/spec/reek/cli/option_interperter_spec.rb +0 -14
  231. data/spec/reek/cli/yaml_report_spec.rb +0 -23
  232. data/spec/reek/core/singleton_method_context_spec.rb +0 -9
  233. data/spec/reek/core/smell_repository_spec.rb +0 -17
  234. data/spec/reek/core/stop_context_spec.rb +0 -17
  235. data/spec/reek/core/warning_collector_spec.rb +0 -30
  236. data/spec/reek/source/object_source_spec.rb +0 -20
  237. data/spec/reek/source/tree_dresser_spec.rb +0 -18
  238. data/spec/samples/config/allow_duplication.reek +0 -3
  239. data/spec/samples/config/deeper_nested_iterators.reek +0 -3
  240. data/spec/samples/configuration_loading/minimal_dirty.rb +0 -4
  241. data/spec/samples/configuration_loading/reek-test-run-disable_smells.reek +0 -7
  242. data/spec/samples/configuration_loading/reek-test-run-enable_smells.reek +0 -7
  243. data/spec/samples/corrupt_config_file/corrupt.reek +0 -1
  244. data/spec/samples/corrupt_config_file/dirty.rb +0 -8
  245. data/spec/samples/demo/demo.rb +0 -8
  246. data/spec/samples/empty_config_file/dirty.rb +0 -8
  247. data/spec/samples/empty_config_file/empty.reek +0 -0
  248. data/spec/samples/inline_config/dirty.rb +0 -16
  249. data/spec/samples/inline_config/masked.reek +0 -7
  250. data/spec/samples/mask_some/dirty.rb +0 -8
  251. data/spec/samples/mask_some/some.reek +0 -8
  252. data/spec/samples/masked/dirty.rb +0 -8
  253. data/spec/samples/masked/masked.reek +0 -5
  254. data/spec/samples/minimal_smelly_and_masked/config.reek +0 -7
  255. data/spec/samples/minimal_smelly_and_masked/minimal_dirty.rb +0 -4
  256. data/spec/samples/mixed_results/clean_one.rb +0 -7
  257. data/spec/samples/mixed_results/clean_three.rb +0 -7
  258. data/spec/samples/mixed_results/clean_two.rb +0 -7
  259. data/spec/samples/mixed_results/dirty_one.rb +0 -8
  260. data/spec/samples/mixed_results/dirty_two.rb +0 -8
  261. data/spec/samples/not_quite_masked/dirty.rb +0 -8
  262. data/spec/samples/not_quite_masked/masked.reek +0 -5
  263. data/spec/samples/not_quite_masked/smelly.rb +0 -3
  264. data/spec/samples/one_smelly_file/dirty.rb +0 -3
  265. data/spec/samples/overrides/masked/dirty.rb +0 -8
  266. data/spec/samples/overrides/upper.reek +0 -5
  267. data/spec/samples/overrides_defaults/camel_case.rb +0 -14
  268. data/spec/samples/overrides_defaults/config.reek +0 -6
  269. data/spec/samples/ruby21_syntax.rb +0 -5
  270. data/spec/samples/standard_smelly/dirty.rb +0 -8
  271. data/spec/samples/standard_smelly/minimal_dirty.rb +0 -4
  272. data/spec/samples/three_smelly_files/dirty_one.rb +0 -3
  273. data/spec/samples/three_smelly_files/dirty_three.rb +0 -5
  274. data/spec/samples/three_smelly_files/dirty_two.rb +0 -4
  275. /data/spec/samples/{simple_configuration.reek → configuration/simple_configuration.reek} +0 -0
@@ -1,11 +1,12 @@
1
- require 'reek/examiner'
2
- require 'reek/cli/report/formatter'
1
+ require_relative '../examiner'
2
+ require_relative '../report/formatter'
3
3
 
4
4
  module Reek
5
5
  module Spec
6
6
  #
7
7
  # An rspec matcher that matches when the +actual+ has code smells.
8
8
  #
9
+ # @api private
9
10
  class ShouldReek # :nodoc:
10
11
  def matches?(actual)
11
12
  @examiner = Examiner.new(actual)
@@ -17,7 +18,7 @@ module Reek
17
18
  end
18
19
 
19
20
  def failure_message_when_negated
20
- rpt = Cli::Report::Formatter.format_list(@examiner.smells)
21
+ rpt = Report::Formatter.format_list(@examiner.smells)
21
22
  "Expected no smells, but got:\n#{rpt}"
22
23
  end
23
24
  end
@@ -1,4 +1,4 @@
1
- require 'reek/examiner'
1
+ require_relative '../examiner'
2
2
 
3
3
  module Reek
4
4
  module Spec
@@ -6,6 +6,7 @@ module Reek
6
6
  # An rspec matcher that matches when the +actual+ has the specified
7
7
  # code smell.
8
8
  #
9
+ # @api private
9
10
  class ShouldReekOf
10
11
  def initialize(smell_category, smell_details = {})
11
12
  @smell_category = normalize smell_category
@@ -1,5 +1,5 @@
1
- require 'reek/examiner'
2
- require 'reek/cli/report/formatter'
1
+ require_relative '../examiner'
2
+ require_relative '../report/formatter'
3
3
 
4
4
  module Reek
5
5
  module Spec
@@ -7,6 +7,7 @@ module Reek
7
7
  # An rspec matcher that matches when the +actual+ has the specified
8
8
  # code smell and no others.
9
9
  #
10
+ # @api private
10
11
  class ShouldReekOnlyOf < ShouldReekOf
11
12
  def matches?(actual)
12
13
  matches_examiner?(Examiner.new(actual))
@@ -20,7 +21,7 @@ module Reek
20
21
  end
21
22
 
22
23
  def failure_message
23
- rpt = Cli::Report::Formatter.format_list(@warnings)
24
+ rpt = Report::Formatter.format_list(@warnings)
24
25
  "Expected #{@examiner.description} to reek only of #{@smell_category}, but got:\n#{rpt}"
25
26
  end
26
27
 
data/lib/reek/spec.rb CHANGED
@@ -1,6 +1,6 @@
1
- require 'reek/spec/should_reek'
2
- require 'reek/spec/should_reek_of'
3
- require 'reek/spec/should_reek_only_of'
1
+ require_relative 'spec/should_reek'
2
+ require_relative 'spec/should_reek_of'
3
+ require_relative 'spec/should_reek_only_of'
4
4
 
5
5
  module Reek
6
6
  #
@@ -0,0 +1,32 @@
1
+ require_relative 'ast/ast_node_class_map'
2
+
3
+ module Reek
4
+ #
5
+ # Adorns an abstract syntax tree with mix-in modules to make accessing
6
+ # the tree more understandable and less implementation-dependent.
7
+ #
8
+ # @api private
9
+ class TreeDresser
10
+ def initialize(klass_map = AST::ASTNodeClassMap.new)
11
+ @klass_map = klass_map
12
+ end
13
+
14
+ # Recursively enhance an AST with type-dependent mixins, and comments.
15
+ #
16
+ # See {file:docs/How-reek-works-internally.md} for the big picture of how this works.
17
+ #
18
+ # @param sexp [Parser::AST::Node] - the given sexp
19
+ # @param comment_map [Hash] - see the documentation for SourceCode#syntax_tree
20
+ # @param parent [Parser::AST::Node] - the parent sexp
21
+ #
22
+ # @return an instance of Reek::AST::Node with type-dependent sexp extensions mixed in.
23
+ def dress(sexp, comment_map, parent = nil)
24
+ return sexp unless sexp.is_a? ::Parser::AST::Node
25
+ type = sexp.type
26
+ children = sexp.children.map { |child| dress(child, comment_map, sexp) }
27
+ comments = comment_map[sexp]
28
+ @klass_map.klass_for(type).new(type, children,
29
+ location: sexp.loc, comments: comments, parent: parent)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,182 @@
1
+ require_relative 'context/method_context'
2
+ require_relative 'context/module_context'
3
+ require_relative 'context/root_context'
4
+ require_relative 'context/singleton_method_context'
5
+ require_relative 'smells/smell_repository'
6
+ require_relative 'ast/node'
7
+
8
+ module Reek
9
+ #
10
+ # Traverses a Sexp abstract syntax tree and fires events whenever
11
+ # it encounters specific node types.
12
+ #
13
+ # SMELL: This class is responsible for counting statements and for feeding
14
+ # each context to the smell repository.
15
+ #
16
+ # @api private
17
+ class TreeWalker
18
+ def initialize(smell_repository = Smells::SmellRepository.new)
19
+ @smell_repository = smell_repository
20
+ @element = Context::RootContext.new
21
+ end
22
+
23
+ def process(exp)
24
+ context_processor = "process_#{exp.type}"
25
+ if context_processor_exists?(context_processor)
26
+ send(context_processor, exp)
27
+ else
28
+ process_default exp
29
+ end
30
+ @element
31
+ end
32
+
33
+ def process_default(exp)
34
+ exp.children.each do |child|
35
+ process(child) if child.is_a? AST::Node
36
+ end
37
+ end
38
+
39
+ def process_module(exp)
40
+ inside_new_context(Context::ModuleContext, exp) do
41
+ process_default(exp)
42
+ end
43
+ end
44
+
45
+ alias_method :process_class, :process_module
46
+
47
+ def process_def(exp)
48
+ inside_new_context(Context::MethodContext, exp) do
49
+ count_clause(exp.body)
50
+ process_default(exp)
51
+ end
52
+ end
53
+
54
+ def process_defs(exp)
55
+ inside_new_context(Context::SingletonMethodContext, exp) do
56
+ count_clause(exp.body)
57
+ process_default(exp)
58
+ end
59
+ end
60
+
61
+ def process_args(_) end
62
+
63
+ #
64
+ # Recording of calls to methods and self
65
+ #
66
+
67
+ def process_send(exp)
68
+ @element.record_call_to(exp)
69
+ process_default(exp)
70
+ end
71
+
72
+ alias_method :process_attrasgn, :process_send
73
+ alias_method :process_op_asgn, :process_send
74
+
75
+ def process_ivar(exp)
76
+ @element.record_use_of_self
77
+ process_default(exp)
78
+ end
79
+
80
+ alias_method :process_ivasgn, :process_ivar
81
+
82
+ def process_self(_)
83
+ @element.record_use_of_self
84
+ end
85
+
86
+ alias_method :process_zsuper, :process_self
87
+
88
+ #
89
+ # Statement counting
90
+ #
91
+
92
+ def process_block(exp)
93
+ count_clause(exp.block)
94
+ process_default(exp)
95
+ end
96
+
97
+ def process_begin(exp)
98
+ count_statement_list(exp.children)
99
+ @element.count_statements(-1)
100
+ process_default(exp)
101
+ end
102
+
103
+ alias_method :process_kwbegin, :process_begin
104
+
105
+ def process_if(exp)
106
+ count_clause(exp[2])
107
+ count_clause(exp[3])
108
+ @element.count_statements(-1)
109
+ process_default(exp)
110
+ end
111
+
112
+ def process_while(exp)
113
+ count_clause(exp[2])
114
+ @element.count_statements(-1)
115
+ process_default(exp)
116
+ end
117
+
118
+ alias_method :process_until, :process_while
119
+
120
+ def process_for(exp)
121
+ count_clause(exp[3])
122
+ @element.count_statements(-1)
123
+ process_default(exp)
124
+ end
125
+
126
+ def process_rescue(exp)
127
+ count_clause(exp[1])
128
+ @element.count_statements(-1)
129
+ process_default(exp)
130
+ end
131
+
132
+ def process_resbody(exp)
133
+ count_statement_list(exp[2..-1].compact)
134
+ process_default(exp)
135
+ end
136
+
137
+ def process_case(exp)
138
+ count_clause(exp.else_body)
139
+ @element.count_statements(-1)
140
+ process_default(exp)
141
+ end
142
+
143
+ def process_when(exp)
144
+ count_clause(exp.body)
145
+ process_default(exp)
146
+ end
147
+
148
+ private
149
+
150
+ def context_processor_exists?(name)
151
+ respond_to?(name)
152
+ end
153
+
154
+ def count_clause(sexp)
155
+ @element.count_statements(1) if sexp
156
+ end
157
+
158
+ def count_statement_list(statement_list)
159
+ @element.count_statements statement_list.length
160
+ end
161
+
162
+ def inside_new_context(klass, exp)
163
+ scope = klass.new(@element, exp)
164
+ push(scope) do
165
+ yield
166
+ check_smells(exp.type)
167
+ end
168
+ scope
169
+ end
170
+
171
+ def check_smells(type)
172
+ @smell_repository.examine(@element, type)
173
+ end
174
+
175
+ def push(scope)
176
+ orig = @element
177
+ @element = scope
178
+ yield
179
+ @element = orig
180
+ end
181
+ end
182
+ end
data/lib/reek/version.rb CHANGED
@@ -3,6 +3,6 @@ module Reek
3
3
  # This module holds the Reek version informations
4
4
  #
5
5
  module Version
6
- STRING = '2.0.4'
6
+ STRING = '3.0.0'
7
7
  end
8
8
  end
data/lib/reek.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Reek's core functionality
3
3
  #
4
- require 'reek/version'
5
- require 'reek/examiner'
6
- require 'reek/smell_warning'
4
+ require_relative 'reek/version'
5
+ require_relative 'reek/examiner'
6
+ require_relative 'reek/report/report'
data/reek.gemspec CHANGED
@@ -1,6 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $LOAD_PATH.push File.join(File.dirname(__FILE__), 'lib')
3
- require 'reek/version'
2
+ require File.join(File.dirname(__FILE__), 'lib/reek/version')
4
3
 
5
4
  Gem::Specification.new do |s|
6
5
  s.name = 'reek'
@@ -15,31 +14,25 @@ Gem::Specification.new do |s|
15
14
 
16
15
  s.license = 'MIT'
17
16
  s.email = ['timo.roessner@googlemail.com']
18
- s.executables = ['reek']
19
17
  s.extra_rdoc_files = ['CHANGELOG', 'License.txt']
20
- s.files = Dir['.yardopts', 'CHANGELOG', 'License.txt', 'README.md',
21
- 'Rakefile', 'assets/html_output.html.erb', 'bin/reek',
22
- 'config/defaults.reek', '{features,lib,spec,tasks}/**/*',
23
- 'reek.gemspec'] & `git ls-files -z`.split("\0")
24
- s.homepage = 'https://wiki.github.com/troessner/reek'
25
- s.rdoc_options = ['--main', 'README.md',
26
- '-x', 'assets/|bin/|config/|features/|spec/|tasks/']
27
- s.require_paths = ['lib']
28
- s.rubyforge_project = 'reek'
29
- s.rubygems_version = '1.3.6'
30
- s.required_ruby_version = '>= 1.9.3'
18
+ s.files = `git ls-files -z`.split("\0")
19
+ s.executables = s.files.grep(%r{^bin/}).map { |path| File.basename(path) }
20
+ s.homepage = 'https://github.com/troessner/reek/wiki'
21
+ s.rdoc_options = %w(--main README.md -x assets/|bin/|config/|features/|spec/|tasks/)
22
+ s.required_ruby_version = '>= 2.0.0'
31
23
  s.summary = 'Code smell detector for Ruby'
32
24
 
33
- s.add_runtime_dependency('parser', ['~> 2.2'])
34
- s.add_runtime_dependency('unparser', ['~> 0.2.2'])
35
- s.add_runtime_dependency('rainbow', ['~> 2.0'])
36
- s.add_runtime_dependency('require_all', ['~> 1.3'])
25
+ s.add_runtime_dependency 'parser', '~> 2.2.2.5'
26
+ s.add_runtime_dependency 'rainbow', '~> 2.0'
27
+ s.add_runtime_dependency 'unparser', '~> 0.2.2'
37
28
 
38
- s.add_development_dependency('bundler', ['~> 1.1'])
39
- s.add_development_dependency('rake', ['~> 10.0'])
40
- s.add_development_dependency('cucumber', ['~> 1.3', '>= 1.3.18'])
41
- s.add_development_dependency('rspec', ['~> 3.0'])
42
- s.add_development_dependency('yard', ['>= 0.8.7', '< 0.9'])
43
- s.add_development_dependency('factory_girl', ['~> 4.0'])
44
- s.add_development_dependency('rubocop', ['~> 0.29.0'])
29
+ s.add_development_dependency 'activesupport', '~> 4.2'
30
+ s.add_development_dependency 'aruba', '~> 0.6.2'
31
+ s.add_development_dependency 'ataru', '~> 0.2.0'
32
+ s.add_development_dependency 'bundler', '~> 1.1'
33
+ s.add_development_dependency 'cucumber', '~> 2.0'
34
+ s.add_development_dependency 'factory_girl', '~> 4.0'
35
+ s.add_development_dependency 'rake', '~> 10.0'
36
+ s.add_development_dependency 'rspec', '~> 3.0'
37
+ s.add_development_dependency 'rubocop', '~> 0.30.0'
45
38
  end
@@ -1,4 +1,6 @@
1
- require 'reek/smells'
1
+ require_relative '../../lib/reek/smells'
2
+ require_relative '../../lib/reek/smells/smell_detector'
3
+ require_relative '../../lib/reek/smells/smell_warning'
2
4
 
3
5
  FactoryGirl.define do
4
6
  factory :smell_detector, class: Reek::Smells::SmellDetector do
@@ -13,7 +15,7 @@ FactoryGirl.define do
13
15
  end
14
16
  end
15
17
 
16
- factory :smell_warning, class: Reek::SmellWarning do
18
+ factory :smell_warning, class: Reek::Smells::SmellWarning do
17
19
  skip_create
18
20
  smell_detector
19
21
  context 'self'
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ require_relative '../spec_helper'
2
2
  require 'find'
3
3
 
4
4
  release_timestamp_file = 'build/.last-release'
@@ -1,7 +1,7 @@
1
- require 'spec_helper'
1
+ require_relative '../spec_helper'
2
2
  require 'tempfile'
3
3
 
4
- describe 'yardoc' do
4
+ RSpec.describe 'yardoc' do
5
5
  before :each do
6
6
  stderr_file = Tempfile.new('yardoc')
7
7
  stderr_file.close
@@ -1,7 +1,7 @@
1
- require 'spec_helper'
1
+ require_relative '../spec_helper'
2
2
 
3
- describe 'Reek source code' do
3
+ RSpec.describe 'Reek source code' do
4
4
  it 'has no smells' do
5
- Dir['lib/**/*.rb'].should_not reek
5
+ expect(Dir['lib/**/*.rb']).to_not reek
6
6
  end
7
7
  end
@@ -1,13 +1,11 @@
1
- require 'spec_helper'
2
- require 'reek/source/sexp_node'
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/ast/node'
3
3
 
4
- include Reek::Source
5
-
6
- describe SexpNode do
4
+ RSpec.describe Reek::AST::Node do
7
5
  context 'format' do
8
6
  it 'formats self' do
9
7
  @node = s(:self)
10
- expect(@node.format_ruby).to eq('self')
8
+ expect(@node.format_to_ruby).to eq('self')
11
9
  end
12
10
  end
13
11
 
@@ -1,11 +1,9 @@
1
- require 'spec_helper'
2
- require 'reek/core/object_refs'
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/ast/object_refs'
3
3
 
4
- include Reek::Core
5
-
6
- describe ObjectRefs do
4
+ RSpec.describe Reek::AST::ObjectRefs do
7
5
  before(:each) do
8
- @refs = ObjectRefs.new
6
+ @refs = Reek::AST::ObjectRefs.new
9
7
  end
10
8
 
11
9
  context 'when empty' do
@@ -1,51 +1,59 @@
1
- require 'spec_helper'
2
- require 'reek/source/reference_collector'
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/ast/reference_collector'
3
3
 
4
- include Reek::Source
5
-
6
- describe ReferenceCollector do
4
+ RSpec.describe Reek::AST::ReferenceCollector do
7
5
  context 'counting refs to self' do
8
6
  def refs_to_self(src)
9
- ReferenceCollector.new(src.to_reek_source.syntax_tree).num_refs_to_self
7
+ syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
8
+ described_class.new(syntax_tree).num_refs_to_self
10
9
  end
10
+
11
11
  it 'with no refs to self' do
12
12
  expect(refs_to_self('def no_envy(arga) arga.barg end')).to eq(0)
13
13
  end
14
+
14
15
  it 'counts a call to super' do
15
16
  expect(refs_to_self('def simple() super; end')).to eq(1)
16
17
  end
18
+
17
19
  it 'counts a local call' do
18
20
  expect(refs_to_self('def simple() to_s; end')).to eq(1)
19
21
  end
22
+
20
23
  it 'counts a use of self' do
21
24
  expect(refs_to_self('def simple() lv = self; end')).to eq(1)
22
25
  end
26
+
23
27
  it 'counts a call with self as receiver' do
24
28
  expect(refs_to_self('def simple() self.to_s; end')).to eq(1)
25
29
  end
30
+
26
31
  it 'counts uses of an ivar' do
27
32
  expect(refs_to_self('def no_envy() @item.to_a; @item = 4; @item end')).to eq(3)
28
33
  end
34
+
29
35
  it 'counts an ivar passed to a method' do
30
36
  expect(refs_to_self('def no_envy(arga) arga.barg(@item); arga end')).to eq(1)
31
37
  end
38
+
32
39
  it 'ignores global variables' do
33
40
  expect(refs_to_self('def no_envy(arga) $s2.to_a; $s2[arga] end')).to eq(0)
34
41
  end
42
+
35
43
  it 'ignores global variables' do
36
- src = <<EOS
37
- def accept(t, pat = /.*/nm, &block)
38
- if pat
39
- pat.respond_to?(:match) or raise TypeError, "has no `match'"
40
- else
41
- pat = t if t.respond_to?(:match)
42
- end
43
- unless block
44
- block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
45
- end
46
- @atype[t] = [pat, block]
47
- end
48
- EOS
44
+ src = <<-EOS
45
+ def accept(t, pat = /.*/nm, &block)
46
+ if pat
47
+ pat.respond_to?(:match) or raise TypeError, "has no `match'"
48
+ else
49
+ pat = t if t.respond_to?(:match)
50
+ end
51
+ unless block
52
+ block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
53
+ end
54
+ @atype[t] = [pat, block]
55
+ end
56
+ EOS
49
57
  expect(refs_to_self(src)).to eq(2)
50
58
  end
51
59
  end
@@ -1,9 +1,7 @@
1
- require 'spec_helper'
2
- require 'reek/source/sexp_extensions'
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/ast/sexp_extensions'
3
3
 
4
- include Reek::Source
5
-
6
- describe SexpExtensions::DefNode do
4
+ RSpec.describe Reek::AST::SexpExtensions::DefNode do
7
5
  context 'with no parameters' do
8
6
  before :each do
9
7
  @node = s(:def, :hello, s(:args))
@@ -110,11 +108,6 @@ describe SexpExtensions::DefNode do
110
108
  expect(@node.body).to eq s(:begin, s(:first), s(:second))
111
109
  end
112
110
 
113
- it 'has a body extended with SexpNode' do
114
- b = @node.body
115
- expect(b.class.included_modules.first).to eq SexpNode
116
- end
117
-
118
111
  it 'finds nodes in the body with #body_nodes' do
119
112
  expect(@node.body_nodes([:first])).to eq [s(:first)]
120
113
  end
@@ -135,7 +128,7 @@ describe SexpExtensions::DefNode do
135
128
  end
136
129
  end
137
130
 
138
- describe SexpExtensions::DefsNode do
131
+ RSpec.describe Reek::AST::SexpExtensions::DefsNode do
139
132
  context 'with no parameters' do
140
133
  before :each do
141
134
  @node = s(:defs, s(:lvar, :obj), :hello, s(:args))
@@ -241,15 +234,10 @@ describe SexpExtensions::DefsNode do
241
234
  it 'has 2 body statements' do
242
235
  expect(@node.body).to eq s(:begin, s(:first), s(:second))
243
236
  end
244
-
245
- it 'has a body extended with SexpNode' do
246
- b = @node.body
247
- expect(b.class.included_modules.first).to eq SexpNode
248
- end
249
237
  end
250
238
  end
251
239
 
252
- describe SexpExtensions::SendNode do
240
+ RSpec.describe Reek::AST::SexpExtensions::SendNode do
253
241
  context 'with no parameters' do
254
242
  before :each do
255
243
  @node = s(:send, nil, :hello)
@@ -281,7 +269,7 @@ describe SexpExtensions::SendNode do
281
269
  end
282
270
  end
283
271
 
284
- describe SexpExtensions::BlockNode do
272
+ RSpec.describe Reek::AST::SexpExtensions::BlockNode do
285
273
  context 'with no parameters' do
286
274
  before :each do
287
275
  @node = s(:block, s(:send, nil, :map), s(:args), nil)
@@ -313,7 +301,7 @@ describe SexpExtensions::BlockNode do
313
301
  end
314
302
  end
315
303
 
316
- describe SexpExtensions::ModuleNode do
304
+ RSpec.describe Reek::AST::SexpExtensions::ModuleNode do
317
305
  context 'with a simple name' do
318
306
  subject do
319
307
  mod = ast(:module, :Fred, nil)
@@ -1,17 +1,16 @@
1
- require 'spec_helper'
2
- require 'reek/source/sexp_formatter'
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/ast/sexp_formatter'
3
3
 
4
- include Reek::Source
5
-
6
- describe SexpFormatter do
4
+ RSpec.describe Reek::AST::SexpFormatter do
7
5
  describe '::format' do
8
6
  it 'formats a simple s-expression' do
9
- result = SexpFormatter.format s(:lvar, :foo)
7
+ result = described_class.format s(:lvar, :foo)
10
8
  expect(result).to eq('foo')
11
9
  end
12
10
 
13
11
  it 'formats a more complex s-expression' do
14
- result = SexpFormatter.format s(:send, nil, :foo, s(:lvar, :bar))
12
+ ast = s(:send, nil, :foo, s(:lvar, :bar))
13
+ result = described_class.format(ast)
15
14
  expect(result).to eq('foo(bar)')
16
15
  end
17
16
 
@@ -22,9 +21,15 @@ describe SexpFormatter do
22
21
  s(:begin,
23
22
  s(:send, nil, :baz),
24
23
  s(:send, nil, :qux)))
25
- result = SexpFormatter.format ast
24
+ result = described_class.format ast
26
25
 
27
26
  expect(result).to eq 'if foo ... end'
28
27
  end
28
+
29
+ it "doesn't reduce two-line ASTs" do
30
+ ast = s(:def, 'my_method', s(:args))
31
+ result = described_class.format ast
32
+ expect(result).to eq 'def my_method; end'
33
+ end
29
34
  end
30
35
  end
@@ -0,0 +1,15 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ require_relative '../../../lib/reek/cli/options'
4
+ require_relative '../../../lib/reek/report/report'
5
+
6
+ RSpec.describe Reek::CLI::OptionInterpreter do
7
+ let(:options) { OpenStruct.new }
8
+ let(:instance) { Reek::CLI::OptionInterpreter.new(options) }
9
+
10
+ describe '#reporter' do
11
+ it 'returns a Report::TextReport instance by default' do
12
+ expect(instance.reporter).to be_instance_of Reek::Report::TextReport
13
+ end
14
+ end
15
+ end