reek 4.6.0 → 5.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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -12
  3. data/.rubocop.yml +79 -26
  4. data/.simplecov +1 -0
  5. data/.travis.yml +3 -9
  6. data/.yardopts +1 -1
  7. data/CHANGELOG.md +76 -0
  8. data/CONTRIBUTING.md +1 -1
  9. data/Gemfile +5 -5
  10. data/README.md +138 -107
  11. data/Rakefile +16 -3
  12. data/bin/code_climate_reek +1 -0
  13. data/bin/reek +2 -3
  14. data/docs/API.md +2 -9
  15. data/docs/Basic-Smell-Options.md +51 -11
  16. data/docs/Code-Smells.md +1 -1
  17. data/docs/Command-Line-Options.md +14 -4
  18. data/docs/Duplicate-Method-Call.md +49 -1
  19. data/docs/Feature-Envy.md +44 -0
  20. data/docs/How-To-Write-New-Detectors.md +7 -7
  21. data/docs/Instance-Variable-Assumption.md +1 -1
  22. data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
  23. data/docs/Rake-Task.md +1 -1
  24. data/docs/Reek-4-to-Reek-5-migration.md +193 -0
  25. data/docs/Reek-Driven-Development.md +1 -1
  26. data/docs/Uncommunicative-Method-Name.md +45 -6
  27. data/docs/Uncommunicative-Module-Name.md +49 -7
  28. data/docs/Uncommunicative-Parameter-Name.md +43 -5
  29. data/docs/Uncommunicative-Variable-Name.md +73 -2
  30. data/docs/Unused-Private-Method.md +3 -3
  31. data/docs/defaults.reek.yml +129 -0
  32. data/docs/yard_plugin.rb +1 -0
  33. data/features/command_line_interface/basic_usage.feature +2 -2
  34. data/features/command_line_interface/options.feature +46 -4
  35. data/features/command_line_interface/show_progress.feature +4 -4
  36. data/features/command_line_interface/smell_selection.feature +1 -1
  37. data/features/command_line_interface/smells_count.feature +6 -6
  38. data/features/command_line_interface/stdin.feature +31 -5
  39. data/features/configuration_files/accept_setting.feature +45 -28
  40. data/features/configuration_files/directory_specific_directives.feature +80 -75
  41. data/features/configuration_files/exclude_directives.feature +11 -10
  42. data/features/configuration_files/exclude_paths_directives.feature +4 -4
  43. data/features/configuration_files/masking_smells.feature +38 -9
  44. data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
  45. data/features/configuration_files/reject_setting.feature +52 -41
  46. data/features/configuration_files/schema_validation.feature +59 -0
  47. data/features/configuration_files/unused_private_method.feature +18 -16
  48. data/features/configuration_loading.feature +53 -10
  49. data/features/configuration_via_source_comments/erroneous_source_comments.feature +3 -3
  50. data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
  51. data/features/locales.feature +32 -0
  52. data/features/rake_task/rake_task.feature +58 -18
  53. data/features/reports/codeclimate.feature +59 -0
  54. data/features/reports/json.feature +3 -3
  55. data/features/reports/reports.feature +34 -34
  56. data/features/reports/yaml.feature +3 -3
  57. data/features/rspec_matcher.feature +40 -0
  58. data/features/samples.feature +287 -287
  59. data/features/step_definitions/reek_steps.rb +14 -2
  60. data/features/step_definitions/sample_file_steps.rb +9 -4
  61. data/features/support/env.rb +2 -11
  62. data/features/todo_list.feature +26 -23
  63. data/lib/reek/ast/ast_node_class_map.rb +1 -0
  64. data/lib/reek/ast/builder.rb +16 -0
  65. data/lib/reek/ast/node.rb +50 -58
  66. data/lib/reek/ast/object_refs.rb +2 -1
  67. data/lib/reek/ast/reference_collector.rb +3 -4
  68. data/lib/reek/ast/sexp_extensions/arguments.rb +1 -0
  69. data/lib/reek/ast/sexp_extensions/attribute_assignments.rb +1 -0
  70. data/lib/reek/ast/sexp_extensions/begin.rb +17 -0
  71. data/lib/reek/ast/sexp_extensions/block.rb +1 -0
  72. data/lib/reek/ast/sexp_extensions/case.rb +2 -1
  73. data/lib/reek/ast/sexp_extensions/constant.rb +1 -0
  74. data/lib/reek/ast/sexp_extensions/if.rb +9 -1
  75. data/lib/reek/ast/sexp_extensions/lambda.rb +1 -0
  76. data/lib/reek/ast/sexp_extensions/literal.rb +1 -0
  77. data/lib/reek/ast/sexp_extensions/logical_operators.rb +2 -1
  78. data/lib/reek/ast/sexp_extensions/methods.rb +5 -6
  79. data/lib/reek/ast/sexp_extensions/module.rb +55 -8
  80. data/lib/reek/ast/sexp_extensions/nested_assignables.rb +1 -0
  81. data/lib/reek/ast/sexp_extensions/self.rb +1 -0
  82. data/lib/reek/ast/sexp_extensions/send.rb +1 -4
  83. data/lib/reek/ast/sexp_extensions/super.rb +1 -0
  84. data/lib/reek/ast/sexp_extensions/symbols.rb +1 -0
  85. data/lib/reek/ast/sexp_extensions/variables.rb +1 -0
  86. data/lib/reek/ast/sexp_extensions/when.rb +1 -0
  87. data/lib/reek/ast/sexp_extensions/yield.rb +1 -0
  88. data/lib/reek/ast/sexp_extensions.rb +2 -0
  89. data/lib/reek/cli/application.rb +5 -3
  90. data/lib/reek/cli/command/base_command.rb +1 -0
  91. data/lib/reek/cli/command/report_command.rb +2 -2
  92. data/lib/reek/cli/command/todo_list_command.rb +9 -8
  93. data/lib/reek/cli/options.rb +32 -16
  94. data/lib/reek/cli/silencer.rb +15 -3
  95. data/lib/reek/cli/status.rb +1 -0
  96. data/lib/reek/code_comment.rb +14 -16
  97. data/lib/reek/configuration/app_configuration.rb +34 -28
  98. data/lib/reek/configuration/configuration_converter.rb +110 -0
  99. data/lib/reek/configuration/configuration_file_finder.rb +17 -41
  100. data/lib/reek/configuration/configuration_validator.rb +13 -23
  101. data/lib/reek/configuration/default_directive.rb +18 -3
  102. data/lib/reek/configuration/directory_directives.rb +18 -11
  103. data/lib/reek/configuration/excluded_paths.rb +2 -1
  104. data/lib/reek/configuration/rake_task_converter.rb +29 -0
  105. data/lib/reek/configuration/schema.yml +210 -0
  106. data/lib/reek/configuration/schema_validator.rb +38 -0
  107. data/lib/reek/context/attribute_context.rb +4 -3
  108. data/lib/reek/context/class_context.rb +1 -0
  109. data/lib/reek/context/code_context.rb +49 -44
  110. data/lib/reek/context/ghost_context.rb +1 -2
  111. data/lib/reek/context/method_context.rb +26 -18
  112. data/lib/reek/context/module_context.rb +11 -11
  113. data/lib/reek/context/root_context.rb +1 -4
  114. data/lib/reek/context/send_context.rb +3 -2
  115. data/lib/reek/context/singleton_attribute_context.rb +1 -0
  116. data/lib/reek/context/singleton_method_context.rb +1 -0
  117. data/lib/reek/context/statement_counter.rb +1 -0
  118. data/lib/reek/context/visibility_tracker.rb +1 -0
  119. data/lib/reek/context_builder.rb +44 -44
  120. data/lib/reek/detector_repository.rb +12 -11
  121. data/lib/reek/documentation_link.rb +28 -0
  122. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +15 -13
  123. data/lib/reek/errors/bad_detector_in_comment_error.rb +13 -11
  124. data/lib/reek/errors/base_error.rb +3 -0
  125. data/lib/reek/errors/config_file_error.rb +11 -0
  126. data/lib/reek/errors/encoding_error.rb +43 -0
  127. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +14 -12
  128. data/lib/reek/errors/incomprehensible_source_error.rb +23 -24
  129. data/lib/reek/errors/syntax_error.rb +41 -0
  130. data/lib/reek/examiner.rb +24 -22
  131. data/lib/reek/logging_error_handler.rb +8 -5
  132. data/lib/reek/rake/task.rb +8 -5
  133. data/lib/reek/report/base_report.rb +9 -12
  134. data/lib/reek/report/code_climate/code_climate_configuration.rb +2 -1
  135. data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -6
  136. data/lib/reek/report/code_climate/code_climate_fingerprint.rb +1 -0
  137. data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -0
  138. data/lib/reek/report/code_climate/code_climate_report.rb +1 -0
  139. data/lib/reek/report/code_climate.rb +1 -0
  140. data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
  141. data/lib/reek/report/heading_formatter.rb +54 -0
  142. data/lib/reek/report/html_report.rb +1 -0
  143. data/lib/reek/report/json_report.rb +2 -1
  144. data/lib/reek/report/location_formatter.rb +40 -0
  145. data/lib/reek/report/progress_formatter.rb +79 -0
  146. data/lib/reek/report/simple_warning_formatter.rb +34 -0
  147. data/lib/reek/report/text_report.rb +2 -2
  148. data/lib/reek/report/xml_report.rb +4 -3
  149. data/lib/reek/report/yaml_report.rb +2 -1
  150. data/lib/reek/report.rb +16 -10
  151. data/lib/reek/smell_configuration.rb +3 -2
  152. data/lib/reek/smell_detectors/attribute.rb +6 -11
  153. data/lib/reek/smell_detectors/base_detector.rb +31 -26
  154. data/lib/reek/smell_detectors/boolean_parameter.rb +4 -5
  155. data/lib/reek/smell_detectors/class_variable.rb +6 -14
  156. data/lib/reek/smell_detectors/control_parameter.rb +19 -33
  157. data/lib/reek/smell_detectors/data_clump.rb +16 -9
  158. data/lib/reek/smell_detectors/duplicate_method_call.rb +24 -17
  159. data/lib/reek/smell_detectors/feature_envy.rb +10 -7
  160. data/lib/reek/smell_detectors/instance_variable_assumption.rb +15 -23
  161. data/lib/reek/smell_detectors/irresponsible_module.rb +6 -12
  162. data/lib/reek/smell_detectors/long_parameter_list.rb +11 -7
  163. data/lib/reek/smell_detectors/long_yield_list.rb +11 -7
  164. data/lib/reek/smell_detectors/manual_dispatch.rb +5 -5
  165. data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +21 -20
  166. data/lib/reek/smell_detectors/module_initialize.rb +4 -5
  167. data/lib/reek/smell_detectors/nested_iterators.rb +17 -24
  168. data/lib/reek/smell_detectors/nil_check.rb +9 -15
  169. data/lib/reek/smell_detectors/repeated_conditional.rb +14 -11
  170. data/lib/reek/smell_detectors/subclassed_from_core_class.rb +8 -8
  171. data/lib/reek/smell_detectors/too_many_constants.rb +11 -9
  172. data/lib/reek/smell_detectors/too_many_instance_variables.rb +11 -6
  173. data/lib/reek/smell_detectors/too_many_methods.rb +12 -7
  174. data/lib/reek/smell_detectors/too_many_statements.rb +11 -6
  175. data/lib/reek/smell_detectors/uncommunicative_method_name.rb +11 -11
  176. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +15 -18
  177. data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +18 -22
  178. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +27 -27
  179. data/lib/reek/smell_detectors/unused_parameters.rb +5 -6
  180. data/lib/reek/smell_detectors/unused_private_method.rb +14 -20
  181. data/lib/reek/smell_detectors/utility_function.rb +13 -16
  182. data/lib/reek/smell_detectors.rb +2 -1
  183. data/lib/reek/smell_warning.rb +16 -8
  184. data/lib/reek/source/source_code.rb +65 -46
  185. data/lib/reek/source/source_locator.rb +9 -8
  186. data/lib/reek/spec/should_reek.rb +3 -2
  187. data/lib/reek/spec/should_reek_of.rb +13 -26
  188. data/lib/reek/spec/should_reek_only_of.rb +5 -4
  189. data/lib/reek/spec/smell_matcher.rb +2 -1
  190. data/lib/reek/spec.rb +7 -6
  191. data/lib/reek/tree_dresser.rb +9 -8
  192. data/lib/reek/version.rb +2 -1
  193. data/lib/reek.rb +1 -0
  194. data/reek.gemspec +5 -6
  195. data/samples/checkstyle.xml +1 -1
  196. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
  197. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
  198. data/samples/configuration/full_configuration.reek +8 -4
  199. data/samples/configuration/full_mask.reek +5 -4
  200. data/samples/configuration/partial_mask.reek +3 -2
  201. data/samples/configuration/regular_configuration/.reek.yml +4 -0
  202. data/samples/paths.rb +5 -4
  203. data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
  204. data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
  205. data/spec/factories/factories.rb +2 -13
  206. data/spec/reek/ast/node_spec.rb +103 -10
  207. data/spec/reek/ast/reference_collector_spec.rb +1 -1
  208. data/spec/reek/ast/sexp_extensions_spec.rb +15 -34
  209. data/spec/reek/cli/application_spec.rb +52 -42
  210. data/spec/reek/cli/command/todo_list_command_spec.rb +6 -4
  211. data/spec/reek/cli/silencer_spec.rb +28 -0
  212. data/spec/reek/code_comment_spec.rb +31 -38
  213. data/spec/reek/configuration/app_configuration_spec.rb +46 -33
  214. data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -51
  215. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  216. data/spec/reek/configuration/directory_directives_spec.rb +6 -7
  217. data/spec/reek/configuration/excluded_paths_spec.rb +6 -6
  218. data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
  219. data/spec/reek/configuration/schema_validator_spec.rb +165 -0
  220. data/spec/reek/context/code_context_spec.rb +70 -106
  221. data/spec/reek/context/ghost_context_spec.rb +9 -9
  222. data/spec/reek/context/method_context_spec.rb +2 -2
  223. data/spec/reek/context/module_context_spec.rb +3 -3
  224. data/spec/reek/context/root_context_spec.rb +1 -1
  225. data/spec/reek/context/statement_counter_spec.rb +1 -0
  226. data/spec/reek/context_builder_spec.rb +20 -0
  227. data/spec/reek/documentation_link_spec.rb +20 -0
  228. data/spec/reek/errors/base_error_spec.rb +13 -0
  229. data/spec/reek/examiner_spec.rb +137 -29
  230. data/spec/reek/rake/task_spec.rb +25 -2
  231. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -78
  232. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
  233. data/spec/reek/report/code_climate/code_climate_report_spec.rb +22 -22
  234. data/spec/reek/report/json_report_spec.rb +13 -46
  235. data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
  236. data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
  237. data/spec/reek/report/text_report_spec.rb +4 -4
  238. data/spec/reek/report/xml_report_spec.rb +3 -3
  239. data/spec/reek/report/yaml_report_spec.rb +17 -46
  240. data/spec/reek/report_spec.rb +3 -3
  241. data/spec/reek/smell_detectors/base_detector_spec.rb +4 -5
  242. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +2 -2
  243. data/spec/reek/smell_detectors/class_variable_spec.rb +26 -32
  244. data/spec/reek/smell_detectors/control_parameter_spec.rb +34 -4
  245. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +3 -3
  246. data/spec/reek/smell_detectors/feature_envy_spec.rb +47 -2
  247. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +59 -21
  248. data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +10 -10
  249. data/spec/reek/smell_detectors/module_initialize_spec.rb +14 -0
  250. data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
  251. data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
  252. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
  253. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
  254. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
  255. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +36 -15
  256. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +9 -9
  257. data/spec/reek/smell_detectors/unused_parameters_spec.rb +3 -3
  258. data/spec/reek/smell_detectors/unused_private_method_spec.rb +21 -10
  259. data/spec/reek/smell_detectors/utility_function_spec.rb +57 -5
  260. data/spec/reek/smell_warning_spec.rb +12 -8
  261. data/spec/reek/source/source_code_spec.rb +27 -38
  262. data/spec/reek/source/source_locator_spec.rb +42 -12
  263. data/spec/reek/spec/should_reek_of_spec.rb +25 -30
  264. data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
  265. data/spec/reek/spec/should_reek_spec.rb +8 -8
  266. data/spec/reek/spec/smell_matcher_spec.rb +23 -23
  267. data/spec/reek/tree_dresser_spec.rb +12 -17
  268. data/spec/spec_helper.rb +7 -17
  269. data/tasks/configuration.rake +8 -5
  270. metadata +77 -40
  271. data/defaults.reek +0 -128
  272. data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
  273. data/lib/reek/errors/parse_error.rb +0 -19
  274. data/lib/reek/report/formatter/heading_formatter.rb +0 -51
  275. data/lib/reek/report/formatter/location_formatter.rb +0 -41
  276. data/lib/reek/report/formatter/progress_formatter.rb +0 -80
  277. data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
  278. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -35
  279. data/lib/reek/report/formatter.rb +0 -32
  280. data/samples/configuration/non_public_modifiers_mask.reek +0 -3
  281. data/samples/smelly_with_inline_mask.rb +0 -8
  282. data/samples/smelly_with_modifiers.rb +0 -12
  283. data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
  284. data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
  285. /data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
  286. /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
  287. /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
  288. /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
  289. /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
  290. /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
  291. /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
  292. /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
  293. /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
  294. /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative '../examiner'
3
- require_relative '../report/formatter'
4
+ require_relative '../report/simple_warning_formatter'
4
5
  require_relative 'should_reek_of'
5
6
  require_relative 'smell_matcher'
6
7
 
@@ -23,12 +24,12 @@ module Reek
23
24
  end
24
25
 
25
26
  def failure_message
26
- rpt = Report::Formatter.format_list(warnings)
27
- "Expected #{examiner.description} to reek only of #{smell_type}, but got:\n#{rpt}"
27
+ rpt = Report::SimpleWarningFormatter.new.format_list(warnings)
28
+ "Expected #{examiner.origin} to reek only of #{smell_type}, but got:\n#{rpt}"
28
29
  end
29
30
 
30
31
  def failure_message_when_negated
31
- "Expected #{examiner.description} not to reek only of #{smell_type}, but it did"
32
+ "Expected #{examiner.origin} not to reek only of #{smell_type}, but it did"
32
33
  end
33
34
 
34
35
  private
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Reek
3
4
  module Spec
4
5
  #
@@ -7,7 +8,7 @@ module Reek
7
8
  class SmellMatcher
8
9
  attr_reader :smell_warning
9
10
 
10
- COMPARABLE_ATTRIBUTES = %i(message lines context source).freeze
11
+ COMPARABLE_ATTRIBUTES = [:message, :lines, :context, :source].freeze
11
12
 
12
13
  def initialize(smell_warning)
13
14
  @smell_warning = smell_warning
data/lib/reek/spec.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'spec/should_reek'
3
4
  require_relative 'spec/should_reek_of'
4
5
  require_relative 'spec/should_reek_only_of'
@@ -64,7 +65,7 @@ module Reek
64
65
  # raise an ArgumentError to give you a hint that you passed something that doesn't make
65
66
  # much sense.
66
67
  #
67
- # @param smell_type [Symbol, String, Class] The "smell type" to check for.
68
+ # @param smell_type [Symbol, String] The "smell type" to check for.
68
69
  # @param smell_details [Hash] A hash containing "smell warning" parameters
69
70
  #
70
71
  # @example Without smell_details
@@ -83,7 +84,7 @@ module Reek
83
84
  #
84
85
  # @public
85
86
  #
86
- # :reek:UtilityFunction
87
+ # @quality :reek:UtilityFunction
87
88
  def reek_of(smell_type,
88
89
  smell_details = {},
89
90
  configuration = Configuration::AppConfiguration.default)
@@ -98,11 +99,11 @@ module Reek
98
99
  # "reek_only_of" will fail in that case.
99
100
  # 2.) "reek_only_of" doesn't support the additional smell_details hash.
100
101
  #
101
- # @param smell_type [Symbol, String, Class] The "smell type" to check for.
102
+ # @param smell_type [Symbol, String] The "smell type" to check for.
102
103
  #
103
104
  # @public
104
105
  #
105
- # :reek:UtilityFunction
106
+ # @quality :reek:UtilityFunction
106
107
  def reek_only_of(smell_type, configuration = Configuration::AppConfiguration.default)
107
108
  ShouldReekOnlyOf.new(smell_type, configuration)
108
109
  end
@@ -112,8 +113,8 @@ module Reek
112
113
  #
113
114
  # @public
114
115
  #
115
- # :reek:UtilityFunction
116
- def reek(configuration = Configuration::AppConfiguration.default)
116
+ # @quality :reek:UtilityFunction
117
+ def reek(configuration = Configuration::AppConfiguration.from_default_path)
117
118
  ShouldReek.new(configuration: configuration)
118
119
  end
119
120
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'ast/ast_node_class_map'
3
4
 
4
5
  module Reek
@@ -30,21 +31,21 @@ module Reek
30
31
  # time the nodes will contain type-dependent mixins, e.g. this:
31
32
  # (const nil :Klazz)
32
33
  # will be of type Reek::AST::Node with Reek::AST::SexpExtensions::ConstNode mixed in.
33
- # @param sexp [Parser::AST::Node] - the given sexp
34
- # @param comment_map [Hash] - see the documentation for SourceCode#syntax_tree
35
- # @param parent [Parser::AST::Node] - the parent sexp
34
+ #
35
+ # @param sexp [Parser::AST::Node] the given sexp
36
+ # @param comment_map [Hash] see the documentation for SourceCode#syntax_tree
36
37
  #
37
38
  # @return an instance of Reek::AST::Node with type-dependent sexp extensions mixed in.
38
39
  #
39
- # :reek:FeatureEnvy
40
- # :reek:TooManyStatements: { max_statements: 6 }
41
- def dress(sexp, comment_map, parent: nil)
40
+ # @quality :reek:FeatureEnvy
41
+ # @quality :reek:TooManyStatements { max_statements: 6 }
42
+ def dress(sexp, comment_map)
42
43
  return sexp unless sexp.is_a? ::Parser::AST::Node
43
44
  type = sexp.type
44
- children = sexp.children.map { |child| dress(child, comment_map, parent: sexp) }
45
+ children = sexp.children.map { |child| dress(child, comment_map) }
45
46
  comments = comment_map[sexp]
46
47
  klass_map.klass_for(type).new(type, children,
47
- location: sexp.loc, comments: comments, parent: parent)
48
+ location: sexp.loc, comments: comments)
48
49
  end
49
50
 
50
51
  private
data/lib/reek/version.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # @public
3
4
  module Reek
4
5
  #
@@ -7,6 +8,6 @@ module Reek
7
8
  # @public
8
9
  module Version
9
10
  # @public
10
- STRING = '4.6.0'.freeze
11
+ STRING = '5.0.0'
11
12
  end
12
13
  end
data/lib/reek.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  #
3
4
  # Reek's core functionality
4
5
  #
data/reek.gemspec CHANGED
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require File.join(File.dirname(__FILE__), 'lib/reek/version')
3
2
 
4
3
  Gem::Specification.new do |s|
@@ -6,7 +5,6 @@ Gem::Specification.new do |s|
6
5
  s.version = Reek::Version::STRING
7
6
 
8
7
  s.authors = ['Kevin Rutherford', 'Timo Roessner', 'Matijs van Zuijlen', 'Piotr Szotkowski']
9
- s.default_executable = 'reek'
10
8
  s.description =
11
9
  'Reek is a tool that examines Ruby classes, modules and methods and reports ' \
12
10
  'any code smells it finds.'
@@ -16,12 +14,13 @@ Gem::Specification.new do |s|
16
14
  s.extra_rdoc_files = ['CHANGELOG.md', 'License.txt']
17
15
  s.files = `git ls-files -z`.split("\0")
18
16
  s.executables = s.files.grep(%r{^bin/}).map { |path| File.basename(path) }
19
- s.homepage = 'https://github.com/troessner/reek/wiki'
17
+ s.homepage = 'https://github.com/troessner/reek'
20
18
  s.rdoc_options = %w(--main README.md -x assets/|bin/|config/|features/|spec/|tasks/)
21
- s.required_ruby_version = '>= 2.1.0'
19
+ s.required_ruby_version = '>= 2.3.0'
22
20
  s.summary = 'Code smell detector for Ruby'
23
21
 
24
22
  s.add_runtime_dependency 'codeclimate-engine-rb', '~> 0.4.0'
25
- s.add_runtime_dependency 'parser', '< 2.5', '>= 2.3.1.2'
26
- s.add_runtime_dependency 'rainbow', '~> 2.0'
23
+ s.add_runtime_dependency 'kwalify', '~> 0.7.0'
24
+ s.add_runtime_dependency 'parser', '< 2.6', '>= 2.5.0.0'
25
+ s.add_runtime_dependency 'rainbow', '>= 2.0', '< 4.0'
27
26
  end
@@ -1,6 +1,6 @@
1
1
  <?xml version='1.0'?>
2
2
  <checkstyle>
3
- <file name='samples/smelly.rb'>
3
+ <file name='samples/smelly_source/smelly.rb'>
4
4
  <error column='0' line='4' message='has the name &apos;x&apos;' severity='warning' source='UncommunicativeMethodName'/>
5
5
  <error column='0' line='5' message='has the variable name &apos;y&apos;' severity='warning' source='UncommunicativeVariableName'/>
6
6
  </file>
@@ -0,0 +1,29 @@
1
+ ---
2
+ detectors:
3
+ UnusedPrivateMethod:
4
+ exclude:
5
+ - "/exclude regexp/"
6
+ UncommunicativeMethodName:
7
+ reject:
8
+ - "reject name"
9
+ accept:
10
+ - "accept name"
11
+ UncommunicativeModuleName:
12
+ reject:
13
+ - "reject name 1"
14
+ - "reject name 2"
15
+ accept:
16
+ - "accept name 1"
17
+ - "accept name 2"
18
+ UncommunicativeParameterName:
19
+ reject:
20
+ - "reject name"
21
+ - "/reject regexp/"
22
+ accept:
23
+ - "accept name"
24
+ - "/accept regexp/"
25
+ UncommunicativeVariableName:
26
+ reject:
27
+ - "/^reject regexp$/"
28
+ accept:
29
+ - "/accept(.*)regexp/"
@@ -0,0 +1,30 @@
1
+ ---
2
+ directories:
3
+ "app/controllers":
4
+ UnusedPrivateMethod:
5
+ exclude:
6
+ - "/exclude regexp/"
7
+ UncommunicativeMethodName:
8
+ reject:
9
+ - "reject name"
10
+ accept:
11
+ - "accept name"
12
+ UncommunicativeModuleName:
13
+ reject:
14
+ - "reject name 1"
15
+ - "reject name 2"
16
+ accept:
17
+ - "accept name 1"
18
+ - "accept name 2"
19
+ UncommunicativeParameterName:
20
+ reject:
21
+ - "reject name"
22
+ - "/reject regexp/"
23
+ accept:
24
+ - "accept name"
25
+ - "/accept regexp/"
26
+ UncommunicativeVariableName:
27
+ reject:
28
+ - "/^reject regexp$/"
29
+ accept:
30
+ - "/accept(.*)regexp/"
@@ -1,9 +1,13 @@
1
1
  ---
2
- IrresponsibleModule:
3
- enabled: false
4
- "samples/three_clean_files/":
5
- UtilityFunction:
2
+ detectors:
3
+ IrresponsibleModule:
6
4
  enabled: false
5
+
6
+ directories:
7
+ "samples/three_clean_files/":
8
+ UtilityFunction:
9
+ enabled: false
10
+
7
11
  exclude_paths:
8
12
  - "samples/two_smelly_files/"
9
13
  - "samples/source_with_non_ruby_files/"
@@ -1,5 +1,6 @@
1
1
  ---
2
- UncommunicativeMethodName:
3
- enabled: false
4
- UncommunicativeVariableName:
5
- enabled: false
2
+ detectors:
3
+ UncommunicativeMethodName:
4
+ enabled: false
5
+ UncommunicativeVariableName:
6
+ enabled: false
@@ -1,3 +1,4 @@
1
1
  ---
2
- UncommunicativeMethodName:
3
- enabled: false
2
+ detectors:
3
+ UncommunicativeMethodName:
4
+ enabled: false
@@ -0,0 +1,4 @@
1
+ ---
2
+ UncommunicativeVariableName:
3
+ accept:
4
+ - md5
data/samples/paths.rb CHANGED
@@ -1,4 +1,5 @@
1
- SAMPLES_PATH = Pathname.new(__dir__).relative_path_from(Pathname.pwd)
2
- CONFIG_PATH = SAMPLES_PATH.join('configuration')
3
- CLEAN_FILE = SAMPLES_PATH.join('clean.rb')
4
- SMELLY_FILE = SAMPLES_PATH.join('smelly.rb')
1
+ SAMPLES_DIR = Pathname.new(__dir__).relative_path_from(Pathname.pwd)
2
+ CONFIGURATION_DIR = SAMPLES_DIR.join('configuration')
3
+ CLEAN_FILE = SAMPLES_DIR.join('clean_source').join('clean.rb')
4
+ SMELLY_FILE = SAMPLES_DIR.join('smelly_source').join('smelly.rb')
5
+
@@ -3,18 +3,7 @@ require_relative '../../lib/reek/smell_detectors/base_detector'
3
3
  require_relative '../../lib/reek/smell_warning'
4
4
  require_relative '../../lib/reek/cli/options'
5
5
 
6
- FactoryGirl.define do
7
- factory :method_context, class: Reek::Context::MethodContext do
8
- skip_create
9
- transient do
10
- source 'def foo; end'
11
- end
12
-
13
- initialize_with do
14
- new(nil, Reek::Source::SourceCode.from(source).syntax_tree)
15
- end
16
- end
17
-
6
+ FactoryBot.define do
18
7
  factory :smell_detector, class: Reek::SmellDetectors::BaseDetector do
19
8
  skip_create
20
9
  transient do
@@ -33,7 +22,7 @@ FactoryGirl.define do
33
22
  source 'dummy_file'
34
23
  lines [42]
35
24
  message 'smell warning message'
36
- parameters { {} }
25
+ parameters({})
37
26
 
38
27
  initialize_with do
39
28
  new(smell_detector,
@@ -2,6 +2,92 @@ require_relative '../../spec_helper'
2
2
  require_lib 'reek/ast/node'
3
3
 
4
4
  RSpec.describe Reek::AST::Node do
5
+ describe '#each_node' do
6
+ context 'with an empty module' do
7
+ let(:ast) do
8
+ src = 'module Emptiness; end'
9
+ Reek::Source::SourceCode.from(src).syntax_tree
10
+ end
11
+
12
+ it 'yields no calls' do
13
+ ast.each_node(:send, []) { |exp| raise "#{exp} yielded by empty module!" }
14
+ end
15
+
16
+ it 'yields one module' do
17
+ mods = 0
18
+ ast.each_node(:module, []) { |_exp| mods += 1 }
19
+ expect(mods).to eq(1)
20
+ end
21
+
22
+ it "yields the module's full AST" do
23
+ ast.each_node(:module, []) do |exp|
24
+ expect(exp).to eq(sexp(:module, sexp(:const, nil, :Emptiness), nil))
25
+ end
26
+ end
27
+
28
+ it 'returns an enumerator when no block is passed' do
29
+ expect(ast.each_node(:if)).to be_instance_of Enumerator
30
+ end
31
+ end
32
+
33
+ context 'with a nested element' do
34
+ let(:ast) do
35
+ src = "module Loneliness; def calloo; puts('hello') end; end"
36
+ Reek::Source::SourceCode.from(src).syntax_tree
37
+ end
38
+
39
+ it 'yields no ifs' do
40
+ ast.each_node(:if) { |exp| raise "#{exp} yielded by empty module!" }
41
+ end
42
+
43
+ it 'yields one module' do
44
+ expect(ast.each_node(:module).to_a.length).to eq(1)
45
+ end
46
+
47
+ it "yields the module's full AST" do
48
+ ast.each_node(:module) do |exp|
49
+ expect(exp).to eq sexp(:module,
50
+ sexp(:const, nil, :Loneliness),
51
+ sexp(:def, :calloo,
52
+ sexp(:args),
53
+ sexp(:send, nil, :puts, sexp(:str, 'hello'))))
54
+ end
55
+ end
56
+
57
+ it 'yields one method' do
58
+ expect(ast.each_node(:def).to_a.length).to eq(1)
59
+ end
60
+
61
+ it "yields the method's full AST" do
62
+ ast.each_node(:def, []) { |exp| expect(exp.children.first).to eq(:calloo) }
63
+ end
64
+
65
+ it 'ignores the call inside the method if the traversal is pruned' do
66
+ expect(ast.each_node(:send, [:def]).to_a).to be_empty
67
+ end
68
+ end
69
+
70
+ it 'finds 3 ifs in a class' do
71
+ src = <<-EOS
72
+ class Scrunch
73
+ def first
74
+ return @field == :sym ? 0 : 3;
75
+ end
76
+ def second
77
+ if @field == :sym
78
+ @other += " quarts"
79
+ end
80
+ end
81
+ def third
82
+ raise 'flu!' unless @field == :sym
83
+ end
84
+ end
85
+ EOS
86
+ ast = Reek::Source::SourceCode.from(src).syntax_tree
87
+ expect(ast.each_node(:if).to_a.length).to eq(3)
88
+ end
89
+ end
90
+
5
91
  describe '#format_to_ruby' do
6
92
  it 'returns #to_s if location is not present' do
7
93
  ast = sexp(:self)
@@ -56,7 +142,7 @@ RSpec.describe Reek::AST::Node do
56
142
  end
57
143
  end
58
144
 
59
- context 'hash' do
145
+ describe '#hash' do
60
146
  it 'hashes equal for equal sexps' do
61
147
  node1 = sexp(:def, :jim, sexp(:args), sexp(:send, sexp(:int, 4), :+, sexp(:send, nil, :fred)))
62
148
  node2 = sexp(:def, :jim, sexp(:args), sexp(:send, sexp(:int, 4), :+, sexp(:send, nil, :fred)))
@@ -77,8 +163,8 @@ RSpec.describe Reek::AST::Node do
77
163
  end
78
164
 
79
165
  describe '#line' do
80
- context 'source from file' do
81
- let(:file) { SAMPLES_PATH.join('smelly.rb') }
166
+ context 'with source from a file' do
167
+ let(:file) { SMELLY_FILE }
82
168
  let(:ast) { Reek::Source::SourceCode.from(file).syntax_tree }
83
169
 
84
170
  it 'returns the right line number' do
@@ -86,8 +172,8 @@ RSpec.describe Reek::AST::Node do
86
172
  end
87
173
  end
88
174
 
89
- context 'source from string' do
90
- let(:source) { File.read(SAMPLES_PATH.join('smelly.rb')) }
175
+ context 'with source from a string' do
176
+ let(:source) { File.read(SMELLY_FILE) }
91
177
  let(:ast) { Reek::Source::SourceCode.from(source).syntax_tree }
92
178
 
93
179
  it 'returns the right line number' do
@@ -97,17 +183,17 @@ RSpec.describe Reek::AST::Node do
97
183
  end
98
184
 
99
185
  describe '#source' do
100
- context 'source from file' do
101
- let(:file) { SAMPLES_PATH.join('smelly.rb') }
186
+ context 'with source from a file' do
187
+ let(:file) { SMELLY_FILE }
102
188
  let(:ast) { Reek::Source::SourceCode.from(file).syntax_tree }
103
189
 
104
190
  it 'returns the file name' do
105
- expect(ast.source).to eq(SAMPLES_PATH.join('smelly.rb').to_s)
191
+ expect(ast.source).to eq(SMELLY_FILE.to_s)
106
192
  end
107
193
  end
108
194
 
109
- context 'source from string' do
110
- let(:source) { File.read(SAMPLES_PATH.join('smelly.rb')) }
195
+ context 'with source from a string' do
196
+ let(:source) { File.read SMELLY_FILE }
111
197
  let(:ast) { Reek::Source::SourceCode.from(source).syntax_tree }
112
198
 
113
199
  it 'returns "string"' do
@@ -115,4 +201,11 @@ RSpec.describe Reek::AST::Node do
115
201
  end
116
202
  end
117
203
  end
204
+
205
+ describe '#name' do
206
+ it 'returns #to_s if no override is present' do
207
+ ast = sexp(:foo)
208
+ expect(ast.name).to eq ast.to_s
209
+ end
210
+ end
118
211
  end
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
2
2
  require_lib 'reek/ast/reference_collector'
3
3
 
4
4
  RSpec.describe Reek::AST::ReferenceCollector do
5
- context 'counting refs to self' do
5
+ describe '#num_refs_to_self' do
6
6
  def refs_to_self(src)
7
7
  syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
8
8
  described_class.new(syntax_tree).num_refs_to_self
@@ -107,7 +107,7 @@ RSpec.describe Reek::AST::SexpExtensions::DefNode do
107
107
  end
108
108
 
109
109
  it 'finds nodes in the body with #body_nodes' do
110
- expect(node.body_nodes([:first])).to eq [sexp(:first)]
110
+ expect(node.body_nodes([:first]).to_a).to eq [sexp(:first)]
111
111
  end
112
112
  end
113
113
 
@@ -253,6 +253,7 @@ end
253
253
 
254
254
  RSpec.describe Reek::AST::SexpExtensions::LvarNode do
255
255
  let(:node) { sexp(:lvar, :foo) }
256
+
256
257
  describe '#var_name' do
257
258
  it 'returns the lvar’s name' do
258
259
  expect(node.var_name).to eq(:foo)
@@ -302,12 +303,8 @@ RSpec.describe Reek::AST::SexpExtensions::SendNode do
302
303
  context 'with no parameters' do
303
304
  let(:node) { sexp(:send, nil, :hello) }
304
305
 
305
- it 'has no argument names' do
306
- expect(node.arg_names).to eq []
307
- end
308
-
309
306
  it 'is not considered to be a writable attr' do
310
- expect(sexp(:send, nil, :attr).attr_with_writable_flag?).to be_falsey
307
+ expect(sexp(:send, nil, :attr)).not_to be_attr_with_writable_flag
311
308
  end
312
309
  end
313
310
 
@@ -315,15 +312,15 @@ RSpec.describe Reek::AST::SexpExtensions::SendNode do
315
312
  let(:bare_new) { sexp(:send, nil, :new) }
316
313
 
317
314
  it 'is not considered to be a module creation call' do
318
- expect(bare_new.module_creation_call?).to be_falsey
315
+ expect(bare_new).not_to be_module_creation_call
319
316
  end
320
317
 
321
318
  it 'is not considered to have a module creation receiver' do
322
- expect(bare_new.module_creation_receiver?).to be_falsey
319
+ expect(bare_new).not_to be_module_creation_receiver
323
320
  end
324
321
 
325
322
  it 'is considered to be an object creation call' do
326
- expect(bare_new.object_creation_call?).to be_truthy
323
+ expect(bare_new).to be_object_creation_call
327
324
  end
328
325
  end
329
326
 
@@ -331,31 +328,15 @@ RSpec.describe Reek::AST::SexpExtensions::SendNode do
331
328
  let(:node) { Reek::Source::SourceCode.from('(foo ? bar : baz).new').syntax_tree }
332
329
 
333
330
  it 'is not considered to be a module creation call' do
334
- expect(node.module_creation_call?).to be_falsey
331
+ expect(node).not_to be_module_creation_call
335
332
  end
336
333
 
337
334
  it 'is not considered to have a module creation receiver' do
338
- expect(node.module_creation_receiver?).to be_falsey
335
+ expect(node).not_to be_module_creation_receiver
339
336
  end
340
337
 
341
338
  it 'is considered to be an object creation call' do
342
- expect(node.object_creation_call?).to be_truthy
343
- end
344
- end
345
-
346
- context 'with 1 literal parameter' do
347
- let(:node) { sexp(:send, nil, :hello, sexp(:lit, :param)) }
348
-
349
- it 'has 1 argument name' do
350
- expect(node.arg_names).to eq [:param]
351
- end
352
- end
353
-
354
- context 'with 2 literal parameters' do
355
- let(:node) { sexp(:send, nil, :hello, sexp(:lit, :x), sexp(:lit, :y)) }
356
-
357
- it 'has 2 argument names' do
358
- expect(node.arg_names).to eq [:x, :y]
339
+ expect(node).to be_object_creation_call
359
340
  end
360
341
  end
361
342
  end
@@ -393,7 +374,7 @@ end
393
374
  RSpec.describe Reek::AST::SexpExtensions::LambdaNode do
394
375
  let(:node) { sexp(:lambda) }
395
376
 
396
- context '#name' do
377
+ describe '#name' do
397
378
  it 'returns :lambda' do
398
379
  expect(node.name).to eq 'lambda'
399
380
  end
@@ -465,14 +446,14 @@ RSpec.describe Reek::AST::SexpExtensions::CasgnNode do
465
446
  context 'with single assignment' do
466
447
  it 'does not define a module' do
467
448
  exp = sexp(:casgn, nil, :Foo)
468
- expect(exp.defines_module?).to be_falsey
449
+ expect(exp).not_to be_defines_module
469
450
  end
470
451
  end
471
452
 
472
453
  context 'with implicit receiver to new' do
473
454
  it 'does not define a module' do
474
455
  exp = sexp(:casgn, nil, :Foo, sexp(:send, nil, :new))
475
- expect(exp.defines_module?).to be_falsey
456
+ expect(exp).not_to be_defines_module
476
457
  end
477
458
  end
478
459
 
@@ -480,7 +461,7 @@ RSpec.describe Reek::AST::SexpExtensions::CasgnNode do
480
461
  it 'does not define a module' do
481
462
  exp = Reek::Source::SourceCode.from('Foo = Class.new(Bar)').syntax_tree
482
463
 
483
- expect(exp.defines_module?).to be_truthy
464
+ expect(exp).to be_defines_module
484
465
  end
485
466
  end
486
467
 
@@ -488,7 +469,7 @@ RSpec.describe Reek::AST::SexpExtensions::CasgnNode do
488
469
  it 'does not define a module' do
489
470
  exp = Reek::Source::SourceCode.from('C = ->{}').syntax_tree
490
471
 
491
- expect(exp.defines_module?).to be_falsey
472
+ expect(exp).not_to be_defines_module
492
473
  end
493
474
  end
494
475
 
@@ -496,7 +477,7 @@ RSpec.describe Reek::AST::SexpExtensions::CasgnNode do
496
477
  it 'does not define a module' do
497
478
  exp = Reek::Source::SourceCode.from('C = "hello"').syntax_tree
498
479
 
499
- expect(exp.defines_module?).to be_falsey
480
+ expect(exp).not_to be_defines_module
500
481
  end
501
482
  end
502
483
  end