reek 6.0.2 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +13 -0
  3. data/.github/workflows/ruby.yml +57 -0
  4. data/.rubocop.yml +6 -12
  5. data/.rubocop_todo.yml +6 -4
  6. data/CHANGELOG.md +95 -0
  7. data/CONTRIBUTING.md +10 -10
  8. data/Dockerfile +1 -1
  9. data/Gemfile +8 -7
  10. data/README.md +29 -29
  11. data/bin/code_climate_reek +56 -8
  12. data/lib/reek/ast/ast_node_class_map.rb +1 -1
  13. data/lib/reek/ast/node.rb +1 -1
  14. data/lib/reek/ast/sexp_extensions/arguments.rb +20 -0
  15. data/lib/reek/ast/sexp_extensions/case.rb +1 -1
  16. data/lib/reek/ast/sexp_extensions/if.rb +1 -1
  17. data/lib/reek/ast/sexp_extensions/send.rb +22 -7
  18. data/lib/reek/cli/command/todo_list_command.rb +3 -3
  19. data/lib/reek/cli/options.rb +6 -6
  20. data/lib/reek/{report/code_climate → code_climate}/code_climate_configuration.rb +1 -1
  21. data/lib/reek/{report/code_climate → code_climate}/code_climate_configuration.yml +41 -41
  22. data/lib/reek/{report/code_climate → code_climate}/code_climate_fingerprint.rb +2 -2
  23. data/lib/reek/{report/code_climate → code_climate}/code_climate_formatter.rb +2 -4
  24. data/lib/reek/{report/code_climate → code_climate}/code_climate_report.rb +3 -3
  25. data/lib/reek/code_comment.rb +25 -20
  26. data/lib/reek/configuration/app_configuration.rb +5 -5
  27. data/lib/reek/configuration/configuration_converter.rb +1 -1
  28. data/lib/reek/configuration/configuration_file_finder.rb +5 -4
  29. data/lib/reek/configuration/default_directive.rb +1 -1
  30. data/lib/reek/configuration/directory_directives.rb +1 -1
  31. data/lib/reek/configuration/excluded_paths.rb +3 -2
  32. data/lib/reek/configuration/schema.rb +177 -0
  33. data/lib/reek/configuration/schema_validator.rb +12 -13
  34. data/lib/reek/context/attribute_context.rb +1 -1
  35. data/lib/reek/context/code_context.rb +1 -1
  36. data/lib/reek/context/method_context.rb +1 -1
  37. data/lib/reek/context/module_context.rb +4 -0
  38. data/lib/reek/context/refinement_context.rb +16 -0
  39. data/lib/reek/context/send_context.rb +7 -1
  40. data/lib/reek/context_builder.rb +17 -3
  41. data/lib/reek/documentation_link.rb +3 -5
  42. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +2 -2
  43. data/lib/reek/errors/bad_detector_in_comment_error.rb +2 -2
  44. data/lib/reek/errors/encoding_error.rb +1 -1
  45. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +2 -2
  46. data/lib/reek/errors/incomprehensible_source_error.rb +1 -1
  47. data/lib/reek/errors/legacy_comment_separator_error.rb +2 -2
  48. data/lib/reek/errors/syntax_error.rb +1 -1
  49. data/lib/reek/rake/task.rb +5 -5
  50. data/lib/reek/smell_detectors/base_detector.rb +1 -1
  51. data/lib/reek/smell_detectors/class_variable.rb +2 -2
  52. data/lib/reek/smell_detectors/control_parameter_helpers/candidate.rb +6 -6
  53. data/lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb +1 -1
  54. data/lib/reek/smell_detectors/duplicate_method_call.rb +5 -5
  55. data/lib/reek/smell_detectors/instance_variable_assumption.rb +8 -8
  56. data/lib/reek/smell_detectors/nested_iterators.rb +4 -3
  57. data/lib/reek/smell_detectors/unused_private_method.rb +3 -2
  58. data/lib/reek/smell_warning.rb +1 -1
  59. data/lib/reek/source/source_locator.rb +1 -3
  60. data/lib/reek/spec/should_reek_of.rb +11 -9
  61. data/lib/reek/spec.rb +1 -1
  62. data/lib/reek/version.rb +2 -2
  63. data/reek.gemspec +29 -25
  64. metadata +37 -250
  65. data/.travis.yml +0 -40
  66. data/docs/API.md +0 -174
  67. data/docs/Attribute.md +0 -39
  68. data/docs/Basic-Smell-Options.md +0 -85
  69. data/docs/Boolean-Parameter.md +0 -54
  70. data/docs/Class-Variable.md +0 -40
  71. data/docs/Code-Smells.md +0 -39
  72. data/docs/Command-Line-Options.md +0 -119
  73. data/docs/Control-Couple.md +0 -26
  74. data/docs/Control-Parameter.md +0 -32
  75. data/docs/Data-Clump.md +0 -46
  76. data/docs/Duplicate-Method-Call.md +0 -264
  77. data/docs/Feature-Envy.md +0 -93
  78. data/docs/How-To-Write-New-Detectors.md +0 -132
  79. data/docs/How-reek-works-internally.md +0 -114
  80. data/docs/Instance-Variable-Assumption.md +0 -163
  81. data/docs/Irresponsible-Module.md +0 -47
  82. data/docs/Large-Class.md +0 -16
  83. data/docs/Long-Parameter-List.md +0 -39
  84. data/docs/Long-Yield-List.md +0 -37
  85. data/docs/Manual-Dispatch.md +0 -30
  86. data/docs/Missing-Safe-Method.md +0 -92
  87. data/docs/Module-Initialize.md +0 -62
  88. data/docs/Nested-Iterators.md +0 -59
  89. data/docs/Nil-Check.md +0 -47
  90. data/docs/RSpec-matchers.md +0 -129
  91. data/docs/Rake-Task.md +0 -66
  92. data/docs/Reek-4-to-Reek-5-migration.md +0 -188
  93. data/docs/Reek-Driven-Development.md +0 -46
  94. data/docs/Repeated-Conditional.md +0 -47
  95. data/docs/Simulated-Polymorphism.md +0 -16
  96. data/docs/Smell-Suppression.md +0 -96
  97. data/docs/Style-Guide.md +0 -19
  98. data/docs/Subclassed-From-Core-Class.md +0 -79
  99. data/docs/Too-Many-Constants.md +0 -37
  100. data/docs/Too-Many-Instance-Variables.md +0 -43
  101. data/docs/Too-Many-Methods.md +0 -56
  102. data/docs/Too-Many-Statements.md +0 -54
  103. data/docs/Uncommunicative-Method-Name.md +0 -94
  104. data/docs/Uncommunicative-Module-Name.md +0 -92
  105. data/docs/Uncommunicative-Name.md +0 -18
  106. data/docs/Uncommunicative-Parameter-Name.md +0 -90
  107. data/docs/Uncommunicative-Variable-Name.md +0 -96
  108. data/docs/Unused-Parameters.md +0 -28
  109. data/docs/Unused-Private-Method.md +0 -101
  110. data/docs/Utility-Function.md +0 -56
  111. data/docs/Versioning-Policy.md +0 -7
  112. data/docs/YAML-Reports.md +0 -93
  113. data/docs/defaults.reek.yml +0 -129
  114. data/docs/templates/default/docstring/html/public_api_marker.erb +0 -3
  115. data/docs/templates/default/docstring/setup.rb +0 -37
  116. data/docs/templates/default/fulldoc/html/css/common.css +0 -1
  117. data/docs/yard_plugin.rb +0 -17
  118. data/features/command_line_interface/basic_usage.feature +0 -15
  119. data/features/command_line_interface/options.feature +0 -123
  120. data/features/command_line_interface/show_progress.feature +0 -33
  121. data/features/command_line_interface/smell_selection.feature +0 -15
  122. data/features/command_line_interface/smells_count.feature +0 -38
  123. data/features/command_line_interface/stdin.feature +0 -65
  124. data/features/configuration_files/accept_setting.feature +0 -87
  125. data/features/configuration_files/directory_specific_directives.feature +0 -274
  126. data/features/configuration_files/exclude_directives.feature +0 -35
  127. data/features/configuration_files/exclude_paths_directives.feature +0 -42
  128. data/features/configuration_files/masking_smells.feature +0 -94
  129. data/features/configuration_files/mix_accept_reject_setting.feature +0 -84
  130. data/features/configuration_files/reject_setting.feature +0 -89
  131. data/features/configuration_files/schema_validation.feature +0 -59
  132. data/features/configuration_files/show_configuration_file.feature +0 -44
  133. data/features/configuration_files/unused_private_method.feature +0 -68
  134. data/features/configuration_loading.feature +0 -91
  135. data/features/configuration_via_source_comments/erroneous_source_comments.feature +0 -68
  136. data/features/configuration_via_source_comments/well_formed_source_comments.feature +0 -116
  137. data/features/locales.feature +0 -32
  138. data/features/programmatic_access.feature +0 -41
  139. data/features/rake_task/rake_task.feature +0 -138
  140. data/features/reports/codeclimate.feature +0 -59
  141. data/features/reports/json.feature +0 -59
  142. data/features/reports/reports.feature +0 -219
  143. data/features/reports/yaml.feature +0 -52
  144. data/features/rspec_matcher.feature +0 -41
  145. data/features/samples.feature +0 -305
  146. data/features/step_definitions/.rubocop.yml +0 -5
  147. data/features/step_definitions/reek_steps.rb +0 -102
  148. data/features/step_definitions/sample_file_steps.rb +0 -63
  149. data/features/support/env.rb +0 -33
  150. data/features/todo_list.feature +0 -108
  151. data/lib/reek/configuration/schema.yml +0 -210
  152. data/samples/checkstyle.xml +0 -7
  153. data/samples/clean_source/clean.rb +0 -6
  154. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +0 -29
  155. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +0 -30
  156. data/samples/configuration/corrupt.reek +0 -1
  157. data/samples/configuration/empty.reek +0 -0
  158. data/samples/configuration/full_configuration.reek +0 -13
  159. data/samples/configuration/full_mask.reek +0 -6
  160. data/samples/configuration/home/home.reek.yml +0 -4
  161. data/samples/configuration/partial_mask.reek +0 -4
  162. data/samples/configuration/regular_configuration/.reek.yml +0 -4
  163. data/samples/configuration/regular_configuration/empty_sub_directory/.gitignore +0 -0
  164. data/samples/configuration/with_excluded_paths.reek +0 -5
  165. data/samples/no_config_file/.keep +0 -0
  166. data/samples/paths.rb +0 -5
  167. data/samples/smelly_source/inline.rb +0 -704
  168. data/samples/smelly_source/optparse.rb +0 -1788
  169. data/samples/smelly_source/redcloth.rb +0 -1130
  170. data/samples/smelly_source/ruby.rb +0 -368
  171. data/samples/smelly_source/smelly.rb +0 -7
  172. data/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +0 -5
  173. data/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +0 -2
  174. data/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +0 -6
  175. data/samples/source_with_exclude_paths/nested/uncommunicative_variable_name.rb +0 -6
  176. data/samples/source_with_hidden_directories/.hidden/hidden.rb +0 -1
  177. data/samples/source_with_hidden_directories/not_hidden.rb +0 -1
  178. data/samples/source_with_non_ruby_files/gibberish +0 -1
  179. data/samples/source_with_non_ruby_files/python_source.py +0 -1
  180. data/samples/source_with_non_ruby_files/ruby.rb +0 -6
  181. data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +0 -15
  182. data/spec/quality/documentation_spec.rb +0 -41
  183. data/spec/quality/reek_source_spec.rb +0 -11
  184. data/spec/reek/ast/node_spec.rb +0 -211
  185. data/spec/reek/ast/object_refs_spec.rb +0 -83
  186. data/spec/reek/ast/reference_collector_spec.rb +0 -47
  187. data/spec/reek/ast/sexp_extensions_spec.rb +0 -498
  188. data/spec/reek/cli/application_spec.rb +0 -168
  189. data/spec/reek/cli/command/report_command_spec.rb +0 -44
  190. data/spec/reek/cli/command/todo_list_command_spec.rb +0 -86
  191. data/spec/reek/cli/options_spec.rb +0 -51
  192. data/spec/reek/cli/silencer_spec.rb +0 -28
  193. data/spec/reek/code_comment_spec.rb +0 -184
  194. data/spec/reek/configuration/app_configuration_spec.rb +0 -195
  195. data/spec/reek/configuration/configuration_file_finder_spec.rb +0 -230
  196. data/spec/reek/configuration/default_directive_spec.rb +0 -13
  197. data/spec/reek/configuration/directory_directives_spec.rb +0 -122
  198. data/spec/reek/configuration/excluded_paths_spec.rb +0 -16
  199. data/spec/reek/configuration/rake_task_converter_spec.rb +0 -33
  200. data/spec/reek/configuration/schema_validator_spec.rb +0 -165
  201. data/spec/reek/context/code_context_spec.rb +0 -192
  202. data/spec/reek/context/ghost_context_spec.rb +0 -60
  203. data/spec/reek/context/method_context_spec.rb +0 -72
  204. data/spec/reek/context/module_context_spec.rb +0 -55
  205. data/spec/reek/context/root_context_spec.rb +0 -12
  206. data/spec/reek/context/statement_counter_spec.rb +0 -24
  207. data/spec/reek/context_builder_spec.rb +0 -457
  208. data/spec/reek/detector_repository_spec.rb +0 -22
  209. data/spec/reek/documentation_link_spec.rb +0 -20
  210. data/spec/reek/errors/base_error_spec.rb +0 -13
  211. data/spec/reek/examiner_spec.rb +0 -309
  212. data/spec/reek/logging_error_handler_spec.rb +0 -24
  213. data/spec/reek/rake/task_spec.rb +0 -56
  214. data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +0 -22
  215. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +0 -126
  216. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +0 -51
  217. data/spec/reek/report/code_climate/code_climate_report_spec.rb +0 -56
  218. data/spec/reek/report/html_report_spec.rb +0 -19
  219. data/spec/reek/report/json_report_spec.rb +0 -58
  220. data/spec/reek/report/location_formatter_spec.rb +0 -32
  221. data/spec/reek/report/progress_formatter_spec.rb +0 -68
  222. data/spec/reek/report/text_report_spec.rb +0 -89
  223. data/spec/reek/report/xml_report_spec.rb +0 -24
  224. data/spec/reek/report/yaml_report_spec.rb +0 -55
  225. data/spec/reek/report_spec.rb +0 -28
  226. data/spec/reek/smell_configuration_spec.rb +0 -56
  227. data/spec/reek/smell_detectors/attribute_spec.rb +0 -197
  228. data/spec/reek/smell_detectors/base_detector_spec.rb +0 -50
  229. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +0 -93
  230. data/spec/reek/smell_detectors/class_variable_spec.rb +0 -106
  231. data/spec/reek/smell_detectors/control_parameter_spec.rb +0 -300
  232. data/spec/reek/smell_detectors/data_clump_spec.rb +0 -134
  233. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +0 -211
  234. data/spec/reek/smell_detectors/feature_envy_spec.rb +0 -295
  235. data/spec/reek/smell_detectors/instance_variable_assumption_spec.rb +0 -96
  236. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -226
  237. data/spec/reek/smell_detectors/long_parameter_list_spec.rb +0 -61
  238. data/spec/reek/smell_detectors/long_yield_list_spec.rb +0 -49
  239. data/spec/reek/smell_detectors/manual_dispatch_spec.rb +0 -75
  240. data/spec/reek/smell_detectors/missing_safe_method_spec.rb +0 -68
  241. data/spec/reek/smell_detectors/module_initialize_spec.rb +0 -77
  242. data/spec/reek/smell_detectors/nested_iterators_spec.rb +0 -333
  243. data/spec/reek/smell_detectors/nil_check_spec.rb +0 -100
  244. data/spec/reek/smell_detectors/repeated_conditional_spec.rb +0 -100
  245. data/spec/reek/smell_detectors/subclassed_from_core_class_spec.rb +0 -77
  246. data/spec/reek/smell_detectors/too_many_constants_spec.rb +0 -144
  247. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +0 -132
  248. data/spec/reek/smell_detectors/too_many_methods_spec.rb +0 -54
  249. data/spec/reek/smell_detectors/too_many_statements_spec.rb +0 -90
  250. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +0 -78
  251. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +0 -78
  252. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +0 -147
  253. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +0 -201
  254. data/spec/reek/smell_detectors/unused_parameters_spec.rb +0 -114
  255. data/spec/reek/smell_detectors/unused_private_method_spec.rb +0 -205
  256. data/spec/reek/smell_detectors/utility_function_spec.rb +0 -293
  257. data/spec/reek/smell_warning_spec.rb +0 -137
  258. data/spec/reek/source/source_code_spec.rb +0 -79
  259. data/spec/reek/source/source_locator_spec.rb +0 -166
  260. data/spec/reek/spec/should_reek_of_spec.rb +0 -153
  261. data/spec/reek/spec/should_reek_only_of_spec.rb +0 -91
  262. data/spec/reek/spec/should_reek_spec.rb +0 -52
  263. data/spec/reek/spec/smell_matcher_spec.rb +0 -87
  264. data/spec/reek/tree_dresser_spec.rb +0 -46
  265. data/spec/spec_helper.rb +0 -110
  266. data/tasks/configuration.rake +0 -18
  267. data/tasks/console.rake +0 -5
  268. data/tasks/reek.rake +0 -6
  269. data/tasks/rubocop.rake +0 -11
  270. data/tasks/test.rake +0 -32
  271. /data/lib/reek/{report/code_climate.rb → code_climate.rb} +0 -0
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../base_report'
3
+ require_relative '../report/base_report'
4
4
  require_relative 'code_climate_formatter'
5
5
 
6
6
  module Reek
7
- module Report
7
+ module CodeClimate
8
8
  #
9
9
  # Displays a list of smells in Code Climate engine format
10
10
  # (https://github.com/codeclimate/spec/blob/master/SPEC.md)
11
11
  # JSON with empty array for 0 smells
12
12
  #
13
- class CodeClimateReport < BaseReport
13
+ class CodeClimateReport < Report::BaseReport
14
14
  def show(out = $stdout)
15
15
  smells.map do |smell|
16
16
  out.print CodeClimateFormatter.new(smell).render
@@ -19,8 +19,8 @@ module Reek
19
19
  (\w+) # smell detector e.g.: UncommunicativeVariableName
20
20
  (:?\s*) # separator
21
21
  (\{.*?\})? # details in hash style e.g.: { max_methods: 30 }
22
- /x.freeze
23
- SANITIZE_REGEX = /(#|\n|\s)+/.freeze # Matches '#', newlines and > 1 whitespaces.
22
+ /x
23
+ SANITIZE_REGEX = /(#|\n|\s)+/ # Matches '#', newlines and > 1 whitespaces.
24
24
  DISABLE_DETECTOR_CONFIGURATION = '{ enabled: false }'
25
25
  MINIMUM_CONTENT_LENGTH = 2
26
26
 
@@ -39,13 +39,13 @@ module Reek
39
39
 
40
40
  @original_comment.scan(CONFIGURATION_REGEX) do |detector_name, separator, options|
41
41
  escalate_legacy_separator separator
42
- CodeCommentValidator.new(detector_name: detector_name,
43
- original_comment: original_comment,
44
- line: line,
45
- source: source,
46
- options: options).validate
47
- @config.merge! detector_name => YAML.safe_load(options || DISABLE_DETECTOR_CONFIGURATION,
48
- permitted_classes: [Regexp])
42
+ validator = CodeCommentValidator.new(detector_name: detector_name,
43
+ original_comment: original_comment,
44
+ line: line,
45
+ source: source,
46
+ options: options)
47
+ validator.validate
48
+ @config.merge! detector_name => validator.parsed_options
49
49
  end
50
50
  end
51
51
 
@@ -115,6 +115,21 @@ module Reek
115
115
  escalate_unknown_configuration_key
116
116
  end
117
117
 
118
+ def parsed_options
119
+ @parsed_options ||=
120
+ if Psych::VERSION < '3.1.0'
121
+ YAML.safe_load(options || CodeComment::DISABLE_DETECTOR_CONFIGURATION, [Regexp])
122
+ else
123
+ YAML.safe_load(options || CodeComment::DISABLE_DETECTOR_CONFIGURATION,
124
+ permitted_classes: [Regexp])
125
+ end
126
+ rescue Psych::SyntaxError
127
+ raise Errors::GarbageDetectorConfigurationInCommentError.new(detector_name: detector_name,
128
+ original_comment: original_comment,
129
+ source: source,
130
+ line: line)
131
+ end
132
+
118
133
  private
119
134
 
120
135
  attr_reader :detector_name,
@@ -124,16 +139,6 @@ module Reek
124
139
  :separator,
125
140
  :options
126
141
 
127
- def parsed_options
128
- @parsed_options ||= YAML.safe_load(options || CodeComment::DISABLE_DETECTOR_CONFIGURATION,
129
- permitted_classes: [Regexp])
130
- rescue Psych::SyntaxError
131
- raise Errors::GarbageDetectorConfigurationInCommentError.new(detector_name: detector_name,
132
- original_comment: original_comment,
133
- source: source,
134
- line: line)
135
- end
136
-
137
142
  def escalate_unknown_configuration_key
138
143
  return if given_keys_legit?
139
144
 
@@ -165,7 +170,7 @@ module Reek
165
170
 
166
171
  # @return [Set] the configuration keys that are found in the code comment
167
172
  def given_configuration_keys
168
- parsed_options.keys.map(&:to_sym).to_set
173
+ parsed_options.keys.to_set(&:to_sym)
169
174
  end
170
175
 
171
176
  # @return [String] all keys from the code comment that look bad
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'pathname'
4
- require_relative './configuration_file_finder'
5
- require_relative './configuration_validator'
6
- require_relative './default_directive'
7
- require_relative './directory_directives'
8
- require_relative './excluded_paths'
4
+ require_relative 'configuration_file_finder'
5
+ require_relative 'configuration_validator'
6
+ require_relative 'default_directive'
7
+ require_relative 'directory_directives'
8
+ require_relative 'excluded_paths'
9
9
 
10
10
  module Reek
11
11
  module Configuration
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './configuration_validator'
3
+ require_relative 'configuration_validator'
4
4
 
5
5
  module Reek
6
6
  module Configuration
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'pathname'
4
- require_relative './configuration_converter'
5
- require_relative './schema_validator'
4
+ require_relative 'configuration_converter'
5
+ require_relative 'schema_validator'
6
6
  require_relative '../errors/config_file_error'
7
7
 
8
8
  module Reek
@@ -58,11 +58,11 @@ module Reek
58
58
 
59
59
  begin
60
60
  configuration = YAML.load_file(path) || {}
61
+ SchemaValidator.new(configuration).validate
61
62
  rescue StandardError => error
62
63
  raise Errors::ConfigFileError, "Invalid configuration file #{path}, error is #{error}"
63
64
  end
64
65
 
65
- SchemaValidator.new(configuration).validate
66
66
  ConfigurationConverter.new(configuration).convert
67
67
  end
68
68
 
@@ -87,7 +87,8 @@ module Reek
87
87
  #
88
88
  # @quality :reek:FeatureEnvy
89
89
  def find_in_dir(dir)
90
- dir.children.detect { |item| item.file? && item.basename.to_s == DEFAULT_FILE_NAME }
90
+ file = dir + DEFAULT_FILE_NAME
91
+ file if file.file?
91
92
  end
92
93
  end
93
94
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './configuration_validator'
3
+ require_relative 'configuration_validator'
4
4
 
5
5
  module Reek
6
6
  module Configuration
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './configuration_validator'
3
+ require_relative 'configuration_validator'
4
4
 
5
5
  module Reek
6
6
  module Configuration
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './configuration_validator'
3
+ require_relative 'configuration_validator'
4
4
  require_relative '../errors/config_file_error'
5
5
 
6
6
  module Reek
@@ -14,7 +14,8 @@ module Reek
14
14
  # @param paths [String]
15
15
  # @return [undefined]
16
16
  def add(paths)
17
- paths.each { |path| self << Pathname(path) }
17
+ paths.flat_map { |path| Dir[path] }.
18
+ each { |path| self << Pathname(path) }
18
19
  end
19
20
  end
20
21
  end
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/schema'
4
+
5
+ module Reek
6
+ module Configuration
7
+ #
8
+ # Configuration schema constants.
9
+ #
10
+ class Schema
11
+ # Enable the :info extension so we can introspect
12
+ # your keys and types
13
+ Dry::Schema.load_extensions(:info)
14
+
15
+ # rubocop:disable Metrics/BlockLength
16
+ ALL_DETECTORS_SCHEMA = Dry::Schema.Params do
17
+ optional(:Attribute).filled(:hash) do
18
+ optional(:enabled).filled(:bool)
19
+ optional(:exclude).array(:string)
20
+ end
21
+ optional(:BooleanParameter).filled(:hash) do
22
+ optional(:enabled).filled(:bool)
23
+ optional(:exclude).array(:string)
24
+ end
25
+ optional(:ClassVariable).filled(:hash) do
26
+ optional(:enabled).filled(:bool)
27
+ optional(:exclude).array(:string)
28
+ end
29
+ optional(:ControlParameter).filled(:hash) do
30
+ optional(:enabled).filled(:bool)
31
+ optional(:exclude).array(:string)
32
+ end
33
+ optional(:DataClump).filled(:hash) do
34
+ optional(:enabled).filled(:bool)
35
+ optional(:exclude).array(:string)
36
+ optional(:max_copies).filled(:integer)
37
+ optional(:min_clump_size).filled(:integer)
38
+ end
39
+ optional(:DuplicateMethodCall).filled(:hash) do
40
+ optional(:enabled).filled(:bool)
41
+ optional(:exclude).array(:string)
42
+ optional(:max_calls).filled(:integer)
43
+ optional(:allow_calls).array(:string)
44
+ end
45
+ optional(:FeatureEnvy).filled(:hash) do
46
+ optional(:enabled).filled(:bool)
47
+ optional(:exclude).array(:string)
48
+ end
49
+ optional(:InstanceVariableAssumption).filled(:hash) do
50
+ optional(:enabled).filled(:bool)
51
+ optional(:exclude).array(:string)
52
+ end
53
+ optional(:IrresponsibleModule).filled(:hash) do
54
+ optional(:enabled).filled(:bool)
55
+ optional(:exclude).array(:string)
56
+ end
57
+ optional(:LongParameterList).filled(:hash) do
58
+ optional(:enabled).filled(:bool)
59
+ optional(:exclude).array(:string)
60
+ optional(:max_params).filled(:integer)
61
+ optional(:overrides).filled(:hash) do
62
+ required(:initialize).filled(:hash) do
63
+ required(:max_params).filled(:integer)
64
+ end
65
+ end
66
+ end
67
+ optional(:LongYieldList).filled(:hash) do
68
+ optional(:enabled).filled(:bool)
69
+ optional(:exclude).array(:string)
70
+ optional(:max_params).filled(:integer)
71
+ end
72
+ optional(:ManualDispatch).filled(:hash) do
73
+ optional(:enabled).filled(:bool)
74
+ optional(:exclude).array(:string)
75
+ end
76
+ optional(:MissingSafeMethod).filled(:hash) do
77
+ optional(:enabled).filled(:bool)
78
+ optional(:exclude).array(:string)
79
+ end
80
+ optional(:ModuleInitialize).filled(:hash) do
81
+ optional(:enabled).filled(:bool)
82
+ optional(:exclude).array(:string)
83
+ end
84
+ optional(:NestedIterators).filled(:hash) do
85
+ optional(:enabled).filled(:bool)
86
+ optional(:exclude).array(:string)
87
+ optional(:max_allowed_nesting).filled(:integer)
88
+ optional(:ignore_iterators) { array(:string) & filled? }
89
+ end
90
+ optional(:NilCheck).filled(:hash) do
91
+ optional(:enabled).filled(:bool)
92
+ optional(:exclude).array(:string)
93
+ end
94
+ optional(:RepeatedConditional).filled(:hash) do
95
+ optional(:enabled).filled(:bool)
96
+ optional(:exclude).array(:string)
97
+ optional(:max_ifs).filled(:integer)
98
+ end
99
+ optional(:SubclassedFromCoreClass).filled(:hash) do
100
+ optional(:enabled).filled(:bool)
101
+ optional(:exclude).array(:string)
102
+ end
103
+ optional(:TooManyConstants).filled(:hash) do
104
+ optional(:enabled).filled(:bool)
105
+ optional(:exclude).array(:string)
106
+ optional(:max_constants).filled(:integer)
107
+ end
108
+ optional(:TooManyInstanceVariables).filled(:hash) do
109
+ optional(:enabled).filled(:bool)
110
+ optional(:exclude).array(:string)
111
+ optional(:max_instance_variables).filled(:integer)
112
+ end
113
+ optional(:TooManyMethods).filled(:hash) do
114
+ optional(:enabled).filled(:bool)
115
+ optional(:exclude).array(:string)
116
+ optional(:max_methods).filled(:integer)
117
+ end
118
+ optional(:TooManyStatements).filled(:hash) do
119
+ optional(:enabled).filled(:bool)
120
+ optional(:exclude).array(:string)
121
+ optional(:max_statements).filled(:integer)
122
+ end
123
+ optional(:UncommunicativeMethodName).filled(:hash) do
124
+ optional(:enabled).filled(:bool)
125
+ optional(:exclude).array(:string)
126
+ optional(:reject).array(:string)
127
+ optional(:accept).array(:string)
128
+ end
129
+ optional(:UncommunicativeModuleName).filled(:hash) do
130
+ optional(:enabled).filled(:bool)
131
+ optional(:exclude).array(:string)
132
+ optional(:reject).array(:string)
133
+ optional(:accept).array(:string)
134
+ end
135
+ optional(:UncommunicativeParameterName).filled(:hash) do
136
+ optional(:enabled).filled(:bool)
137
+ optional(:exclude).array(:string)
138
+ optional(:reject).array(:string)
139
+ optional(:accept).array(:string)
140
+ end
141
+ optional(:UncommunicativeVariableName).filled(:hash) do
142
+ optional(:enabled).filled(:bool)
143
+ optional(:exclude).array(:string)
144
+ optional(:reject).array(:string)
145
+ optional(:accept).array(:string)
146
+ end
147
+ optional(:UnusedParameters).filled(:hash) do
148
+ optional(:enabled).filled(:bool)
149
+ optional(:exclude).array(:string)
150
+ end
151
+ optional(:UnusedPrivateMethod).filled(:hash) do
152
+ optional(:enabled).filled(:bool)
153
+ optional(:exclude).array(:string)
154
+ end
155
+ optional(:UtilityFunction).filled(:hash) do
156
+ optional(:enabled).filled(:bool)
157
+ optional(:exclude).array(:string)
158
+ optional(:public_methods_only).filled(:bool)
159
+ end
160
+ end
161
+ # rubocop:enable Metrics/BlockLength
162
+
163
+ # @quality :reek:TooManyStatements { max_statements: 7 }
164
+ def self.schema(directories = [])
165
+ Dry::Schema.Params do
166
+ config.validate_keys = true
167
+
168
+ optional(:detectors).filled(ALL_DETECTORS_SCHEMA)
169
+ optional(:directories).filled(:hash) do
170
+ directories.each { |dir| optional(dir.to_sym).filled(ALL_DETECTORS_SCHEMA) }
171
+ end
172
+ optional(:exclude_paths).array(:string)
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
- require_relative '../cli/silencer'
5
- Reek::CLI::Silencer.without_warnings { require 'kwalify' }
6
3
  require_relative '../errors/config_file_error'
4
+ require_relative 'schema'
7
5
 
8
6
  module Reek
9
7
  module Configuration
@@ -11,28 +9,29 @@ module Reek
11
9
  # Schema validator module.
12
10
  #
13
11
  class SchemaValidator
14
- SCHEMA_FILE_PATH = File.expand_path('./schema.yml', __dir__)
15
-
16
12
  def initialize(configuration)
17
13
  @configuration = configuration
18
- @validator = CLI::Silencer.without_warnings do
19
- schema_file = Kwalify::Yaml.load_file(SCHEMA_FILE_PATH)
20
- Kwalify::Validator.new(schema_file)
21
- end
14
+ config_directories = configuration['directories']&.keys || []
15
+ @validator = Reek::Configuration::Schema.schema(config_directories)
22
16
  end
23
17
 
24
18
  def validate
25
- errors = CLI::Silencer.without_warnings { @validator.validate @configuration }
26
- return if !errors || errors.empty?
19
+ result = @validator.call(@configuration)
20
+ return if result.success?
27
21
 
28
- raise Errors::ConfigFileError, error_message(errors)
22
+ raise Errors::ConfigFileError, error_message(result.errors)
23
+ rescue NoMethodError
24
+ raise Errors::ConfigFileError, 'unrecognized configuration data'
29
25
  end
30
26
 
31
27
  private
32
28
 
33
29
  # :reek:UtilityFunction
34
30
  def error_message(errors)
35
- "We found some problems with your configuration file: #{CLI::Silencer.silently { errors.join(', ') }}"
31
+ messages = errors.map do |error|
32
+ "[/#{error.path.join('/')}] #{error.text}."
33
+ end.join("\n")
34
+ "\n#{messages}"
36
35
  end
37
36
  end
38
37
  end
@@ -14,7 +14,7 @@ module Reek
14
14
  def initialize(exp, send_expression)
15
15
  @visibility = :public
16
16
  @send_expression = send_expression
17
- super exp
17
+ super(exp)
18
18
  end
19
19
 
20
20
  def full_comment
@@ -51,7 +51,7 @@ module Reek
51
51
  # @return [Enumerator]
52
52
  #
53
53
  def each(&block)
54
- return enum_for(:each) unless block_given?
54
+ return enum_for(:each) unless block
55
55
 
56
56
  yield self
57
57
  children.each do |child|
@@ -15,7 +15,7 @@ module Reek
15
15
  def initialize(exp, parent_exp)
16
16
  @parent_exp = parent_exp
17
17
  @visibility = :public
18
- super exp
18
+ super(exp)
19
19
  end
20
20
 
21
21
  def references_self?
@@ -55,6 +55,10 @@ module Reek
55
55
  end
56
56
  end
57
57
 
58
+ def instance_method_names_via_to_call
59
+ instance_method_calls.flat_map(&:method_name_called_to_call).compact
60
+ end
61
+
58
62
  #
59
63
  # @deprecated use `defined_instance_methods` instead
60
64
  #
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'module_context'
4
+
5
+ module Reek
6
+ module Context
7
+ #
8
+ # A context wrapper for any refinement blocks found in a syntax tree.
9
+ #
10
+ class RefinementContext < ModuleContext
11
+ def full_name
12
+ exp.call.args.first.name
13
+ end
14
+ end
15
+ end
16
+ end
@@ -12,7 +12,13 @@ module Reek
12
12
 
13
13
  def initialize(exp, name)
14
14
  @name = name
15
- super exp
15
+ super(exp)
16
+ end
17
+
18
+ def method_name_called_to_call
19
+ return unless @name == :method
20
+
21
+ local_nodes(:sym).map(&:name)
16
22
  end
17
23
  end
18
24
  end
@@ -5,6 +5,7 @@ require_relative 'context/class_context'
5
5
  require_relative 'context/ghost_context'
6
6
  require_relative 'context/method_context'
7
7
  require_relative 'context/module_context'
8
+ require_relative 'context/refinement_context'
8
9
  require_relative 'context/root_context'
9
10
  require_relative 'context/send_context'
10
11
  require_relative 'context/singleton_attribute_context'
@@ -20,7 +21,7 @@ module Reek
20
21
  # counting. Ideally `ContextBuilder` would only build up the context tree and leave the
21
22
  # statement and reference counting to the contexts.
22
23
  #
23
- # @quality :reek:TooManyMethods { max_methods: 31 }
24
+ # @quality :reek:TooManyMethods { max_methods: 32 }
24
25
  # @quality :reek:UnusedPrivateMethod { exclude: [ !ruby/regexp /process_/ ] }
25
26
  # @quality :reek:DataClump
26
27
  class ContextBuilder
@@ -263,9 +264,16 @@ module Reek
263
264
  #
264
265
  # Counts non-empty blocks as one statement.
265
266
  #
267
+ # A refinement block is handled differently and causes a RefinementContext
268
+ # to be opened.
269
+ #
266
270
  def process_block(exp, _parent)
267
271
  increase_statement_count_by(exp.block)
268
- process(exp)
272
+ if exp.call.name == :refine
273
+ handle_refinement_block(exp)
274
+ else
275
+ process(exp)
276
+ end
269
277
  end
270
278
 
271
279
  # Handles `begin` and `kwbegin` nodes. `begin` nodes are created implicitly
@@ -414,7 +422,7 @@ module Reek
414
422
  # See `process_rescue` for additional reference.
415
423
  #
416
424
  def process_resbody(exp, _parent)
417
- increase_statement_count_by(exp.children[1..-1].compact)
425
+ increase_statement_count_by(exp.children[1..].compact)
418
426
  process(exp)
419
427
  end
420
428
 
@@ -508,6 +516,12 @@ module Reek
508
516
  end
509
517
  end
510
518
 
519
+ def handle_refinement_block(exp)
520
+ inside_new_context(Context::RefinementContext, exp) do
521
+ process(exp)
522
+ end
523
+ end
524
+
511
525
  def handle_send_for_modules(exp)
512
526
  arg_names = exp.args.map { |arg| arg.children.first }
513
527
  current_context.track_visibility(exp.name, arg_names)
@@ -17,12 +17,10 @@ module Reek
17
17
  Kernel.format(HELP_LINK_TEMPLATE, version: Version::STRING, item: name_to_param(subject))
18
18
  end
19
19
 
20
- # Convert the given subject name to a form that is acceptable in a URL.
20
+ # Convert the given subject name to a form that is acceptable in a URL, by
21
+ # dasherizeing it at the start of capitalized words. Spaces are discared.
21
22
  def name_to_param(name)
22
- # Splits the subject on the start of capitalized words, optionally
23
- # preceded by a space. The space is discarded, the start of the word is
24
- # not.
25
- name.split(/ *(?=[A-Z][a-z])/).join('-')
23
+ name.split(/([A-Z][a-z][a-z]*)/).map(&:strip).reject(&:empty?).join('-')
26
24
  end
27
25
  end
28
26
  end
@@ -8,7 +8,7 @@ module Reek
8
8
  # Gets raised when trying to configure a detector with an option
9
9
  # which is unknown to it.
10
10
  class BadDetectorConfigurationKeyInCommentError < BaseError
11
- UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-MESSAGE
11
+ UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-MESSAGE.freeze
12
12
 
13
13
  Error: You are trying to configure the smell detector '%<detector>s'
14
14
  in one of your source code comments with the unknown option %<option>s.
@@ -32,7 +32,7 @@ module Reek
32
32
  source: source,
33
33
  line: line,
34
34
  comment: original_comment)
35
- super message
35
+ super(message)
36
36
  end
37
37
  end
38
38
  end
@@ -9,7 +9,7 @@ module Reek
9
9
  # This might happen for multiple reasons. The users might have a typo in
10
10
  # his comment or he might use a detector that does not exist anymore.
11
11
  class BadDetectorInCommentError < BaseError
12
- UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-MESSAGE
12
+ UNKNOWN_SMELL_DETECTOR_MESSAGE = <<-MESSAGE.freeze
13
13
 
14
14
  Error: You are trying to configure an unknown smell detector '%<detector>s' in one
15
15
  of your source code comments.
@@ -31,7 +31,7 @@ module Reek
31
31
  source: source,
32
32
  line: line,
33
33
  comment: original_comment)
34
- super message
34
+ super(message)
35
35
  end
36
36
  end
37
37
  end
@@ -29,7 +29,7 @@ module Reek
29
29
  MESSAGE
30
30
 
31
31
  def initialize(origin:)
32
- super format(TEMPLATE, source: origin)
32
+ super(format(TEMPLATE, source: origin))
33
33
  end
34
34
 
35
35
  def long_message
@@ -8,7 +8,7 @@ module Reek
8
8
  # Gets raised when trying to use a configuration for a detector
9
9
  # that can't be parsed into a hash.
10
10
  class GarbageDetectorConfigurationInCommentError < BaseError
11
- BAD_DETECTOR_CONFIGURATION_MESSAGE = <<-MESSAGE
11
+ BAD_DETECTOR_CONFIGURATION_MESSAGE = <<-MESSAGE.freeze
12
12
 
13
13
  Error: You are trying to configure the smell detector '%<detector>s'.
14
14
  Unfortunately we cannot parse the configuration you have given.
@@ -30,7 +30,7 @@ module Reek
30
30
  source: source,
31
31
  line: line,
32
32
  comment: original_comment)
33
- super message
33
+ super(message)
34
34
  end
35
35
  end
36
36
  end
@@ -32,7 +32,7 @@ module Reek
32
32
  MESSAGE
33
33
 
34
34
  def initialize(origin:)
35
- super format(TEMPLATE, source: origin)
35
+ super(format(TEMPLATE, source: origin))
36
36
  end
37
37
 
38
38
  def long_message
@@ -6,7 +6,7 @@ module Reek
6
6
  module Errors
7
7
  # Gets raised for old-style comment configuration format.
8
8
  class LegacyCommentSeparatorError < BaseError
9
- MESSAGE = <<-MESSAGE
9
+ MESSAGE = <<-MESSAGE.freeze
10
10
  Error: You are using the legacy configuration format (including three
11
11
  colons) to configure Reek in one your source code comments.
12
12
 
@@ -29,7 +29,7 @@ module Reek
29
29
  source: source,
30
30
  line: line,
31
31
  comment: original_comment)
32
- super message
32
+ super(message)
33
33
  end
34
34
  end
35
35
  end