reek 4.8.2 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (213) hide show
  1. checksums.yaml +5 -5
  2. data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
  3. data/.rubocop.yml +17 -3
  4. data/.simplecov +1 -0
  5. data/.travis.yml +0 -5
  6. data/.yardopts +1 -1
  7. data/CHANGELOG.md +28 -0
  8. data/Gemfile +1 -1
  9. data/README.md +113 -98
  10. data/Rakefile +16 -3
  11. data/bin/reek +1 -3
  12. data/docs/API.md +2 -9
  13. data/docs/Basic-Smell-Options.md +51 -11
  14. data/docs/Code-Smells.md +1 -1
  15. data/docs/Command-Line-Options.md +14 -4
  16. data/docs/Duplicate-Method-Call.md +49 -1
  17. data/docs/Feature-Envy.md +44 -0
  18. data/docs/How-To-Write-New-Detectors.md +2 -3
  19. data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
  20. data/docs/Rake-Task.md +1 -1
  21. data/docs/Reek-4-to-Reek-5-migration.md +193 -0
  22. data/docs/Reek-Driven-Development.md +1 -1
  23. data/docs/Uncommunicative-Method-Name.md +43 -4
  24. data/docs/Uncommunicative-Module-Name.md +48 -6
  25. data/docs/Uncommunicative-Parameter-Name.md +42 -4
  26. data/docs/Uncommunicative-Variable-Name.md +73 -2
  27. data/docs/Unused-Private-Method.md +1 -1
  28. data/docs/defaults.reek.yml +129 -0
  29. data/docs/yard_plugin.rb +1 -0
  30. data/features/command_line_interface/options.feature +46 -4
  31. data/features/command_line_interface/stdin.feature +27 -5
  32. data/features/configuration_files/accept_setting.feature +39 -22
  33. data/features/configuration_files/directory_specific_directives.feature +58 -53
  34. data/features/configuration_files/exclude_directives.feature +8 -7
  35. data/features/configuration_files/masking_smells.feature +35 -6
  36. data/features/configuration_files/mix_accept_reject_setting.feature +24 -21
  37. data/features/configuration_files/reject_setting.feature +45 -34
  38. data/features/configuration_files/schema_validation.feature +59 -0
  39. data/features/configuration_files/unused_private_method.feature +14 -12
  40. data/features/configuration_loading.feature +50 -7
  41. data/features/rake_task/rake_task.feature +5 -5
  42. data/features/reports/json.feature +4 -1
  43. data/features/reports/reports.feature +12 -12
  44. data/features/reports/yaml.feature +3 -0
  45. data/features/rspec_matcher.feature +9 -1
  46. data/features/step_definitions/reek_steps.rb +4 -0
  47. data/features/step_definitions/sample_file_steps.rb +9 -4
  48. data/features/support/env.rb +2 -2
  49. data/features/todo_list.feature +16 -13
  50. data/lib/reek/ast/node.rb +3 -6
  51. data/lib/reek/ast/object_refs.rb +1 -1
  52. data/lib/reek/ast/sexp_extensions/if.rb +1 -1
  53. data/lib/reek/ast/sexp_extensions/methods.rb +1 -1
  54. data/lib/reek/cli/application.rb +4 -3
  55. data/lib/reek/cli/command/report_command.rb +1 -2
  56. data/lib/reek/cli/command/todo_list_command.rb +4 -2
  57. data/lib/reek/cli/options.rb +27 -13
  58. data/lib/reek/cli/silencer.rb +14 -3
  59. data/lib/reek/code_comment.rb +14 -16
  60. data/lib/reek/configuration/app_configuration.rb +32 -28
  61. data/lib/reek/configuration/configuration_converter.rb +110 -0
  62. data/lib/reek/configuration/configuration_file_finder.rb +15 -40
  63. data/lib/reek/configuration/configuration_validator.rb +12 -23
  64. data/lib/reek/configuration/default_directive.rb +17 -3
  65. data/lib/reek/configuration/directory_directives.rb +17 -11
  66. data/lib/reek/configuration/excluded_paths.rb +1 -1
  67. data/lib/reek/configuration/rake_task_converter.rb +29 -0
  68. data/lib/reek/configuration/schema.yml +210 -0
  69. data/lib/reek/configuration/schema_validator.rb +38 -0
  70. data/lib/reek/context/attribute_context.rb +1 -1
  71. data/lib/reek/context/code_context.rb +4 -4
  72. data/lib/reek/context/method_context.rb +2 -2
  73. data/lib/reek/context/module_context.rb +1 -1
  74. data/lib/reek/context_builder.rb +9 -9
  75. data/lib/reek/detector_repository.rb +6 -0
  76. data/lib/reek/documentation_link.rb +2 -2
  77. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +1 -1
  78. data/lib/reek/errors/bad_detector_in_comment_error.rb +1 -1
  79. data/lib/reek/errors/config_file_error.rb +11 -0
  80. data/lib/reek/errors/encoding_error.rb +2 -2
  81. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +1 -1
  82. data/lib/reek/errors/incomprehensible_source_error.rb +2 -2
  83. data/lib/reek/errors/syntax_error.rb +41 -0
  84. data/lib/reek/examiner.rb +9 -19
  85. data/lib/reek/rake/task.rb +3 -3
  86. data/lib/reek/report.rb +15 -10
  87. data/lib/reek/report/base_report.rb +8 -12
  88. data/lib/reek/report/code_climate/code_climate_configuration.yml +5 -9
  89. data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
  90. data/lib/reek/report/heading_formatter.rb +54 -0
  91. data/lib/reek/report/json_report.rb +1 -1
  92. data/lib/reek/report/location_formatter.rb +40 -0
  93. data/lib/reek/report/progress_formatter.rb +79 -0
  94. data/lib/reek/report/simple_warning_formatter.rb +34 -0
  95. data/lib/reek/report/text_report.rb +1 -2
  96. data/lib/reek/report/xml_report.rb +3 -3
  97. data/lib/reek/report/yaml_report.rb +1 -1
  98. data/lib/reek/smell_configuration.rb +2 -2
  99. data/lib/reek/smell_detectors.rb +1 -2
  100. data/lib/reek/smell_detectors/attribute.rb +0 -1
  101. data/lib/reek/smell_detectors/base_detector.rb +8 -11
  102. data/lib/reek/smell_detectors/boolean_parameter.rb +0 -1
  103. data/lib/reek/smell_detectors/class_variable.rb +0 -1
  104. data/lib/reek/smell_detectors/control_parameter.rb +17 -32
  105. data/lib/reek/smell_detectors/data_clump.rb +3 -4
  106. data/lib/reek/smell_detectors/duplicate_method_call.rb +5 -6
  107. data/lib/reek/smell_detectors/feature_envy.rb +0 -1
  108. data/lib/reek/smell_detectors/instance_variable_assumption.rb +0 -1
  109. data/lib/reek/smell_detectors/irresponsible_module.rb +0 -1
  110. data/lib/reek/smell_detectors/long_parameter_list.rb +1 -2
  111. data/lib/reek/smell_detectors/long_yield_list.rb +2 -3
  112. data/lib/reek/smell_detectors/manual_dispatch.rb +2 -2
  113. data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +6 -7
  114. data/lib/reek/smell_detectors/module_initialize.rb +0 -1
  115. data/lib/reek/smell_detectors/nested_iterators.rb +4 -5
  116. data/lib/reek/smell_detectors/nil_check.rb +0 -1
  117. data/lib/reek/smell_detectors/repeated_conditional.rb +3 -4
  118. data/lib/reek/smell_detectors/subclassed_from_core_class.rb +0 -1
  119. data/lib/reek/smell_detectors/too_many_constants.rb +1 -2
  120. data/lib/reek/smell_detectors/too_many_instance_variables.rb +1 -2
  121. data/lib/reek/smell_detectors/too_many_methods.rb +1 -2
  122. data/lib/reek/smell_detectors/too_many_statements.rb +1 -2
  123. data/lib/reek/smell_detectors/uncommunicative_method_name.rb +2 -3
  124. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +2 -3
  125. data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +2 -3
  126. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +4 -5
  127. data/lib/reek/smell_detectors/unused_parameters.rb +0 -1
  128. data/lib/reek/smell_detectors/unused_private_method.rb +0 -1
  129. data/lib/reek/smell_detectors/utility_function.rb +1 -2
  130. data/lib/reek/smell_warning.rb +10 -8
  131. data/lib/reek/source/source_code.rb +40 -55
  132. data/lib/reek/source/source_locator.rb +7 -7
  133. data/lib/reek/spec.rb +6 -6
  134. data/lib/reek/spec/should_reek.rb +2 -2
  135. data/lib/reek/spec/should_reek_of.rb +9 -16
  136. data/lib/reek/spec/should_reek_only_of.rb +4 -4
  137. data/lib/reek/tree_dresser.rb +5 -5
  138. data/lib/reek/version.rb +1 -1
  139. data/reek.gemspec +3 -3
  140. data/samples/checkstyle.xml +1 -1
  141. data/samples/{clean.rb → clean_source/clean.rb} +0 -0
  142. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
  143. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
  144. data/samples/configuration/full_configuration.reek +8 -4
  145. data/samples/configuration/full_mask.reek +5 -4
  146. data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
  147. data/samples/configuration/partial_mask.reek +3 -2
  148. data/samples/configuration/regular_configuration/.reek.yml +4 -0
  149. data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
  150. data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
  151. data/samples/paths.rb +5 -4
  152. data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
  153. data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
  154. data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
  155. data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
  156. data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
  157. data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
  158. data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
  159. data/spec/reek/ast/node_spec.rb +5 -5
  160. data/spec/reek/cli/application_spec.rb +18 -4
  161. data/spec/reek/cli/command/todo_list_command_spec.rb +4 -2
  162. data/spec/reek/cli/silencer_spec.rb +28 -0
  163. data/spec/reek/code_comment_spec.rb +0 -7
  164. data/spec/reek/configuration/app_configuration_spec.rb +44 -31
  165. data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -49
  166. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  167. data/spec/reek/configuration/directory_directives_spec.rb +3 -4
  168. data/spec/reek/configuration/excluded_paths_spec.rb +5 -5
  169. data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
  170. data/spec/reek/configuration/schema_validator_spec.rb +165 -0
  171. data/spec/reek/context/code_context_spec.rb +1 -1
  172. data/spec/reek/examiner_spec.rb +28 -1
  173. data/spec/reek/report/json_report_spec.rb +13 -46
  174. data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
  175. data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
  176. data/spec/reek/report/text_report_spec.rb +4 -4
  177. data/spec/reek/report/xml_report_spec.rb +1 -1
  178. data/spec/reek/report/yaml_report_spec.rb +9 -38
  179. data/spec/reek/report_spec.rb +3 -3
  180. data/spec/reek/smell_detectors/feature_envy_spec.rb +2 -2
  181. data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +9 -9
  182. data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
  183. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
  184. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
  185. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
  186. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +6 -4
  187. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +6 -6
  188. data/spec/reek/smell_detectors/unused_private_method_spec.rb +1 -1
  189. data/spec/reek/smell_warning_spec.rb +4 -0
  190. data/spec/reek/source/source_code_spec.rb +16 -22
  191. data/spec/reek/source/source_locator_spec.rb +11 -11
  192. data/spec/reek/spec/should_reek_of_spec.rb +0 -4
  193. data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
  194. data/spec/reek/spec/should_reek_spec.rb +1 -1
  195. data/spec/reek/tree_dresser_spec.rb +2 -6
  196. data/spec/spec_helper.rb +3 -5
  197. data/tasks/configuration.rake +8 -5
  198. metadata +56 -35
  199. data/defaults.reek +0 -131
  200. data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
  201. data/lib/reek/report/formatter.rb +0 -33
  202. data/lib/reek/report/formatter/heading_formatter.rb +0 -52
  203. data/lib/reek/report/formatter/location_formatter.rb +0 -42
  204. data/lib/reek/report/formatter/progress_formatter.rb +0 -81
  205. data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
  206. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -23
  207. data/lib/reek/smell_detectors/syntax.rb +0 -37
  208. data/samples/configuration/non_public_modifiers_mask.reek +0 -3
  209. data/samples/smelly_with_inline_mask.rb +0 -8
  210. data/samples/smelly_with_modifiers.rb +0 -12
  211. data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
  212. data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
  213. data/spec/reek/smell_detectors/syntax_spec.rb +0 -17
@@ -0,0 +1,30 @@
1
+ ---
2
+ directories:
3
+ "app/controllers":
4
+ UnusedPrivateMethod:
5
+ exclude:
6
+ - "/exclude regexp/"
7
+ UncommunicativeMethodName:
8
+ reject:
9
+ - "reject name"
10
+ accept:
11
+ - "accept name"
12
+ UncommunicativeModuleName:
13
+ reject:
14
+ - "reject name 1"
15
+ - "reject name 2"
16
+ accept:
17
+ - "accept name 1"
18
+ - "accept name 2"
19
+ UncommunicativeParameterName:
20
+ reject:
21
+ - "reject name"
22
+ - "/reject regexp/"
23
+ accept:
24
+ - "accept name"
25
+ - "/accept regexp/"
26
+ UncommunicativeVariableName:
27
+ reject:
28
+ - "/^reject regexp$/"
29
+ accept:
30
+ - "/accept(.*)regexp/"
@@ -1,9 +1,13 @@
1
1
  ---
2
- IrresponsibleModule:
3
- enabled: false
4
- "samples/three_clean_files/":
5
- UtilityFunction:
2
+ detectors:
3
+ IrresponsibleModule:
6
4
  enabled: false
5
+
6
+ directories:
7
+ "samples/three_clean_files/":
8
+ UtilityFunction:
9
+ enabled: false
10
+
7
11
  exclude_paths:
8
12
  - "samples/two_smelly_files/"
9
13
  - "samples/source_with_non_ruby_files/"
@@ -1,5 +1,6 @@
1
1
  ---
2
- UncommunicativeMethodName:
3
- enabled: false
4
- UncommunicativeVariableName:
5
- enabled: false
2
+ detectors:
3
+ UncommunicativeMethodName:
4
+ enabled: false
5
+ UncommunicativeVariableName:
6
+ enabled: false
@@ -1,3 +1,4 @@
1
1
  ---
2
- UncommunicativeMethodName:
3
- enabled: false
2
+ detectors:
3
+ UncommunicativeMethodName:
4
+ enabled: false
@@ -0,0 +1,4 @@
1
+ ---
2
+ UncommunicativeVariableName:
3
+ accept:
4
+ - md5
data/samples/paths.rb CHANGED
@@ -1,4 +1,5 @@
1
- SAMPLES_PATH = Pathname.new(__dir__).relative_path_from(Pathname.pwd)
2
- CONFIG_PATH = SAMPLES_PATH.join('configuration')
3
- CLEAN_FILE = SAMPLES_PATH.join('clean.rb')
4
- SMELLY_FILE = SAMPLES_PATH.join('smelly.rb')
1
+ SAMPLES_DIR = Pathname.new(__dir__).relative_path_from(Pathname.pwd)
2
+ CONFIGURATION_DIR = SAMPLES_DIR.join('configuration')
3
+ CLEAN_FILE = SAMPLES_DIR.join('clean_source').join('clean.rb')
4
+ SMELLY_FILE = SAMPLES_DIR.join('smelly_source').join('smelly.rb')
5
+
File without changes
File without changes
File without changes
File without changes
@@ -164,7 +164,7 @@ RSpec.describe Reek::AST::Node do
164
164
 
165
165
  describe '#line' do
166
166
  context 'with source from a file' do
167
- let(:file) { SAMPLES_PATH.join('smelly.rb') }
167
+ let(:file) { SMELLY_FILE }
168
168
  let(:ast) { Reek::Source::SourceCode.from(file).syntax_tree }
169
169
 
170
170
  it 'returns the right line number' do
@@ -173,7 +173,7 @@ RSpec.describe Reek::AST::Node do
173
173
  end
174
174
 
175
175
  context 'with source from a string' do
176
- let(:source) { File.read(SAMPLES_PATH.join('smelly.rb')) }
176
+ let(:source) { File.read(SMELLY_FILE) }
177
177
  let(:ast) { Reek::Source::SourceCode.from(source).syntax_tree }
178
178
 
179
179
  it 'returns the right line number' do
@@ -184,16 +184,16 @@ RSpec.describe Reek::AST::Node do
184
184
 
185
185
  describe '#source' do
186
186
  context 'with source from a file' do
187
- let(:file) { SAMPLES_PATH.join('smelly.rb') }
187
+ let(:file) { SMELLY_FILE }
188
188
  let(:ast) { Reek::Source::SourceCode.from(file).syntax_tree }
189
189
 
190
190
  it 'returns the file name' do
191
- expect(ast.source).to eq(SAMPLES_PATH.join('smelly.rb').to_s)
191
+ expect(ast.source).to eq(SMELLY_FILE.to_s)
192
192
  end
193
193
  end
194
194
 
195
195
  context 'with source from a string' do
196
- let(:source) { File.read(SAMPLES_PATH.join('smelly.rb')) }
196
+ let(:source) { File.read SMELLY_FILE }
197
197
  let(:ast) { Reek::Source::SourceCode.from(source).syntax_tree }
198
198
 
199
199
  it 'returns "string"' do
@@ -17,9 +17,9 @@ RSpec.describe Reek::CLI::Application do
17
17
 
18
18
  describe '#execute' do
19
19
  let(:path_excluded_in_configuration) do
20
- SAMPLES_PATH.join('source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb')
20
+ SAMPLES_DIR.join('source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb')
21
21
  end
22
- let(:configuration) { test_configuration_for(CONFIG_PATH.join('with_excluded_paths.reek')) }
22
+ let(:configuration) { test_configuration_for(CONFIGURATION_DIR.join('with_excluded_paths.reek')) }
23
23
  let(:command) { instance_double 'Reek::CLI::Command::ReportCommand' }
24
24
  let(:app) { described_class.new [] }
25
25
 
@@ -37,13 +37,27 @@ RSpec.describe Reek::CLI::Application do
37
37
  allow_any_instance_of(IO).to receive(:tty?).and_return(false)
38
38
  end
39
39
 
40
- it 'uses source form pipe' do
40
+ it 'uses source from pipe' do
41
+ expected_sources = a_collection_containing_exactly(have_attributes(origin: 'STDIN'))
41
42
  app.execute
42
43
  expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
43
- with(sources: [$stdin],
44
+ with(sources: expected_sources,
44
45
  configuration: Reek::Configuration::AppConfiguration,
45
46
  options: Reek::CLI::Options)
46
47
  end
48
+
49
+ context 'when a stdin filename is provided' do
50
+ let(:app) { described_class.new ['--stdin-filename', 'foo.rb'] }
51
+
52
+ it 'assumes that filename' do
53
+ expected_sources = a_collection_containing_exactly(have_attributes(origin: 'foo.rb'))
54
+ app.execute
55
+ expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
56
+ with(sources: expected_sources,
57
+ configuration: Reek::Configuration::AppConfiguration,
58
+ options: Reek::CLI::Options)
59
+ end
60
+ end
47
61
  end
48
62
 
49
63
  context 'when no source files given and no input was piped' do
@@ -1,6 +1,7 @@
1
1
  require_relative '../../../spec_helper'
2
2
  require_lib 'reek/cli/command/todo_list_command'
3
3
  require_lib 'reek/cli/options'
4
+ require_lib 'reek/configuration/app_configuration'
4
5
 
5
6
  RSpec.describe Reek::CLI::Command::TodoListCommand do
6
7
  let(:nil_check) { build :smell_detector, smell_type: :NilCheck }
@@ -37,8 +38,9 @@ RSpec.describe Reek::CLI::Command::TodoListCommand do
37
38
  it 'writes a todo file with exclusions for each smell' do
38
39
  Reek::CLI::Silencer.silently { command.execute }
39
40
  expected_yaml = {
40
- 'UncommunicativeMethodName' => { 'exclude' => ['Smelly#x'] },
41
- 'UncommunicativeVariableName' => { 'exclude' => ['Smelly#x'] }
41
+ Reek::Configuration::AppConfiguration::DETECTORS_KEY =>
42
+ { 'UncommunicativeMethodName' => { 'exclude' => ['Smelly#x'] },
43
+ 'UncommunicativeVariableName' => { 'exclude' => ['Smelly#x'] } }
42
44
  }.to_yaml
43
45
  expect(File).to have_received(:write).with(described_class::FILE_NAME, expected_yaml)
44
46
  end
@@ -0,0 +1,28 @@
1
+ require_relative '../../spec_helper'
2
+ require_lib 'reek/cli/silencer'
3
+
4
+ RSpec.describe Reek::CLI::Silencer do
5
+ describe '.silently' do
6
+ it 'blocks output from the block on $stdout' do
7
+ expect { described_class.silently { puts 'Hi!' } }.not_to output.to_stdout
8
+ end
9
+
10
+ it 'blocks output from the block on $stderr' do
11
+ expect { described_class.silently { warn 'Hi!' } }.not_to output.to_stderr
12
+ end
13
+
14
+ it 'restores output on $stdout after the block' do
15
+ expect do
16
+ described_class.silently { puts 'Hi!' }
17
+ puts 'there!'
18
+ end.to output("there!\n").to_stdout
19
+ end
20
+
21
+ it 'restores output on $stderr after the block' do
22
+ expect do
23
+ described_class.silently { warn 'Hi!' }
24
+ warn 'there!'
25
+ end.to output("there!\n").to_stderr
26
+ end
27
+ end
28
+ end
@@ -161,13 +161,6 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
161
161
  build(:code_comment, comment: comment)
162
162
  end.not_to raise_error
163
163
  end
164
-
165
- it 'does not raise on regexps' do
166
- expect do
167
- comment = '# :reek:UncommunicativeMethodName { exclude: !ruby/regexp /alfa/ }'
168
- build(:code_comment, comment: comment)
169
- end.not_to raise_error
170
- end
171
164
  end
172
165
 
173
166
  context 'when unknown custom options are specified' do
@@ -8,8 +8,8 @@ require_lib 'reek/configuration/excluded_paths'
8
8
  RSpec.describe Reek::Configuration::AppConfiguration do
9
9
  describe 'factory methods' do
10
10
  let(:expected_excluded_paths) do
11
- [SAMPLES_PATH.join('two_smelly_files'),
12
- SAMPLES_PATH.join('source_with_non_ruby_files')]
11
+ [SAMPLES_DIR.join('two_smelly_files'),
12
+ SAMPLES_DIR.join('source_with_non_ruby_files')]
13
13
  end
14
14
 
15
15
  let(:expected_default_directive) do
@@ -17,32 +17,35 @@ RSpec.describe Reek::Configuration::AppConfiguration do
17
17
  end
18
18
 
19
19
  let(:expected_directory_directives) do
20
- { SAMPLES_PATH.join('three_clean_files') =>
20
+ { SAMPLES_DIR.join('three_clean_files') =>
21
21
  { Reek::SmellDetectors::UtilityFunction => { 'enabled' => false } } }
22
22
  end
23
23
 
24
24
  let(:default_directive_value) do
25
- { 'IrresponsibleModule' => { 'enabled' => false } }
25
+ { described_class::DETECTORS_KEY =>
26
+ { 'IrresponsibleModule' => { 'enabled' => false } } }
26
27
  end
27
28
 
28
29
  let(:directory_directives_value) do
29
- { 'samples/three_clean_files' =>
30
- { 'UtilityFunction' => { 'enabled' => false } } }
30
+ { described_class::DIRECTORIES_KEY =>
31
+ { 'samples/three_clean_files' =>
32
+ { 'UtilityFunction' => { 'enabled' => false } } } }
31
33
  end
32
34
 
33
35
  let(:exclude_paths_value) do
34
- ['samples/two_smelly_files',
35
- 'samples/source_with_non_ruby_files']
36
+ { described_class::EXCLUDE_PATHS_KEY =>
37
+ ['samples/two_smelly_files',
38
+ 'samples/source_with_non_ruby_files'] }
36
39
  end
37
40
 
38
41
  let(:combined_value) do
39
42
  directory_directives_value.
40
43
  merge(default_directive_value).
41
- merge('exclude_paths' => exclude_paths_value)
44
+ merge(exclude_paths_value)
42
45
  end
43
46
 
44
47
  describe '#from_path' do
45
- let(:full_configuration_path) { CONFIG_PATH.join('full_configuration.reek') }
48
+ let(:full_configuration_path) { CONFIGURATION_DIR.join('full_configuration.reek') }
46
49
 
47
50
  it 'properly loads configuration and processes it' do
48
51
  config = described_class.from_path full_configuration_path
@@ -77,34 +80,38 @@ RSpec.describe Reek::Configuration::AppConfiguration do
77
80
  describe '#directive_for' do
78
81
  context 'with multiple directory directives and no default directive present' do
79
82
  let(:source_via) { 'samples/three_clean_files/dummy.rb' }
80
- let(:baz_config) { { Reek::SmellDetectors::IrresponsibleModule => { enabled: false } } }
81
- let(:bang_config) { { Reek::SmellDetectors::Attribute => { enabled: true } } }
83
+ let(:baz_config) { { IrresponsibleModule: { enabled: false } } }
84
+ let(:bang_config) { { Attribute: { enabled: true } } }
85
+ let(:expected_result) { { Reek::SmellDetectors::Attribute => { enabled: true } } }
82
86
 
83
87
  let(:directory_directives) do
84
- {
85
- 'samples/two_smelly_files' => baz_config,
86
- 'samples/three_clean_files' => bang_config
87
- }
88
+ { described_class::DIRECTORIES_KEY =>
89
+ {
90
+ 'samples/two_smelly_files' => baz_config,
91
+ 'samples/three_clean_files' => bang_config
92
+ } }
88
93
  end
89
94
 
90
95
  it 'returns the corresponding directive' do
91
96
  configuration = described_class.from_hash directory_directives
92
- expect(configuration.directive_for(source_via)).to eq(bang_config)
97
+ expect(configuration.directive_for(source_via)).to eq expected_result
93
98
  end
94
99
  end
95
100
 
96
101
  context 'with directory directive and default directive present' do
97
102
  let(:directory) { 'spec/samples/two_smelly_files/' }
98
- let(:directory_config) { { Reek::SmellDetectors::TooManyStatements => { max_statements: 8 } } }
99
- let(:directory_directives) { { directory => directory_config } }
100
- let(:default_directive) do
103
+ let(:source_via) { "#{directory}/dummy.rb" }
104
+
105
+ let(:configuration_as_hash) do
101
106
  {
102
- Reek::SmellDetectors::IrresponsibleModule => { enabled: false },
103
- Reek::SmellDetectors::TooManyStatements => { max_statements: 15 }
107
+ described_class::DIRECTORIES_KEY =>
108
+ { directory => { TooManyStatements: { max_statements: 8 } } },
109
+ described_class::DETECTORS_KEY => {
110
+ IrresponsibleModule: { enabled: false },
111
+ TooManyStatements: { max_statements: 15 }
112
+ }
104
113
  }
105
114
  end
106
- let(:source_via) { "#{directory}/dummy.rb" }
107
- let(:configuration_as_hash) { directory_directives.merge(default_directive) }
108
115
 
109
116
  it 'returns the directory directive with the default directive reverse-merged' do
110
117
  configuration = described_class.from_hash configuration_as_hash
@@ -116,18 +123,24 @@ RSpec.describe Reek::Configuration::AppConfiguration do
116
123
  end
117
124
  end
118
125
 
119
- context 'with no directory directive but a default directive present' do
126
+ context 'with a path not covered by a directory directive but a default directive present' do
120
127
  let(:source_via) { 'spec/samples/three_clean_files/dummy.rb' }
121
- let(:default_directive) { { Reek::SmellDetectors::IrresponsibleModule => { enabled: false } } }
122
- let(:attribute_config) { { Reek::SmellDetectors::Attribute => { enabled: false } } }
123
- let(:directory_directives) do
124
- { 'spec/samples/two_smelly_files' => attribute_config }
128
+
129
+ let(:configuration_as_hash) do
130
+ {
131
+ described_class::DETECTORS_KEY => {
132
+ IrresponsibleModule: { enabled: false }
133
+ },
134
+ described_class::DIRECTORIES_KEY =>
135
+ { 'spec/samples/two_smelly_files' => { Attribute: { enabled: false } } }
136
+ }
125
137
  end
126
- let(:configuration_as_hash) { directory_directives.merge(default_directive) }
138
+
139
+ let(:expected_result) { { Reek::SmellDetectors::IrresponsibleModule => { enabled: false } } }
127
140
 
128
141
  it 'returns the default directive' do
129
142
  configuration = described_class.from_hash configuration_as_hash
130
- expect(configuration.directive_for(source_via)).to eq(default_directive)
143
+ expect(configuration.directive_for(source_via)).to eq expected_result
131
144
  end
132
145
  end
133
146
  end
@@ -2,9 +2,13 @@ require 'fileutils'
2
2
  require 'pathname'
3
3
  require 'tmpdir'
4
4
  require_relative '../../spec_helper'
5
+ require_lib 'reek/configuration/app_configuration'
5
6
 
6
7
  RSpec.describe Reek::Configuration::ConfigurationFileFinder do
7
8
  describe '.find' do
9
+ let(:regular_configuration_dir) { CONFIGURATION_DIR.join('regular_configuration') }
10
+ let(:regular_configuration_file) { regular_configuration_dir.join('.reek.yml') }
11
+
8
12
  it 'returns any explicitely passed path' do
9
13
  path = Pathname.new 'foo/bar'
10
14
  found = described_class.find(path: path)
@@ -13,42 +17,44 @@ RSpec.describe Reek::Configuration::ConfigurationFileFinder do
13
17
 
14
18
  it 'prefers an explicitely passed path over a file in current dir' do
15
19
  path = Pathname.new 'foo/bar'
16
- found = described_class.find(path: path, current: SAMPLES_PATH)
20
+ found = described_class.find(path: path, current: regular_configuration_dir)
17
21
  expect(found).to eq(path)
18
22
  end
19
23
 
20
24
  it 'returns the file in current dir if path is not set' do
21
- found = described_class.find(current: SAMPLES_PATH)
22
- expect(found).to eq(SAMPLES_PATH.join('exceptions.reek'))
25
+ found = described_class.find(current: regular_configuration_dir)
26
+ expect(found).to eq(regular_configuration_file)
23
27
  end
24
28
 
25
29
  it 'returns the file in a parent dir if none in current dir' do
26
- Dir.mktmpdir(nil, SAMPLES_PATH) do |tempdir|
27
- found = described_class.find(current: Pathname.new(tempdir))
28
- expect(found).to eq(SAMPLES_PATH.join('exceptions.reek'))
29
- end
30
+ empty_sub_directory = CONFIGURATION_DIR.join('regular_configuration').join('empty_sub_directory')
31
+ found = described_class.find(current: empty_sub_directory)
32
+ expect(found).to eq(regular_configuration_file)
30
33
  end
31
34
 
32
- it 'returns the file even if it’s just ‘.reek’' do
33
- single_configuration_file_dir = CONFIG_PATH.join('single_configuration_file')
34
- found = described_class.find(current: single_configuration_file_dir)
35
- expect(found).to eq(single_configuration_file_dir.join('.reek'))
35
+ it 'skips files ending in .reek.yml in current dir' do
36
+ Dir.mktmpdir(nil, regular_configuration_dir) do |tempdir|
37
+ current = Pathname.new(tempdir)
38
+ bad_config = current.join('ignoreme.reek.yml')
39
+ FileUtils.touch bad_config
40
+ found = described_class.find(current: Pathname.new(tempdir))
41
+ expect(found).to eq(regular_configuration_file)
42
+ end
36
43
  end
37
44
 
38
45
  it 'returns the file in home if traversing from the current dir fails' do
39
46
  skip_if_a_config_in_tempdir
40
47
 
41
- Dir.mktmpdir(nil, SAMPLES_PATH) do |tempdir|
42
- found = described_class.find(current: Pathname.new(tempdir))
43
- expect(found).to eq(SAMPLES_PATH.join('exceptions.reek'))
48
+ Dir.mktmpdir do |tempdir|
49
+ found = described_class.find(current: Pathname.new(tempdir), home: regular_configuration_dir)
50
+ expect(found).to eq(regular_configuration_file)
44
51
  end
45
52
  end
46
53
 
47
54
  it 'prefers the file in :current over one in :home' do
48
- found = described_class.find(current: SAMPLES_PATH, home: CONFIG_PATH)
49
- file_in_current = SAMPLES_PATH.join('exceptions.reek')
50
-
51
- expect(found).to eq(file_in_current)
55
+ home_dir = CONFIGURATION_DIR.join('home')
56
+ found = described_class.find(current: regular_configuration_dir, home: home_dir)
57
+ expect(found).to eq(regular_configuration_file)
52
58
  end
53
59
 
54
60
  it 'returns nil when there are no files to find' do
@@ -68,12 +74,10 @@ RSpec.describe Reek::Configuration::ConfigurationFileFinder do
68
74
  skip_if_a_config_in_tempdir
69
75
 
70
76
  Dir.mktmpdir do |tempdir|
71
- dir = Pathname.new(tempdir)
72
- subdir = dir.join('subdir')
73
-
74
- FileUtils.mkdir(subdir)
77
+ current = Pathname.new(tempdir)
78
+ home = SAMPLES_DIR.join('no_config_file')
75
79
 
76
- found = described_class.find(current: subdir, home: dir)
80
+ found = described_class.find(current: current, home: home)
77
81
 
78
82
  expect(found).to be_nil
79
83
  end
@@ -81,7 +85,7 @@ RSpec.describe Reek::Configuration::ConfigurationFileFinder do
81
85
 
82
86
  it 'works with paths that need escaping' do
83
87
  Dir.mktmpdir("ma\ngic d*r") do |tempdir|
84
- config = Pathname.new("#{tempdir}/ma\ngic f*le.reek")
88
+ config = Pathname.new("#{tempdir}/.reek.yml")
85
89
  subdir = Pathname.new("#{tempdir}/ma\ngic subd*r")
86
90
  FileUtils.touch config
87
91
  FileUtils.mkdir subdir
@@ -89,42 +93,122 @@ RSpec.describe Reek::Configuration::ConfigurationFileFinder do
89
93
  expect(found).to eq(config)
90
94
  end
91
95
  end
92
-
93
- context 'with more than one configuration file' do
94
- let(:path) { CONFIG_PATH.join('more_than_one_configuration_file') }
95
-
96
- it 'prints a message on STDERR' do
97
- expected_message = "Error: Found multiple configuration files 'regular.reek', 'todo.reek'"
98
- expect do
99
- begin
100
- described_class.find(current: path)
101
- rescue SystemExit
102
- end
103
- end.to output(/#{expected_message}/).to_stderr
104
- end
105
-
106
- it 'exits' do
107
- Reek::CLI::Silencer.silently do
108
- expect do
109
- described_class.find(current: path)
110
- end.to raise_error(SystemExit)
111
- end
112
- end
113
- end
114
96
  end
115
97
 
116
98
  describe '.load_from_file' do
117
99
  let(:sample_configuration_loaded) do
118
100
  {
119
- 'UncommunicativeVariableName' => { 'enabled' => false },
120
- 'UncommunicativeMethodName' => { 'enabled' => false }
101
+ Reek::Configuration::AppConfiguration::DETECTORS_KEY => {
102
+ 'UncommunicativeVariableName' => { 'enabled' => false },
103
+ 'UncommunicativeMethodName' => { 'enabled' => false }
104
+ }
121
105
  }
122
106
  end
123
107
 
124
108
  it 'loads the configuration from given file' do
125
- configuration = described_class.load_from_file(CONFIG_PATH.join('full_mask.reek'))
109
+ configuration = described_class.load_from_file(CONFIGURATION_DIR.join('full_mask.reek'))
126
110
  expect(configuration).to eq(sample_configuration_loaded)
127
111
  end
112
+
113
+ context 'with exclude, accept and reject settings' do
114
+ context 'when configuring top level detectors' do
115
+ let(:configuration) do
116
+ described_class.
117
+ load_from_file(CONFIGURATION_DIR.join('accepts_rejects_and_excludes_for_detectors.reek.yml')).
118
+ fetch(Reek::Configuration::AppConfiguration::DETECTORS_KEY)
119
+ end
120
+
121
+ let(:expected) do
122
+ {
123
+ 'UnusedPrivateMethod' => { 'exclude' => [/exclude regexp/] },
124
+ 'UncommunicativeMethodName' => { 'reject' => ['reject name'],
125
+ 'accept' => ['accept name'] },
126
+ 'UncommunicativeModuleName' => { 'reject' => ['reject name 1', 'reject name 2'],
127
+ 'accept' => ['accept name 1', 'accept name 2'] },
128
+ 'UncommunicativeParameterName' => { 'reject' => ['reject name', /reject regexp/],
129
+ 'accept' => ['accept name', /accept regexp/] },
130
+ 'UncommunicativeVariableName' => { 'reject' => [/^reject regexp$/],
131
+ 'accept' => [/accept(.*)regexp/] }
132
+ }
133
+ end
134
+
135
+ it 'converts marked strings to regexes' do
136
+ expect(configuration['UnusedPrivateMethod']).to eq(expected['UnusedPrivateMethod'])
137
+ end
138
+
139
+ it 'leaves regular single strings untouched' do
140
+ expect(configuration['UncommunicativeMethodName']).to eq(expected['UncommunicativeMethodName'])
141
+ end
142
+
143
+ it 'leaves regular multiple strings untouched' do
144
+ expect(configuration['UncommunicativeModuleName']).to eq(expected['UncommunicativeModuleName'])
145
+ end
146
+
147
+ it 'allows mixing of regular strings and marked strings' do
148
+ expect(configuration['UncommunicativeParameterName']).to eq(expected['UncommunicativeParameterName'])
149
+ end
150
+
151
+ it 'converts more complex marked strings correctly to regexes' do
152
+ expect(configuration['UncommunicativeVariableName']).to eq(expected['UncommunicativeVariableName'])
153
+ end
154
+ end
155
+
156
+ context 'when configuring directory directives' do
157
+ let(:directory_name) { 'app/controllers' }
158
+ let(:configuration) do
159
+ described_class.
160
+ load_from_file(CONFIGURATION_DIR.join('accepts_rejects_and_excludes_for_directory_directives.reek.yml')).
161
+ fetch(Reek::Configuration::AppConfiguration::DIRECTORIES_KEY)
162
+ end
163
+
164
+ let(:expected) do
165
+ {
166
+ directory_name => {
167
+ 'UnusedPrivateMethod' => { 'exclude' => [/exclude regexp/] },
168
+ 'UncommunicativeMethodName' => { 'reject' => ['reject name'],
169
+ 'accept' => ['accept name'] },
170
+ 'UncommunicativeModuleName' => { 'reject' => ['reject name 1', 'reject name 2'],
171
+ 'accept' => ['accept name 1', 'accept name 2'] },
172
+ 'UncommunicativeParameterName' => { 'reject' => ['reject name', /reject regexp/],
173
+ 'accept' => ['accept name', /accept regexp/] },
174
+ 'UncommunicativeVariableName' => { 'reject' => [/^reject regexp$/],
175
+ 'accept' => [/accept(.*)regexp/] }
176
+ }
177
+ }
178
+ end
179
+
180
+ it 'converts marked strings to regexes' do
181
+ expect(configuration[directory_name]['UnusedPrivateMethod']).
182
+ to eq(expected[directory_name]['UnusedPrivateMethod'])
183
+ end
184
+
185
+ it 'leaves regular single strings untouched' do
186
+ expect(configuration[directory_name]['UncommunicativeMethodName']).
187
+ to eq(expected[directory_name]['UncommunicativeMethodName'])
188
+ end
189
+
190
+ it 'leaves regular multiple strings untouched' do
191
+ expect(configuration[directory_name]['UncommunicativeModuleName']).
192
+ to eq(expected[directory_name]['UncommunicativeModuleName'])
193
+ end
194
+
195
+ it 'allows mixing of regular strings and marked strings' do
196
+ expect(configuration[directory_name]['UncommunicativeParameterName']).
197
+ to eq(expected[directory_name]['UncommunicativeParameterName'])
198
+ end
199
+
200
+ it 'converts more complex marked strings correctly to regexes' do
201
+ expect(configuration[directory_name]['UncommunicativeVariableName']).
202
+ to eq(expected[directory_name]['UncommunicativeVariableName'])
203
+ end
204
+ end
205
+ end
206
+
207
+ it 'returns blank hash when no file is found' do
208
+ config = described_class.load_from_file(nil)
209
+
210
+ expect(config).to eq({})
211
+ end
128
212
  end
129
213
 
130
214
  private