reek 5.6.0 → 6.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (250) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/ruby.yml +52 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +3 -1
  6. data/.rubocop_todo.yml +27 -20
  7. data/.simplecov +1 -0
  8. data/CHANGELOG.md +29 -0
  9. data/CONTRIBUTING.md +3 -0
  10. data/Dockerfile +2 -1
  11. data/Gemfile +14 -17
  12. data/README.md +11 -11
  13. data/bin/code_climate_reek +12 -2
  14. data/lib/reek.rb +1 -0
  15. data/lib/reek/ast/ast_node_class_map.rb +1 -1
  16. data/lib/reek/ast/node.rb +1 -1
  17. data/lib/reek/ast/sexp_extensions/arguments.rb +11 -0
  18. data/lib/reek/cli/options.rb +3 -3
  19. data/lib/reek/code_comment.rb +36 -29
  20. data/lib/reek/configuration/app_configuration.rb +4 -3
  21. data/lib/reek/configuration/configuration_converter.rb +2 -2
  22. data/lib/reek/configuration/directory_directives.rb +9 -3
  23. data/lib/reek/configuration/excluded_paths.rb +2 -1
  24. data/lib/reek/context/code_context.rb +1 -1
  25. data/lib/reek/context/module_context.rb +3 -1
  26. data/lib/reek/context/refinement_context.rb +16 -0
  27. data/lib/reek/context_builder.rb +16 -2
  28. data/lib/reek/errors/legacy_comment_separator_error.rb +36 -0
  29. data/lib/reek/report.rb +5 -7
  30. data/lib/reek/report/code_climate/code_climate_configuration.yml +1 -1
  31. data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -3
  32. data/lib/reek/report/code_climate/code_climate_report.rb +2 -1
  33. data/lib/reek/report/simple_warning_formatter.rb +0 -7
  34. data/lib/reek/smell_detectors/base_detector.rb +2 -10
  35. data/lib/reek/smell_detectors/boolean_parameter.rb +3 -1
  36. data/lib/reek/smell_detectors/data_clump.rb +23 -56
  37. data/lib/reek/smell_detectors/nil_check.rb +1 -12
  38. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +1 -1
  39. data/lib/reek/smell_warning.rb +2 -3
  40. data/lib/reek/source/source_locator.rb +14 -13
  41. data/lib/reek/spec/smell_matcher.rb +2 -1
  42. data/lib/reek/version.rb +1 -1
  43. data/reek.gemspec +17 -7
  44. metadata +23 -246
  45. data/.travis.yml +0 -35
  46. data/docs/API.md +0 -174
  47. data/docs/Attribute.md +0 -39
  48. data/docs/Basic-Smell-Options.md +0 -85
  49. data/docs/Boolean-Parameter.md +0 -54
  50. data/docs/Class-Variable.md +0 -40
  51. data/docs/Code-Smells.md +0 -39
  52. data/docs/Command-Line-Options.md +0 -119
  53. data/docs/Control-Couple.md +0 -26
  54. data/docs/Control-Parameter.md +0 -32
  55. data/docs/Data-Clump.md +0 -46
  56. data/docs/Duplicate-Method-Call.md +0 -264
  57. data/docs/Feature-Envy.md +0 -93
  58. data/docs/How-To-Write-New-Detectors.md +0 -132
  59. data/docs/How-reek-works-internally.md +0 -114
  60. data/docs/Instance-Variable-Assumption.md +0 -163
  61. data/docs/Irresponsible-Module.md +0 -47
  62. data/docs/Large-Class.md +0 -16
  63. data/docs/Long-Parameter-List.md +0 -39
  64. data/docs/Long-Yield-List.md +0 -37
  65. data/docs/Manual-Dispatch.md +0 -30
  66. data/docs/Missing-Safe-Method.md +0 -92
  67. data/docs/Module-Initialize.md +0 -62
  68. data/docs/Nested-Iterators.md +0 -59
  69. data/docs/Nil-Check.md +0 -44
  70. data/docs/RSpec-matchers.md +0 -129
  71. data/docs/Rake-Task.md +0 -66
  72. data/docs/Reek-4-to-Reek-5-migration.md +0 -188
  73. data/docs/Reek-Driven-Development.md +0 -46
  74. data/docs/Repeated-Conditional.md +0 -47
  75. data/docs/Simulated-Polymorphism.md +0 -16
  76. data/docs/Smell-Suppression.md +0 -96
  77. data/docs/Style-Guide.md +0 -19
  78. data/docs/Subclassed-From-Core-Class.md +0 -79
  79. data/docs/Too-Many-Constants.md +0 -37
  80. data/docs/Too-Many-Instance-Variables.md +0 -43
  81. data/docs/Too-Many-Methods.md +0 -56
  82. data/docs/Too-Many-Statements.md +0 -54
  83. data/docs/Uncommunicative-Method-Name.md +0 -94
  84. data/docs/Uncommunicative-Module-Name.md +0 -92
  85. data/docs/Uncommunicative-Name.md +0 -18
  86. data/docs/Uncommunicative-Parameter-Name.md +0 -90
  87. data/docs/Uncommunicative-Variable-Name.md +0 -96
  88. data/docs/Unused-Parameters.md +0 -28
  89. data/docs/Unused-Private-Method.md +0 -101
  90. data/docs/Utility-Function.md +0 -56
  91. data/docs/Versioning-Policy.md +0 -7
  92. data/docs/YAML-Reports.md +0 -93
  93. data/docs/defaults.reek.yml +0 -129
  94. data/docs/templates/default/docstring/html/public_api_marker.erb +0 -3
  95. data/docs/templates/default/docstring/setup.rb +0 -37
  96. data/docs/templates/default/fulldoc/html/css/common.css +0 -1
  97. data/docs/yard_plugin.rb +0 -17
  98. data/features/command_line_interface/basic_usage.feature +0 -15
  99. data/features/command_line_interface/options.feature +0 -124
  100. data/features/command_line_interface/show_progress.feature +0 -33
  101. data/features/command_line_interface/smell_selection.feature +0 -15
  102. data/features/command_line_interface/smells_count.feature +0 -38
  103. data/features/command_line_interface/stdin.feature +0 -65
  104. data/features/configuration_files/accept_setting.feature +0 -87
  105. data/features/configuration_files/directory_specific_directives.feature +0 -274
  106. data/features/configuration_files/exclude_directives.feature +0 -35
  107. data/features/configuration_files/exclude_paths_directives.feature +0 -42
  108. data/features/configuration_files/masking_smells.feature +0 -94
  109. data/features/configuration_files/mix_accept_reject_setting.feature +0 -84
  110. data/features/configuration_files/reject_setting.feature +0 -89
  111. data/features/configuration_files/schema_validation.feature +0 -59
  112. data/features/configuration_files/show_configuration_file.feature +0 -44
  113. data/features/configuration_files/unused_private_method.feature +0 -68
  114. data/features/configuration_loading.feature +0 -91
  115. data/features/configuration_via_source_comments/erroneous_source_comments.feature +0 -68
  116. data/features/configuration_via_source_comments/well_formed_source_comments.feature +0 -116
  117. data/features/locales.feature +0 -32
  118. data/features/programmatic_access.feature +0 -41
  119. data/features/rake_task/rake_task.feature +0 -138
  120. data/features/reports/codeclimate.feature +0 -59
  121. data/features/reports/json.feature +0 -59
  122. data/features/reports/reports.feature +0 -219
  123. data/features/reports/yaml.feature +0 -52
  124. data/features/rspec_matcher.feature +0 -41
  125. data/features/samples.feature +0 -305
  126. data/features/step_definitions/.rubocop.yml +0 -5
  127. data/features/step_definitions/reek_steps.rb +0 -98
  128. data/features/step_definitions/sample_file_steps.rb +0 -63
  129. data/features/support/env.rb +0 -34
  130. data/features/todo_list.feature +0 -108
  131. data/samples/checkstyle.xml +0 -7
  132. data/samples/clean_source/clean.rb +0 -6
  133. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +0 -29
  134. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +0 -30
  135. data/samples/configuration/corrupt.reek +0 -1
  136. data/samples/configuration/empty.reek +0 -0
  137. data/samples/configuration/full_configuration.reek +0 -13
  138. data/samples/configuration/full_mask.reek +0 -6
  139. data/samples/configuration/home/home.reek.yml +0 -4
  140. data/samples/configuration/partial_mask.reek +0 -4
  141. data/samples/configuration/regular_configuration/.reek.yml +0 -4
  142. data/samples/configuration/regular_configuration/empty_sub_directory/.gitignore +0 -0
  143. data/samples/configuration/with_excluded_paths.reek +0 -5
  144. data/samples/no_config_file/.keep +0 -0
  145. data/samples/paths.rb +0 -5
  146. data/samples/smelly_source/inline.rb +0 -704
  147. data/samples/smelly_source/optparse.rb +0 -1788
  148. data/samples/smelly_source/redcloth.rb +0 -1130
  149. data/samples/smelly_source/ruby.rb +0 -368
  150. data/samples/smelly_source/smelly.rb +0 -7
  151. data/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +0 -5
  152. data/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +0 -2
  153. data/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +0 -6
  154. data/samples/source_with_exclude_paths/nested/uncommunicative_variable_name.rb +0 -6
  155. data/samples/source_with_hidden_directories/.hidden/hidden.rb +0 -1
  156. data/samples/source_with_hidden_directories/not_hidden.rb +0 -1
  157. data/samples/source_with_non_ruby_files/gibberish +0 -1
  158. data/samples/source_with_non_ruby_files/python_source.py +0 -1
  159. data/samples/source_with_non_ruby_files/ruby.rb +0 -6
  160. data/spec/factories/factories.rb +0 -37
  161. data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +0 -17
  162. data/spec/quality/documentation_spec.rb +0 -40
  163. data/spec/quality/reek_source_spec.rb +0 -11
  164. data/spec/reek/ast/node_spec.rb +0 -211
  165. data/spec/reek/ast/object_refs_spec.rb +0 -83
  166. data/spec/reek/ast/reference_collector_spec.rb +0 -47
  167. data/spec/reek/ast/sexp_extensions_spec.rb +0 -516
  168. data/spec/reek/cli/application_spec.rb +0 -168
  169. data/spec/reek/cli/command/report_command_spec.rb +0 -44
  170. data/spec/reek/cli/command/todo_list_command_spec.rb +0 -86
  171. data/spec/reek/cli/options_spec.rb +0 -51
  172. data/spec/reek/cli/silencer_spec.rb +0 -28
  173. data/spec/reek/code_comment_spec.rb +0 -185
  174. data/spec/reek/configuration/app_configuration_spec.rb +0 -195
  175. data/spec/reek/configuration/configuration_file_finder_spec.rb +0 -230
  176. data/spec/reek/configuration/default_directive_spec.rb +0 -13
  177. data/spec/reek/configuration/directory_directives_spec.rb +0 -116
  178. data/spec/reek/configuration/excluded_paths_spec.rb +0 -16
  179. data/spec/reek/configuration/rake_task_converter_spec.rb +0 -33
  180. data/spec/reek/configuration/schema_validator_spec.rb +0 -165
  181. data/spec/reek/context/code_context_spec.rb +0 -192
  182. data/spec/reek/context/ghost_context_spec.rb +0 -60
  183. data/spec/reek/context/method_context_spec.rb +0 -72
  184. data/spec/reek/context/module_context_spec.rb +0 -55
  185. data/spec/reek/context/root_context_spec.rb +0 -12
  186. data/spec/reek/context/statement_counter_spec.rb +0 -24
  187. data/spec/reek/context_builder_spec.rb +0 -460
  188. data/spec/reek/detector_repository_spec.rb +0 -22
  189. data/spec/reek/documentation_link_spec.rb +0 -20
  190. data/spec/reek/errors/base_error_spec.rb +0 -13
  191. data/spec/reek/examiner_spec.rb +0 -309
  192. data/spec/reek/logging_error_handler_spec.rb +0 -24
  193. data/spec/reek/rake/task_spec.rb +0 -56
  194. data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +0 -24
  195. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +0 -126
  196. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +0 -51
  197. data/spec/reek/report/code_climate/code_climate_report_spec.rb +0 -56
  198. data/spec/reek/report/html_report_spec.rb +0 -19
  199. data/spec/reek/report/json_report_spec.rb +0 -58
  200. data/spec/reek/report/location_formatter_spec.rb +0 -32
  201. data/spec/reek/report/progress_formatter_spec.rb +0 -68
  202. data/spec/reek/report/text_report_spec.rb +0 -89
  203. data/spec/reek/report/xml_report_spec.rb +0 -24
  204. data/spec/reek/report/yaml_report_spec.rb +0 -55
  205. data/spec/reek/report_spec.rb +0 -28
  206. data/spec/reek/smell_configuration_spec.rb +0 -56
  207. data/spec/reek/smell_detectors/attribute_spec.rb +0 -197
  208. data/spec/reek/smell_detectors/base_detector_spec.rb +0 -60
  209. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +0 -93
  210. data/spec/reek/smell_detectors/class_variable_spec.rb +0 -106
  211. data/spec/reek/smell_detectors/control_parameter_spec.rb +0 -300
  212. data/spec/reek/smell_detectors/data_clump_spec.rb +0 -120
  213. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +0 -211
  214. data/spec/reek/smell_detectors/feature_envy_spec.rb +0 -295
  215. data/spec/reek/smell_detectors/instance_variable_assumption_spec.rb +0 -96
  216. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -226
  217. data/spec/reek/smell_detectors/long_parameter_list_spec.rb +0 -61
  218. data/spec/reek/smell_detectors/long_yield_list_spec.rb +0 -49
  219. data/spec/reek/smell_detectors/manual_dispatch_spec.rb +0 -75
  220. data/spec/reek/smell_detectors/missing_safe_method_spec.rb +0 -62
  221. data/spec/reek/smell_detectors/module_initialize_spec.rb +0 -77
  222. data/spec/reek/smell_detectors/nested_iterators_spec.rb +0 -333
  223. data/spec/reek/smell_detectors/nil_check_spec.rb +0 -100
  224. data/spec/reek/smell_detectors/repeated_conditional_spec.rb +0 -100
  225. data/spec/reek/smell_detectors/subclassed_from_core_class_spec.rb +0 -77
  226. data/spec/reek/smell_detectors/too_many_constants_spec.rb +0 -144
  227. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +0 -132
  228. data/spec/reek/smell_detectors/too_many_methods_spec.rb +0 -54
  229. data/spec/reek/smell_detectors/too_many_statements_spec.rb +0 -90
  230. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +0 -78
  231. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +0 -78
  232. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +0 -147
  233. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +0 -201
  234. data/spec/reek/smell_detectors/unused_parameters_spec.rb +0 -114
  235. data/spec/reek/smell_detectors/unused_private_method_spec.rb +0 -205
  236. data/spec/reek/smell_detectors/utility_function_spec.rb +0 -293
  237. data/spec/reek/smell_warning_spec.rb +0 -137
  238. data/spec/reek/source/source_code_spec.rb +0 -66
  239. data/spec/reek/source/source_locator_spec.rb +0 -166
  240. data/spec/reek/spec/should_reek_of_spec.rb +0 -154
  241. data/spec/reek/spec/should_reek_only_of_spec.rb +0 -91
  242. data/spec/reek/spec/should_reek_spec.rb +0 -52
  243. data/spec/reek/spec/smell_matcher_spec.rb +0 -87
  244. data/spec/reek/tree_dresser_spec.rb +0 -46
  245. data/spec/spec_helper.rb +0 -96
  246. data/tasks/configuration.rake +0 -19
  247. data/tasks/console.rake +0 -5
  248. data/tasks/reek.rake +0 -6
  249. data/tasks/rubocop.rake +0 -11
  250. data/tasks/test.rake +0 -32
@@ -87,7 +87,7 @@ module Reek
87
87
 
88
88
  def set_banner
89
89
  program_name = parser.program_name
90
- parser.banner = <<-BANNER.gsub(/^[ ]+/, '')
90
+ parser.banner = <<-BANNER.gsub(/^ +/, '')
91
91
  Usage: #{program_name} [options] [files]
92
92
 
93
93
  Examples:
@@ -131,9 +131,9 @@ module Reek
131
131
  def set_alternative_formatter_options
132
132
  parser.separator "\nReport format:"
133
133
  parser.on(
134
- '-f', '--format FORMAT', [:html, :text, :yaml, :json, :xml, :code_climate],
134
+ '-f', '--format FORMAT', [:html, :text, :yaml, :json, :xml],
135
135
  'Report smells in the given format:',
136
- ' html', ' text (default)', ' yaml', ' json', ' xml', ' code_climate') do |opt|
136
+ ' html', ' text (default)', ' yaml', ' json', ' xml') do |opt|
137
137
  self.report_format = opt
138
138
  end
139
139
  end
@@ -6,6 +6,7 @@ require_relative 'smell_detectors/base_detector'
6
6
  require_relative 'errors/bad_detector_in_comment_error'
7
7
  require_relative 'errors/bad_detector_configuration_key_in_comment_error'
8
8
  require_relative 'errors/garbage_detector_configuration_in_comment_error'
9
+ require_relative 'errors/legacy_comment_separator_error'
9
10
 
10
11
  module Reek
11
12
  #
@@ -14,12 +15,10 @@ module Reek
14
15
  #
15
16
  class CodeComment
16
17
  CONFIGURATION_REGEX = /
17
- :reek: # prefix
18
- (\w+) # smell detector e.g.: UncommunicativeVariableName
19
- (
20
- \s*
21
- (\{.*?\}) # optional details in hash style e.g.: { max_methods: 30 }
22
- )?
18
+ :reek: # prefix
19
+ (\w+) # smell detector e.g.: UncommunicativeVariableName
20
+ (:?\s*) # separator
21
+ (\{.*?\})? # details in hash style e.g.: { max_methods: 30 }
23
22
  /x.freeze
24
23
  SANITIZE_REGEX = /(#|\n|\s)+/.freeze # Matches '#', newlines and > 1 whitespaces.
25
24
  DISABLE_DETECTOR_CONFIGURATION = '{ enabled: false }'
@@ -38,7 +37,8 @@ module Reek
38
37
  @source = source
39
38
  @config = Hash.new { |hash, key| hash[key] = {} }
40
39
 
41
- @original_comment.scan(CONFIGURATION_REGEX) do |detector_name, _option_string, options|
40
+ @original_comment.scan(CONFIGURATION_REGEX) do |detector_name, separator, options|
41
+ escalate_legacy_separator separator
42
42
  CodeCommentValidator.new(detector_name: detector_name,
43
43
  original_comment: original_comment,
44
44
  line: line,
@@ -64,6 +64,14 @@ module Reek
64
64
  strip
65
65
  end
66
66
 
67
+ def escalate_legacy_separator(separator)
68
+ return unless separator.start_with? ':'
69
+
70
+ raise Errors::LegacyCommentSeparatorError.new(original_comment: original_comment,
71
+ source: source,
72
+ line: line)
73
+ end
74
+
67
75
  #
68
76
  # A typical configuration via code comment looks like this:
69
77
  #
@@ -88,25 +96,22 @@ module Reek
88
96
  # @param source [String] path to source file or "string"
89
97
  # @param options [String] the configuration options as String for the detector that were
90
98
  # extracted from the original comment
91
- def initialize(detector_name:, original_comment:, line:, source:, options: {})
99
+ def initialize(detector_name:, original_comment:, line:, source:, options:)
92
100
  @detector_name = detector_name
93
101
  @original_comment = original_comment
94
102
  @line = line
95
103
  @source = source
96
104
  @options = options
97
- @detector_class = nil # We only know this one after our first initial checks
98
- @parsed_options = nil # We only know this one after our first initial checks
99
105
  end
100
106
 
101
107
  #
102
108
  # Method can raise the following errors:
109
+ # * Errors::LegacyCommentSeparatorError
103
110
  # * Errors::BadDetectorInCommentError
104
111
  # * Errors::GarbageDetectorConfigurationInCommentError
105
112
  # * Errors::BadDetectorConfigurationKeyInCommentError
106
113
  # @return [undefined]
107
114
  def validate
108
- escalate_bad_detector
109
- escalate_bad_detector_configuration
110
115
  escalate_unknown_configuration_key
111
116
  end
112
117
 
@@ -116,22 +121,12 @@ module Reek
116
121
  :original_comment,
117
122
  :line,
118
123
  :source,
119
- :options,
120
- :detector_class,
121
- :parsed_options
122
-
123
- def escalate_bad_detector
124
- return if SmellDetectors::BaseDetector.valid_detector?(detector_name)
124
+ :separator,
125
+ :options
125
126
 
126
- raise Errors::BadDetectorInCommentError.new(detector_name: detector_name,
127
- original_comment: original_comment,
128
- source: source,
129
- line: line)
130
- end
131
-
132
- def escalate_bad_detector_configuration
133
- @parsed_options = YAML.safe_load(options || CodeComment::DISABLE_DETECTOR_CONFIGURATION,
134
- permitted_classes: [Regexp])
127
+ def parsed_options
128
+ @parsed_options ||= YAML.safe_load(options || CodeComment::DISABLE_DETECTOR_CONFIGURATION,
129
+ permitted_classes: [Regexp])
135
130
  rescue Psych::SyntaxError
136
131
  raise Errors::GarbageDetectorConfigurationInCommentError.new(detector_name: detector_name,
137
132
  original_comment: original_comment,
@@ -140,8 +135,6 @@ module Reek
140
135
  end
141
136
 
142
137
  def escalate_unknown_configuration_key
143
- @detector_class = SmellDetectors::BaseDetector.to_detector(detector_name)
144
-
145
138
  return if given_keys_legit?
146
139
 
147
140
  raise Errors::BadDetectorConfigurationKeyInCommentError.new(detector_name: detector_name,
@@ -151,6 +144,20 @@ module Reek
151
144
  line: line)
152
145
  end
153
146
 
147
+ def detector_class
148
+ @detector_class ||= SmellDetectors::BaseDetector.to_detector(detector_name)
149
+ rescue NameError
150
+ raise Errors::BadDetectorInCommentError.new(detector_name: detector_name,
151
+ original_comment: original_comment,
152
+ source: source,
153
+ line: line)
154
+ end
155
+
156
+ # @return [Boolean] comment uses legacy three-colon format
157
+ def legacy_format?
158
+ separator.start_with? ':'
159
+ end
160
+
154
161
  # @return [Boolean] all keys in code comment are applicable to the detector in question
155
162
  def given_keys_legit?
156
163
  given_configuration_keys.subset? valid_detector_keys
@@ -72,11 +72,12 @@ module Reek
72
72
 
73
73
  def load_values(values)
74
74
  values.each do |key, value|
75
- if key == EXCLUDE_PATHS_KEY
75
+ case key
76
+ when EXCLUDE_PATHS_KEY
76
77
  excluded_paths.add value
77
- elsif key == DIRECTORIES_KEY
78
+ when DIRECTORIES_KEY
78
79
  directory_directives.add value
79
- elsif key == DETECTORS_KEY
80
+ when DETECTORS_KEY
80
81
  default_directive.add value
81
82
  end
82
83
  end
@@ -74,7 +74,7 @@ module Reek
74
74
  return unless configuration[DETECTORS_KEY]
75
75
 
76
76
  configuration[DETECTORS_KEY].tap do |detectors|
77
- detectors.keys.each do |detector|
77
+ detectors.each_key do |detector|
78
78
  convertible_attributes(detectors[detector]).each do |attribute|
79
79
  detectors[detector][attribute] = detectors[detector][attribute].map do |item|
80
80
  to_regex item
@@ -94,7 +94,7 @@ module Reek
94
94
  return unless configuration[DIRECTORIES_KEY]
95
95
 
96
96
  configuration[DIRECTORIES_KEY].tap do |directories|
97
- directories.keys.each do |directory|
97
+ directories.each_key do |directory|
98
98
  directories[directory].each do |detector, configuration|
99
99
  convertible_attributes(configuration).each do |attribute|
100
100
  directories[directory][detector][attribute] = directories[directory][detector][attribute].map do |item|
@@ -53,10 +53,16 @@ module Reek
53
53
  # @quality :reek:FeatureEnvy
54
54
  def best_match_for(source_base_dir)
55
55
  keys.
56
- select { |pathname| source_base_dir.to_s.match(glob_to_regexp(pathname.to_s)) }.
56
+ select do |pathname|
57
+ match?(source_base_dir, pathname) || match?(source_base_dir, pathname.expand_path)
58
+ end.
57
59
  max_by { |pathname| pathname.to_s.length }
58
60
  end
59
61
 
62
+ def match?(source_base_dir, pathname)
63
+ source_base_dir.to_s.match(glob_to_regexp(pathname.to_s))
64
+ end
65
+
60
66
  # Transform a glob pattern to a regexp.
61
67
  #
62
68
  # It changes:
@@ -78,7 +84,7 @@ module Reek
78
84
  gsub('<<to_eol_wildcards>>', '.*').
79
85
  gsub('<<to_wildcards>>', '.*')
80
86
  else
81
- glob + '.*'
87
+ "#{glob}.*"
82
88
  end
83
89
 
84
90
  Regexp.new("^#{regexp}$", Regexp::IGNORECASE)
@@ -86,7 +92,7 @@ module Reek
86
92
 
87
93
  def error_message_for_invalid_smell_type(klass)
88
94
  "You are trying to configure smell type #{klass} but we can't find one with that name.\n" \
89
- "Please make sure you spelled it right. (See 'docs/defaults.reek' in the Reek\n" \
95
+ "Please make sure you spelled it right. (See 'docs/defaults.reek.yml' in the Reek\n" \
90
96
  'repository for a list of all available smell types.)'
91
97
  end
92
98
  end
@@ -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
@@ -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|
@@ -66,6 +66,8 @@ module Reek
66
66
  CodeComment.new(comment: exp.leading_comment).descriptive?
67
67
  end
68
68
 
69
+ CONSTANT_SEXP_TYPES = [:casgn, :class, :module].freeze
70
+
69
71
  # A namespace module is a module (or class) that is only there for namespacing
70
72
  # purposes, and thus contains only nested constants, modules or classes.
71
73
  #
@@ -78,7 +80,7 @@ module Reek
78
80
  return false if exp.type == :casgn
79
81
 
80
82
  children = exp.direct_children
81
- children.any? && children.all? { |child| [:casgn, :class, :module].include? child.type }
83
+ children.any? && children.all? { |child| CONSTANT_SEXP_TYPES.include? child.type }
82
84
  end
83
85
 
84
86
  def track_visibility(visibility, names)
@@ -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
@@ -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
@@ -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)
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_error'
4
+
5
+ module Reek
6
+ module Errors
7
+ # Gets raised for old-style comment configuration format.
8
+ class LegacyCommentSeparatorError < BaseError
9
+ MESSAGE = <<-MESSAGE
10
+ Error: You are using the legacy configuration format (including three
11
+ colons) to configure Reek in one your source code comments.
12
+
13
+ The source is '%<source>s' and the comment belongs to the expression
14
+ starting in line %<line>d.
15
+
16
+ Here's the original comment:
17
+
18
+ %<comment>s
19
+
20
+ Please see the Reek docs for information on how to configure Reek via
21
+ source code comments: #{DocumentationLink.build('Smell Suppression')}
22
+
23
+ Update the offensive comment and re-run Reek.
24
+
25
+ MESSAGE
26
+
27
+ def initialize(source:, line:, original_comment:)
28
+ message = format(MESSAGE,
29
+ source: source,
30
+ line: line,
31
+ comment: original_comment)
32
+ super message
33
+ end
34
+ end
35
+ end
36
+ end
data/lib/reek/report.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'report/code_climate'
4
3
  require_relative 'report/html_report'
5
4
  require_relative 'report/json_report'
6
5
  require_relative 'report/text_report'
@@ -17,12 +16,11 @@ module Reek
17
16
  # Reek reporting functionality.
18
17
  module Report
19
18
  REPORT_CLASSES = {
20
- yaml: YAMLReport,
21
- json: JSONReport,
22
- html: HTMLReport,
23
- xml: XMLReport,
24
- text: TextReport,
25
- code_climate: CodeClimateReport
19
+ yaml: YAMLReport,
20
+ json: JSONReport,
21
+ html: HTMLReport,
22
+ xml: XMLReport,
23
+ text: TextReport
26
24
  }.freeze
27
25
 
28
26
  LOCATION_FORMATTERS = {
@@ -59,7 +59,7 @@ BooleanParameter:
59
59
 
60
60
  ## Getting rid of the smell
61
61
 
62
- This is highly dependant on your exact architecture, but looking at the example above what you could do is:
62
+ This is highly dependent on your exact architecture, but looking at the example above what you could do is:
63
63
 
64
64
  * Move everything in the `if` branch into a separate method
65
65
  * Move everything in the `else` branch into a separate method
@@ -57,9 +57,7 @@ module Reek
57
57
  end
58
58
 
59
59
  def configuration
60
- @configuration ||= begin
61
- CodeClimateConfiguration.load
62
- end
60
+ @configuration ||= CodeClimateConfiguration.load
63
61
  end
64
62
  end
65
63
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../base_report'
4
+ require_relative 'code_climate_formatter'
4
5
 
5
6
  module Reek
6
7
  module Report
@@ -12,7 +13,7 @@ module Reek
12
13
  class CodeClimateReport < BaseReport
13
14
  def show(out = $stdout)
14
15
  smells.map do |smell|
15
- out.print warning_formatter.format_code_climate_hash(smell)
16
+ out.print CodeClimateFormatter.new(smell).render
16
17
  end
17
18
  end
18
19
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'code_climate/code_climate_formatter'
4
-
5
3
  module Reek
6
4
  module Report
7
5
  #
@@ -17,11 +15,6 @@ module Reek
17
15
  "#{location_formatter.format(warning)}#{warning.base_message}"
18
16
  end
19
17
 
20
- # @quality :reek:UtilityFunction
21
- def format_code_climate_hash(warning)
22
- CodeClimateFormatter.new(warning).render
23
- end
24
-
25
18
  def format_list(warnings)
26
19
  warnings.map { |warning| " #{format(warning)}" }.join("\n")
27
20
  end