reek 6.0.2 → 6.5.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 (280) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +13 -0
  3. data/.github/workflows/ruby.yml +58 -0
  4. data/.gitignore +0 -1
  5. data/.rubocop.yml +7 -20
  6. data/.rubocop_todo.yml +6 -4
  7. data/.simplecov +2 -0
  8. data/CHANGELOG.md +114 -0
  9. data/CONTRIBUTING.md +10 -10
  10. data/Dockerfile +1 -1
  11. data/Gemfile +17 -24
  12. data/README.md +38 -40
  13. data/Rakefile +2 -0
  14. data/bin/code_climate_reek +56 -8
  15. data/docs/yard_plugin.rb +3 -1
  16. data/lib/reek/ast/ast_node_class_map.rb +1 -1
  17. data/lib/reek/ast/node.rb +16 -10
  18. data/lib/reek/ast/sexp_extensions/arguments.rb +20 -0
  19. data/lib/reek/ast/sexp_extensions/case.rb +1 -1
  20. data/lib/reek/ast/sexp_extensions/if.rb +1 -1
  21. data/lib/reek/ast/sexp_extensions/send.rb +22 -7
  22. data/lib/reek/cli/command/todo_list_command.rb +3 -3
  23. data/lib/reek/cli/options.rb +8 -8
  24. data/lib/reek/{report/code_climate → code_climate}/code_climate_configuration.rb +1 -1
  25. data/lib/reek/{report/code_climate → code_climate}/code_climate_configuration.yml +41 -41
  26. data/lib/reek/{report/code_climate → code_climate}/code_climate_fingerprint.rb +2 -2
  27. data/lib/reek/{report/code_climate → code_climate}/code_climate_formatter.rb +2 -4
  28. data/lib/reek/{report/code_climate → code_climate}/code_climate_report.rb +3 -3
  29. data/lib/reek/code_comment.rb +25 -20
  30. data/lib/reek/configuration/app_configuration.rb +5 -5
  31. data/lib/reek/configuration/configuration_converter.rb +1 -1
  32. data/lib/reek/configuration/configuration_file_finder.rb +5 -4
  33. data/lib/reek/configuration/default_directive.rb +1 -1
  34. data/lib/reek/configuration/directory_directives.rb +1 -1
  35. data/lib/reek/configuration/excluded_paths.rb +3 -2
  36. data/lib/reek/configuration/schema.rb +177 -0
  37. data/lib/reek/configuration/schema_validator.rb +12 -13
  38. data/lib/reek/context/attribute_context.rb +1 -1
  39. data/lib/reek/context/code_context.rb +3 -3
  40. data/lib/reek/context/method_context.rb +1 -1
  41. data/lib/reek/context/module_context.rb +4 -0
  42. data/lib/reek/context/refinement_context.rb +16 -0
  43. data/lib/reek/context/send_context.rb +7 -1
  44. data/lib/reek/context_builder.rb +17 -3
  45. data/lib/reek/documentation_link.rb +3 -5
  46. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +2 -2
  47. data/lib/reek/errors/bad_detector_in_comment_error.rb +2 -2
  48. data/lib/reek/errors/encoding_error.rb +1 -1
  49. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +2 -2
  50. data/lib/reek/errors/incomprehensible_source_error.rb +1 -1
  51. data/lib/reek/errors/legacy_comment_separator_error.rb +2 -2
  52. data/lib/reek/errors/syntax_error.rb +1 -1
  53. data/lib/reek/rake/task.rb +5 -5
  54. data/lib/reek/report/github_report.rb +55 -0
  55. data/lib/reek/report/text_report.rb +1 -1
  56. data/lib/reek/report.rb +7 -5
  57. data/lib/reek/smell_detectors/base_detector.rb +1 -1
  58. data/lib/reek/smell_detectors/class_variable.rb +2 -2
  59. data/lib/reek/smell_detectors/control_parameter_helpers/candidate.rb +6 -6
  60. data/lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb +1 -1
  61. data/lib/reek/smell_detectors/data_clump.rb +1 -1
  62. data/lib/reek/smell_detectors/duplicate_method_call.rb +5 -5
  63. data/lib/reek/smell_detectors/instance_variable_assumption.rb +8 -8
  64. data/lib/reek/smell_detectors/nested_iterators.rb +4 -3
  65. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +1 -1
  66. data/lib/reek/smell_detectors/unused_private_method.rb +3 -2
  67. data/lib/reek/smell_warning.rb +1 -1
  68. data/lib/reek/source/source_code.rb +11 -5
  69. data/lib/reek/source/source_locator.rb +1 -3
  70. data/lib/reek/spec/should_reek_of.rb +11 -9
  71. data/lib/reek/spec.rb +1 -1
  72. data/lib/reek/version.rb +2 -2
  73. data/reek.gemspec +33 -25
  74. metadata +41 -238
  75. data/.travis.yml +0 -40
  76. data/docs/API.md +0 -174
  77. data/docs/Attribute.md +0 -39
  78. data/docs/Basic-Smell-Options.md +0 -85
  79. data/docs/Boolean-Parameter.md +0 -54
  80. data/docs/Class-Variable.md +0 -40
  81. data/docs/Code-Smells.md +0 -39
  82. data/docs/Command-Line-Options.md +0 -119
  83. data/docs/Control-Couple.md +0 -26
  84. data/docs/Control-Parameter.md +0 -32
  85. data/docs/Data-Clump.md +0 -46
  86. data/docs/Duplicate-Method-Call.md +0 -264
  87. data/docs/Feature-Envy.md +0 -93
  88. data/docs/How-To-Write-New-Detectors.md +0 -132
  89. data/docs/How-reek-works-internally.md +0 -114
  90. data/docs/Instance-Variable-Assumption.md +0 -163
  91. data/docs/Irresponsible-Module.md +0 -47
  92. data/docs/Large-Class.md +0 -16
  93. data/docs/Long-Parameter-List.md +0 -39
  94. data/docs/Long-Yield-List.md +0 -37
  95. data/docs/Manual-Dispatch.md +0 -30
  96. data/docs/Missing-Safe-Method.md +0 -92
  97. data/docs/Module-Initialize.md +0 -62
  98. data/docs/Nested-Iterators.md +0 -59
  99. data/docs/Nil-Check.md +0 -47
  100. data/docs/RSpec-matchers.md +0 -129
  101. data/docs/Rake-Task.md +0 -66
  102. data/docs/Reek-4-to-Reek-5-migration.md +0 -188
  103. data/docs/Reek-Driven-Development.md +0 -46
  104. data/docs/Repeated-Conditional.md +0 -47
  105. data/docs/Simulated-Polymorphism.md +0 -16
  106. data/docs/Smell-Suppression.md +0 -96
  107. data/docs/Style-Guide.md +0 -19
  108. data/docs/Subclassed-From-Core-Class.md +0 -79
  109. data/docs/Too-Many-Constants.md +0 -37
  110. data/docs/Too-Many-Instance-Variables.md +0 -43
  111. data/docs/Too-Many-Methods.md +0 -56
  112. data/docs/Too-Many-Statements.md +0 -54
  113. data/docs/Uncommunicative-Method-Name.md +0 -94
  114. data/docs/Uncommunicative-Module-Name.md +0 -92
  115. data/docs/Uncommunicative-Name.md +0 -18
  116. data/docs/Uncommunicative-Parameter-Name.md +0 -90
  117. data/docs/Uncommunicative-Variable-Name.md +0 -96
  118. data/docs/Unused-Parameters.md +0 -28
  119. data/docs/Unused-Private-Method.md +0 -101
  120. data/docs/Utility-Function.md +0 -56
  121. data/docs/Versioning-Policy.md +0 -7
  122. data/docs/YAML-Reports.md +0 -93
  123. data/docs/defaults.reek.yml +0 -129
  124. data/docs/templates/default/docstring/html/public_api_marker.erb +0 -3
  125. data/docs/templates/default/docstring/setup.rb +0 -37
  126. data/docs/templates/default/fulldoc/html/css/common.css +0 -1
  127. data/features/command_line_interface/basic_usage.feature +0 -15
  128. data/features/command_line_interface/options.feature +0 -123
  129. data/features/command_line_interface/show_progress.feature +0 -33
  130. data/features/command_line_interface/smell_selection.feature +0 -15
  131. data/features/command_line_interface/smells_count.feature +0 -38
  132. data/features/command_line_interface/stdin.feature +0 -65
  133. data/features/configuration_files/accept_setting.feature +0 -87
  134. data/features/configuration_files/directory_specific_directives.feature +0 -274
  135. data/features/configuration_files/exclude_directives.feature +0 -35
  136. data/features/configuration_files/exclude_paths_directives.feature +0 -42
  137. data/features/configuration_files/masking_smells.feature +0 -94
  138. data/features/configuration_files/mix_accept_reject_setting.feature +0 -84
  139. data/features/configuration_files/reject_setting.feature +0 -89
  140. data/features/configuration_files/schema_validation.feature +0 -59
  141. data/features/configuration_files/show_configuration_file.feature +0 -44
  142. data/features/configuration_files/unused_private_method.feature +0 -68
  143. data/features/configuration_loading.feature +0 -91
  144. data/features/configuration_via_source_comments/erroneous_source_comments.feature +0 -68
  145. data/features/configuration_via_source_comments/well_formed_source_comments.feature +0 -116
  146. data/features/locales.feature +0 -32
  147. data/features/programmatic_access.feature +0 -41
  148. data/features/rake_task/rake_task.feature +0 -138
  149. data/features/reports/codeclimate.feature +0 -59
  150. data/features/reports/json.feature +0 -59
  151. data/features/reports/reports.feature +0 -219
  152. data/features/reports/yaml.feature +0 -52
  153. data/features/rspec_matcher.feature +0 -41
  154. data/features/samples.feature +0 -305
  155. data/features/step_definitions/.rubocop.yml +0 -5
  156. data/features/step_definitions/reek_steps.rb +0 -102
  157. data/features/step_definitions/sample_file_steps.rb +0 -63
  158. data/features/support/env.rb +0 -33
  159. data/features/todo_list.feature +0 -108
  160. data/lib/reek/configuration/schema.yml +0 -210
  161. data/samples/checkstyle.xml +0 -7
  162. data/samples/clean_source/clean.rb +0 -6
  163. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +0 -29
  164. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +0 -30
  165. data/samples/configuration/corrupt.reek +0 -1
  166. data/samples/configuration/empty.reek +0 -0
  167. data/samples/configuration/full_configuration.reek +0 -13
  168. data/samples/configuration/full_mask.reek +0 -6
  169. data/samples/configuration/home/home.reek.yml +0 -4
  170. data/samples/configuration/partial_mask.reek +0 -4
  171. data/samples/configuration/regular_configuration/.reek.yml +0 -4
  172. data/samples/configuration/regular_configuration/empty_sub_directory/.gitignore +0 -0
  173. data/samples/configuration/with_excluded_paths.reek +0 -5
  174. data/samples/no_config_file/.keep +0 -0
  175. data/samples/paths.rb +0 -5
  176. data/samples/smelly_source/inline.rb +0 -704
  177. data/samples/smelly_source/optparse.rb +0 -1788
  178. data/samples/smelly_source/redcloth.rb +0 -1130
  179. data/samples/smelly_source/ruby.rb +0 -368
  180. data/samples/smelly_source/smelly.rb +0 -7
  181. data/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +0 -5
  182. data/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +0 -2
  183. data/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +0 -6
  184. data/samples/source_with_exclude_paths/nested/uncommunicative_variable_name.rb +0 -6
  185. data/samples/source_with_hidden_directories/.hidden/hidden.rb +0 -1
  186. data/samples/source_with_hidden_directories/not_hidden.rb +0 -1
  187. data/samples/source_with_non_ruby_files/gibberish +0 -1
  188. data/samples/source_with_non_ruby_files/python_source.py +0 -1
  189. data/samples/source_with_non_ruby_files/ruby.rb +0 -6
  190. data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +0 -15
  191. data/spec/quality/documentation_spec.rb +0 -41
  192. data/spec/quality/reek_source_spec.rb +0 -11
  193. data/spec/reek/ast/node_spec.rb +0 -211
  194. data/spec/reek/ast/object_refs_spec.rb +0 -83
  195. data/spec/reek/ast/reference_collector_spec.rb +0 -47
  196. data/spec/reek/ast/sexp_extensions_spec.rb +0 -498
  197. data/spec/reek/cli/application_spec.rb +0 -168
  198. data/spec/reek/cli/command/report_command_spec.rb +0 -44
  199. data/spec/reek/cli/command/todo_list_command_spec.rb +0 -86
  200. data/spec/reek/cli/options_spec.rb +0 -51
  201. data/spec/reek/cli/silencer_spec.rb +0 -28
  202. data/spec/reek/code_comment_spec.rb +0 -184
  203. data/spec/reek/configuration/app_configuration_spec.rb +0 -195
  204. data/spec/reek/configuration/configuration_file_finder_spec.rb +0 -230
  205. data/spec/reek/configuration/default_directive_spec.rb +0 -13
  206. data/spec/reek/configuration/directory_directives_spec.rb +0 -122
  207. data/spec/reek/configuration/excluded_paths_spec.rb +0 -16
  208. data/spec/reek/configuration/rake_task_converter_spec.rb +0 -33
  209. data/spec/reek/configuration/schema_validator_spec.rb +0 -165
  210. data/spec/reek/context/code_context_spec.rb +0 -192
  211. data/spec/reek/context/ghost_context_spec.rb +0 -60
  212. data/spec/reek/context/method_context_spec.rb +0 -72
  213. data/spec/reek/context/module_context_spec.rb +0 -55
  214. data/spec/reek/context/root_context_spec.rb +0 -12
  215. data/spec/reek/context/statement_counter_spec.rb +0 -24
  216. data/spec/reek/context_builder_spec.rb +0 -457
  217. data/spec/reek/detector_repository_spec.rb +0 -22
  218. data/spec/reek/documentation_link_spec.rb +0 -20
  219. data/spec/reek/errors/base_error_spec.rb +0 -13
  220. data/spec/reek/examiner_spec.rb +0 -309
  221. data/spec/reek/logging_error_handler_spec.rb +0 -24
  222. data/spec/reek/rake/task_spec.rb +0 -56
  223. data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +0 -22
  224. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +0 -126
  225. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +0 -51
  226. data/spec/reek/report/code_climate/code_climate_report_spec.rb +0 -56
  227. data/spec/reek/report/html_report_spec.rb +0 -19
  228. data/spec/reek/report/json_report_spec.rb +0 -58
  229. data/spec/reek/report/location_formatter_spec.rb +0 -32
  230. data/spec/reek/report/progress_formatter_spec.rb +0 -68
  231. data/spec/reek/report/text_report_spec.rb +0 -89
  232. data/spec/reek/report/xml_report_spec.rb +0 -24
  233. data/spec/reek/report/yaml_report_spec.rb +0 -55
  234. data/spec/reek/report_spec.rb +0 -28
  235. data/spec/reek/smell_configuration_spec.rb +0 -56
  236. data/spec/reek/smell_detectors/attribute_spec.rb +0 -197
  237. data/spec/reek/smell_detectors/base_detector_spec.rb +0 -50
  238. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +0 -93
  239. data/spec/reek/smell_detectors/class_variable_spec.rb +0 -106
  240. data/spec/reek/smell_detectors/control_parameter_spec.rb +0 -300
  241. data/spec/reek/smell_detectors/data_clump_spec.rb +0 -134
  242. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +0 -211
  243. data/spec/reek/smell_detectors/feature_envy_spec.rb +0 -295
  244. data/spec/reek/smell_detectors/instance_variable_assumption_spec.rb +0 -96
  245. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -226
  246. data/spec/reek/smell_detectors/long_parameter_list_spec.rb +0 -61
  247. data/spec/reek/smell_detectors/long_yield_list_spec.rb +0 -49
  248. data/spec/reek/smell_detectors/manual_dispatch_spec.rb +0 -75
  249. data/spec/reek/smell_detectors/missing_safe_method_spec.rb +0 -68
  250. data/spec/reek/smell_detectors/module_initialize_spec.rb +0 -77
  251. data/spec/reek/smell_detectors/nested_iterators_spec.rb +0 -333
  252. data/spec/reek/smell_detectors/nil_check_spec.rb +0 -100
  253. data/spec/reek/smell_detectors/repeated_conditional_spec.rb +0 -100
  254. data/spec/reek/smell_detectors/subclassed_from_core_class_spec.rb +0 -77
  255. data/spec/reek/smell_detectors/too_many_constants_spec.rb +0 -144
  256. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +0 -132
  257. data/spec/reek/smell_detectors/too_many_methods_spec.rb +0 -54
  258. data/spec/reek/smell_detectors/too_many_statements_spec.rb +0 -90
  259. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +0 -78
  260. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +0 -78
  261. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +0 -147
  262. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +0 -201
  263. data/spec/reek/smell_detectors/unused_parameters_spec.rb +0 -114
  264. data/spec/reek/smell_detectors/unused_private_method_spec.rb +0 -205
  265. data/spec/reek/smell_detectors/utility_function_spec.rb +0 -293
  266. data/spec/reek/smell_warning_spec.rb +0 -137
  267. data/spec/reek/source/source_code_spec.rb +0 -79
  268. data/spec/reek/source/source_locator_spec.rb +0 -166
  269. data/spec/reek/spec/should_reek_of_spec.rb +0 -153
  270. data/spec/reek/spec/should_reek_only_of_spec.rb +0 -91
  271. data/spec/reek/spec/should_reek_spec.rb +0 -52
  272. data/spec/reek/spec/smell_matcher_spec.rb +0 -87
  273. data/spec/reek/tree_dresser_spec.rb +0 -46
  274. data/spec/spec_helper.rb +0 -110
  275. data/tasks/configuration.rake +0 -18
  276. data/tasks/console.rake +0 -5
  277. data/tasks/reek.rake +0 -6
  278. data/tasks/rubocop.rake +0 -11
  279. data/tasks/test.rake +0 -32
  280. /data/lib/reek/{report/code_climate.rb → code_climate.rb} +0 -0
@@ -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
@@ -38,9 +38,9 @@ module Reek
38
38
  # @param type [Symbol] the type of the nodes we are looking for, e.g. :defs.
39
39
  # @yield block that is executed for every node.
40
40
  #
41
- def local_nodes(type, ignored = [], &blk)
41
+ def local_nodes(type, ignored = [], &)
42
42
  ignored |= [:class, :module]
43
- exp.each_node(type, ignored, &blk)
43
+ exp.each_node(type, ignored, &)
44
44
  end
45
45
 
46
46
  # Iterate over `self` and child contexts.
@@ -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
@@ -31,7 +31,7 @@ module Reek
31
31
  MESSAGE
32
32
 
33
33
  def initialize(origin:)
34
- super format(TEMPLATE, source: origin)
34
+ super(format(TEMPLATE, source: origin))
35
35
  end
36
36
 
37
37
  def long_message
@@ -69,15 +69,15 @@ module Reek
69
69
 
70
70
  # @public
71
71
  def initialize(name = :reek)
72
- @config_file = ENV['REEK_CFG']
72
+ @config_file = ENV.fetch('REEK_CFG', nil)
73
73
  @name = name
74
- @reek_opts = ENV['REEK_OPTS'] || ''
74
+ @reek_opts = ENV.fetch('REEK_OPTS', '')
75
75
  @fail_on_error = true
76
76
  @verbose = false
77
77
 
78
78
  yield self if block_given?
79
79
 
80
- if (reek_src = ENV['REEK_SRC'])
80
+ if (reek_src = ENV.fetch('REEK_SRC', nil))
81
81
  @source_files = FileList[reek_src]
82
82
  end
83
83
  @source_files ||= FileList['lib/**/*.rb']
@@ -87,8 +87,8 @@ module Reek
87
87
  # @public
88
88
  def source_files=(files)
89
89
  unless files.is_a?(String) || files.is_a?(FileList)
90
- raise ArgumentError, 'File list should be a FileList or a String that can contain'\
91
- " a glob pattern, e.g. '{app,lib,spec}/**/*.rb'"
90
+ raise ArgumentError, 'File list should be a FileList or a String that can contain ' \
91
+ "a glob pattern, e.g. '{app,lib,spec}/**/*.rb'"
92
92
  end
93
93
  @source_files = FileList[files]
94
94
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_report'
4
+
5
+ module Reek
6
+ module Report
7
+ #
8
+ # Displays smells as GitHub Workflow commands.
9
+ #
10
+ # @public
11
+ #
12
+ class GithubReport < BaseReport
13
+ def show(out = $stdout)
14
+ out.print(workflow_commands.join)
15
+ end
16
+
17
+ private
18
+
19
+ def workflow_commands
20
+ smells.map do |smell|
21
+ WorkflowCommand.new(smell)
22
+ end
23
+ end
24
+
25
+ # Represents a smell as a GitHub Workflow command.
26
+ class WorkflowCommand
27
+ def initialize(smell)
28
+ @smell = smell
29
+ end
30
+
31
+ def to_s
32
+ format(
33
+ "::warning file=%<file>s,line=%<line>d::%<message>s\n",
34
+ file: file,
35
+ line: line,
36
+ message: message)
37
+ end
38
+
39
+ private
40
+
41
+ def file
42
+ @smell.source
43
+ end
44
+
45
+ def line
46
+ @smell.lines.first
47
+ end
48
+
49
+ def message
50
+ @smell.base_message.gsub('%', '%25').gsub("\r", '%0D').gsub("\n", '%0A')
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -20,7 +20,7 @@ module Reek
20
20
  # @public
21
21
  def add_examiner(examiner)
22
22
  print progress_formatter.progress examiner
23
- super(examiner)
23
+ super
24
24
  end
25
25
 
26
26
  # @public
data/lib/reek/report.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'report/github_report'
3
4
  require_relative 'report/html_report'
4
5
  require_relative 'report/json_report'
5
6
  require_relative 'report/text_report'
@@ -16,11 +17,12 @@ module Reek
16
17
  # Reek reporting functionality.
17
18
  module Report
18
19
  REPORT_CLASSES = {
19
- yaml: YAMLReport,
20
- json: JSONReport,
21
- html: HTMLReport,
22
- xml: XMLReport,
23
- text: TextReport
20
+ yaml: YAMLReport,
21
+ json: JSONReport,
22
+ html: HTMLReport,
23
+ xml: XMLReport,
24
+ text: TextReport,
25
+ github: GithubReport
24
26
  }.freeze
25
27
 
26
28
  LOCATION_FORMATTERS = {
@@ -90,7 +90,7 @@ module Reek
90
90
 
91
91
  class << self
92
92
  def smell_type
93
- @smell_type ||= name.split(/::/).last
93
+ @smell_type ||= name.split('::').last
94
94
  end
95
95
 
96
96
  def contexts
@@ -25,8 +25,8 @@ module Reek
25
25
  # @return [Array<SmellWarning>]
26
26
  #
27
27
  def sniff
28
- class_variables_in_context.map do |variable, occurences|
29
- lines = occurences.map(&:line)
28
+ class_variables_in_context.map do |variable, occurrences|
29
+ lines = occurrences.map(&:line)
30
30
  smell_warning(
31
31
  lines: lines,
32
32
  message: "declares the class variable '#{variable}'",
@@ -9,20 +9,20 @@ module Reek
9
9
  class Candidate
10
10
  #
11
11
  # @param parameter [Symbol] the parameter name
12
- # @param occurences [Array<Reek::AST::Node>] the occurences of the ControlParameter smell
12
+ # @param occurrences [Array<Reek::AST::Node>] the occurrences of the ControlParameter smell
13
13
  # e.g. [s(:lvar, :bravo), s(:lvar, :bravo)]
14
14
  #
15
- def initialize(parameter, occurences)
15
+ def initialize(parameter, occurrences)
16
16
  @parameter = parameter
17
- @occurences = occurences
17
+ @occurrences = occurrences
18
18
  end
19
19
 
20
20
  def smells?
21
- occurences.any?
21
+ occurrences.any?
22
22
  end
23
23
 
24
24
  def lines
25
- occurences.map(&:line)
25
+ occurrences.map(&:line)
26
26
  end
27
27
 
28
28
  def name
@@ -31,7 +31,7 @@ module Reek
31
31
 
32
32
  private
33
33
 
34
- attr_reader :occurences, :parameter
34
+ attr_reader :occurrences, :parameter
35
35
  end
36
36
  end
37
37
  end