reek 4.6.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -12
  3. data/.rubocop.yml +79 -26
  4. data/.simplecov +1 -0
  5. data/.travis.yml +3 -9
  6. data/.yardopts +1 -1
  7. data/CHANGELOG.md +76 -0
  8. data/CONTRIBUTING.md +1 -1
  9. data/Gemfile +5 -5
  10. data/README.md +138 -107
  11. data/Rakefile +16 -3
  12. data/bin/code_climate_reek +1 -0
  13. data/bin/reek +2 -3
  14. data/docs/API.md +2 -9
  15. data/docs/Basic-Smell-Options.md +51 -11
  16. data/docs/Code-Smells.md +1 -1
  17. data/docs/Command-Line-Options.md +14 -4
  18. data/docs/Duplicate-Method-Call.md +49 -1
  19. data/docs/Feature-Envy.md +44 -0
  20. data/docs/How-To-Write-New-Detectors.md +7 -7
  21. data/docs/Instance-Variable-Assumption.md +1 -1
  22. data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
  23. data/docs/Rake-Task.md +1 -1
  24. data/docs/Reek-4-to-Reek-5-migration.md +193 -0
  25. data/docs/Reek-Driven-Development.md +1 -1
  26. data/docs/Uncommunicative-Method-Name.md +45 -6
  27. data/docs/Uncommunicative-Module-Name.md +49 -7
  28. data/docs/Uncommunicative-Parameter-Name.md +43 -5
  29. data/docs/Uncommunicative-Variable-Name.md +73 -2
  30. data/docs/Unused-Private-Method.md +3 -3
  31. data/docs/defaults.reek.yml +129 -0
  32. data/docs/yard_plugin.rb +1 -0
  33. data/features/command_line_interface/basic_usage.feature +2 -2
  34. data/features/command_line_interface/options.feature +46 -4
  35. data/features/command_line_interface/show_progress.feature +4 -4
  36. data/features/command_line_interface/smell_selection.feature +1 -1
  37. data/features/command_line_interface/smells_count.feature +6 -6
  38. data/features/command_line_interface/stdin.feature +31 -5
  39. data/features/configuration_files/accept_setting.feature +45 -28
  40. data/features/configuration_files/directory_specific_directives.feature +80 -75
  41. data/features/configuration_files/exclude_directives.feature +11 -10
  42. data/features/configuration_files/exclude_paths_directives.feature +4 -4
  43. data/features/configuration_files/masking_smells.feature +38 -9
  44. data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
  45. data/features/configuration_files/reject_setting.feature +52 -41
  46. data/features/configuration_files/schema_validation.feature +59 -0
  47. data/features/configuration_files/unused_private_method.feature +18 -16
  48. data/features/configuration_loading.feature +53 -10
  49. data/features/configuration_via_source_comments/erroneous_source_comments.feature +3 -3
  50. data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
  51. data/features/locales.feature +32 -0
  52. data/features/rake_task/rake_task.feature +58 -18
  53. data/features/reports/codeclimate.feature +59 -0
  54. data/features/reports/json.feature +3 -3
  55. data/features/reports/reports.feature +34 -34
  56. data/features/reports/yaml.feature +3 -3
  57. data/features/rspec_matcher.feature +40 -0
  58. data/features/samples.feature +287 -287
  59. data/features/step_definitions/reek_steps.rb +14 -2
  60. data/features/step_definitions/sample_file_steps.rb +9 -4
  61. data/features/support/env.rb +2 -11
  62. data/features/todo_list.feature +26 -23
  63. data/lib/reek/ast/ast_node_class_map.rb +1 -0
  64. data/lib/reek/ast/builder.rb +16 -0
  65. data/lib/reek/ast/node.rb +50 -58
  66. data/lib/reek/ast/object_refs.rb +2 -1
  67. data/lib/reek/ast/reference_collector.rb +3 -4
  68. data/lib/reek/ast/sexp_extensions/arguments.rb +1 -0
  69. data/lib/reek/ast/sexp_extensions/attribute_assignments.rb +1 -0
  70. data/lib/reek/ast/sexp_extensions/begin.rb +17 -0
  71. data/lib/reek/ast/sexp_extensions/block.rb +1 -0
  72. data/lib/reek/ast/sexp_extensions/case.rb +2 -1
  73. data/lib/reek/ast/sexp_extensions/constant.rb +1 -0
  74. data/lib/reek/ast/sexp_extensions/if.rb +9 -1
  75. data/lib/reek/ast/sexp_extensions/lambda.rb +1 -0
  76. data/lib/reek/ast/sexp_extensions/literal.rb +1 -0
  77. data/lib/reek/ast/sexp_extensions/logical_operators.rb +2 -1
  78. data/lib/reek/ast/sexp_extensions/methods.rb +5 -6
  79. data/lib/reek/ast/sexp_extensions/module.rb +55 -8
  80. data/lib/reek/ast/sexp_extensions/nested_assignables.rb +1 -0
  81. data/lib/reek/ast/sexp_extensions/self.rb +1 -0
  82. data/lib/reek/ast/sexp_extensions/send.rb +1 -4
  83. data/lib/reek/ast/sexp_extensions/super.rb +1 -0
  84. data/lib/reek/ast/sexp_extensions/symbols.rb +1 -0
  85. data/lib/reek/ast/sexp_extensions/variables.rb +1 -0
  86. data/lib/reek/ast/sexp_extensions/when.rb +1 -0
  87. data/lib/reek/ast/sexp_extensions/yield.rb +1 -0
  88. data/lib/reek/ast/sexp_extensions.rb +2 -0
  89. data/lib/reek/cli/application.rb +5 -3
  90. data/lib/reek/cli/command/base_command.rb +1 -0
  91. data/lib/reek/cli/command/report_command.rb +2 -2
  92. data/lib/reek/cli/command/todo_list_command.rb +9 -8
  93. data/lib/reek/cli/options.rb +32 -16
  94. data/lib/reek/cli/silencer.rb +15 -3
  95. data/lib/reek/cli/status.rb +1 -0
  96. data/lib/reek/code_comment.rb +14 -16
  97. data/lib/reek/configuration/app_configuration.rb +34 -28
  98. data/lib/reek/configuration/configuration_converter.rb +110 -0
  99. data/lib/reek/configuration/configuration_file_finder.rb +17 -41
  100. data/lib/reek/configuration/configuration_validator.rb +13 -23
  101. data/lib/reek/configuration/default_directive.rb +18 -3
  102. data/lib/reek/configuration/directory_directives.rb +18 -11
  103. data/lib/reek/configuration/excluded_paths.rb +2 -1
  104. data/lib/reek/configuration/rake_task_converter.rb +29 -0
  105. data/lib/reek/configuration/schema.yml +210 -0
  106. data/lib/reek/configuration/schema_validator.rb +38 -0
  107. data/lib/reek/context/attribute_context.rb +4 -3
  108. data/lib/reek/context/class_context.rb +1 -0
  109. data/lib/reek/context/code_context.rb +49 -44
  110. data/lib/reek/context/ghost_context.rb +1 -2
  111. data/lib/reek/context/method_context.rb +26 -18
  112. data/lib/reek/context/module_context.rb +11 -11
  113. data/lib/reek/context/root_context.rb +1 -4
  114. data/lib/reek/context/send_context.rb +3 -2
  115. data/lib/reek/context/singleton_attribute_context.rb +1 -0
  116. data/lib/reek/context/singleton_method_context.rb +1 -0
  117. data/lib/reek/context/statement_counter.rb +1 -0
  118. data/lib/reek/context/visibility_tracker.rb +1 -0
  119. data/lib/reek/context_builder.rb +44 -44
  120. data/lib/reek/detector_repository.rb +12 -11
  121. data/lib/reek/documentation_link.rb +28 -0
  122. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +15 -13
  123. data/lib/reek/errors/bad_detector_in_comment_error.rb +13 -11
  124. data/lib/reek/errors/base_error.rb +3 -0
  125. data/lib/reek/errors/config_file_error.rb +11 -0
  126. data/lib/reek/errors/encoding_error.rb +43 -0
  127. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +14 -12
  128. data/lib/reek/errors/incomprehensible_source_error.rb +23 -24
  129. data/lib/reek/errors/syntax_error.rb +41 -0
  130. data/lib/reek/examiner.rb +24 -22
  131. data/lib/reek/logging_error_handler.rb +8 -5
  132. data/lib/reek/rake/task.rb +8 -5
  133. data/lib/reek/report/base_report.rb +9 -12
  134. data/lib/reek/report/code_climate/code_climate_configuration.rb +2 -1
  135. data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -6
  136. data/lib/reek/report/code_climate/code_climate_fingerprint.rb +1 -0
  137. data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -0
  138. data/lib/reek/report/code_climate/code_climate_report.rb +1 -0
  139. data/lib/reek/report/code_climate.rb +1 -0
  140. data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
  141. data/lib/reek/report/heading_formatter.rb +54 -0
  142. data/lib/reek/report/html_report.rb +1 -0
  143. data/lib/reek/report/json_report.rb +2 -1
  144. data/lib/reek/report/location_formatter.rb +40 -0
  145. data/lib/reek/report/progress_formatter.rb +79 -0
  146. data/lib/reek/report/simple_warning_formatter.rb +34 -0
  147. data/lib/reek/report/text_report.rb +2 -2
  148. data/lib/reek/report/xml_report.rb +4 -3
  149. data/lib/reek/report/yaml_report.rb +2 -1
  150. data/lib/reek/report.rb +16 -10
  151. data/lib/reek/smell_configuration.rb +3 -2
  152. data/lib/reek/smell_detectors/attribute.rb +6 -11
  153. data/lib/reek/smell_detectors/base_detector.rb +31 -26
  154. data/lib/reek/smell_detectors/boolean_parameter.rb +4 -5
  155. data/lib/reek/smell_detectors/class_variable.rb +6 -14
  156. data/lib/reek/smell_detectors/control_parameter.rb +19 -33
  157. data/lib/reek/smell_detectors/data_clump.rb +16 -9
  158. data/lib/reek/smell_detectors/duplicate_method_call.rb +24 -17
  159. data/lib/reek/smell_detectors/feature_envy.rb +10 -7
  160. data/lib/reek/smell_detectors/instance_variable_assumption.rb +15 -23
  161. data/lib/reek/smell_detectors/irresponsible_module.rb +6 -12
  162. data/lib/reek/smell_detectors/long_parameter_list.rb +11 -7
  163. data/lib/reek/smell_detectors/long_yield_list.rb +11 -7
  164. data/lib/reek/smell_detectors/manual_dispatch.rb +5 -5
  165. data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +21 -20
  166. data/lib/reek/smell_detectors/module_initialize.rb +4 -5
  167. data/lib/reek/smell_detectors/nested_iterators.rb +17 -24
  168. data/lib/reek/smell_detectors/nil_check.rb +9 -15
  169. data/lib/reek/smell_detectors/repeated_conditional.rb +14 -11
  170. data/lib/reek/smell_detectors/subclassed_from_core_class.rb +8 -8
  171. data/lib/reek/smell_detectors/too_many_constants.rb +11 -9
  172. data/lib/reek/smell_detectors/too_many_instance_variables.rb +11 -6
  173. data/lib/reek/smell_detectors/too_many_methods.rb +12 -7
  174. data/lib/reek/smell_detectors/too_many_statements.rb +11 -6
  175. data/lib/reek/smell_detectors/uncommunicative_method_name.rb +11 -11
  176. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +15 -18
  177. data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +18 -22
  178. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +27 -27
  179. data/lib/reek/smell_detectors/unused_parameters.rb +5 -6
  180. data/lib/reek/smell_detectors/unused_private_method.rb +14 -20
  181. data/lib/reek/smell_detectors/utility_function.rb +13 -16
  182. data/lib/reek/smell_detectors.rb +2 -1
  183. data/lib/reek/smell_warning.rb +16 -8
  184. data/lib/reek/source/source_code.rb +65 -46
  185. data/lib/reek/source/source_locator.rb +9 -8
  186. data/lib/reek/spec/should_reek.rb +3 -2
  187. data/lib/reek/spec/should_reek_of.rb +13 -26
  188. data/lib/reek/spec/should_reek_only_of.rb +5 -4
  189. data/lib/reek/spec/smell_matcher.rb +2 -1
  190. data/lib/reek/spec.rb +7 -6
  191. data/lib/reek/tree_dresser.rb +9 -8
  192. data/lib/reek/version.rb +2 -1
  193. data/lib/reek.rb +1 -0
  194. data/reek.gemspec +5 -6
  195. data/samples/checkstyle.xml +1 -1
  196. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
  197. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
  198. data/samples/configuration/full_configuration.reek +8 -4
  199. data/samples/configuration/full_mask.reek +5 -4
  200. data/samples/configuration/partial_mask.reek +3 -2
  201. data/samples/configuration/regular_configuration/.reek.yml +4 -0
  202. data/samples/paths.rb +5 -4
  203. data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
  204. data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
  205. data/spec/factories/factories.rb +2 -13
  206. data/spec/reek/ast/node_spec.rb +103 -10
  207. data/spec/reek/ast/reference_collector_spec.rb +1 -1
  208. data/spec/reek/ast/sexp_extensions_spec.rb +15 -34
  209. data/spec/reek/cli/application_spec.rb +52 -42
  210. data/spec/reek/cli/command/todo_list_command_spec.rb +6 -4
  211. data/spec/reek/cli/silencer_spec.rb +28 -0
  212. data/spec/reek/code_comment_spec.rb +31 -38
  213. data/spec/reek/configuration/app_configuration_spec.rb +46 -33
  214. data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -51
  215. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  216. data/spec/reek/configuration/directory_directives_spec.rb +6 -7
  217. data/spec/reek/configuration/excluded_paths_spec.rb +6 -6
  218. data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
  219. data/spec/reek/configuration/schema_validator_spec.rb +165 -0
  220. data/spec/reek/context/code_context_spec.rb +70 -106
  221. data/spec/reek/context/ghost_context_spec.rb +9 -9
  222. data/spec/reek/context/method_context_spec.rb +2 -2
  223. data/spec/reek/context/module_context_spec.rb +3 -3
  224. data/spec/reek/context/root_context_spec.rb +1 -1
  225. data/spec/reek/context/statement_counter_spec.rb +1 -0
  226. data/spec/reek/context_builder_spec.rb +20 -0
  227. data/spec/reek/documentation_link_spec.rb +20 -0
  228. data/spec/reek/errors/base_error_spec.rb +13 -0
  229. data/spec/reek/examiner_spec.rb +137 -29
  230. data/spec/reek/rake/task_spec.rb +25 -2
  231. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -78
  232. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
  233. data/spec/reek/report/code_climate/code_climate_report_spec.rb +22 -22
  234. data/spec/reek/report/json_report_spec.rb +13 -46
  235. data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
  236. data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
  237. data/spec/reek/report/text_report_spec.rb +4 -4
  238. data/spec/reek/report/xml_report_spec.rb +3 -3
  239. data/spec/reek/report/yaml_report_spec.rb +17 -46
  240. data/spec/reek/report_spec.rb +3 -3
  241. data/spec/reek/smell_detectors/base_detector_spec.rb +4 -5
  242. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +2 -2
  243. data/spec/reek/smell_detectors/class_variable_spec.rb +26 -32
  244. data/spec/reek/smell_detectors/control_parameter_spec.rb +34 -4
  245. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +3 -3
  246. data/spec/reek/smell_detectors/feature_envy_spec.rb +47 -2
  247. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +59 -21
  248. data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +10 -10
  249. data/spec/reek/smell_detectors/module_initialize_spec.rb +14 -0
  250. data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
  251. data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
  252. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
  253. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
  254. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
  255. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +36 -15
  256. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +9 -9
  257. data/spec/reek/smell_detectors/unused_parameters_spec.rb +3 -3
  258. data/spec/reek/smell_detectors/unused_private_method_spec.rb +21 -10
  259. data/spec/reek/smell_detectors/utility_function_spec.rb +57 -5
  260. data/spec/reek/smell_warning_spec.rb +12 -8
  261. data/spec/reek/source/source_code_spec.rb +27 -38
  262. data/spec/reek/source/source_locator_spec.rb +42 -12
  263. data/spec/reek/spec/should_reek_of_spec.rb +25 -30
  264. data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
  265. data/spec/reek/spec/should_reek_spec.rb +8 -8
  266. data/spec/reek/spec/smell_matcher_spec.rb +23 -23
  267. data/spec/reek/tree_dresser_spec.rb +12 -17
  268. data/spec/spec_helper.rb +7 -17
  269. data/tasks/configuration.rake +8 -5
  270. metadata +77 -40
  271. data/defaults.reek +0 -128
  272. data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
  273. data/lib/reek/errors/parse_error.rb +0 -19
  274. data/lib/reek/report/formatter/heading_formatter.rb +0 -51
  275. data/lib/reek/report/formatter/location_formatter.rb +0 -41
  276. data/lib/reek/report/formatter/progress_formatter.rb +0 -80
  277. data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
  278. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -35
  279. data/lib/reek/report/formatter.rb +0 -32
  280. data/samples/configuration/non_public_modifiers_mask.reek +0 -3
  281. data/samples/smelly_with_inline_mask.rb +0 -8
  282. data/samples/smelly_with_modifiers.rb +0 -12
  283. data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
  284. data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
  285. /data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
  286. /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
  287. /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
  288. /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
  289. /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
  290. /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
  291. /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
  292. /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
  293. /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
  294. /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
@@ -15,13 +15,11 @@ RSpec.describe Reek::CLI::Application do
15
15
  end
16
16
  end
17
17
 
18
- let(:path_excluded_in_configuration) do
19
- SAMPLES_PATH.join('source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb')
20
- end
21
-
22
- let(:configuration) { test_configuration_for(CONFIG_PATH.join('with_excluded_paths.reek')) }
23
-
24
18
  describe '#execute' do
19
+ let(:path_excluded_in_configuration) do
20
+ SAMPLES_DIR.join('source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb')
21
+ end
22
+ let(:configuration) { test_configuration_for(CONFIGURATION_DIR.join('with_excluded_paths.reek')) }
25
23
  let(:command) { instance_double 'Reek::CLI::Command::ReportCommand' }
26
24
  let(:app) { described_class.new [] }
27
25
 
@@ -34,57 +32,69 @@ RSpec.describe Reek::CLI::Application do
34
32
  expect(app.execute).to eq 'foo'
35
33
  end
36
34
 
37
- context 'when no source files given' do
38
- context 'and input was piped' do
39
- before do
40
- allow_any_instance_of(IO).to receive(:tty?).and_return(false)
41
- end
35
+ context 'when no source files given and input was piped' do
36
+ before do
37
+ allow_any_instance_of(IO).to receive(:tty?).and_return(false)
38
+ end
42
39
 
43
- it 'uses source form pipe' do
44
- app.execute
45
- expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
46
- with(sources: [$stdin],
47
- configuration: Reek::Configuration::AppConfiguration,
48
- options: Reek::CLI::Options)
49
- end
40
+ it 'uses source from pipe' do
41
+ expected_sources = a_collection_containing_exactly(have_attributes(origin: 'STDIN'))
42
+ app.execute
43
+ expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
44
+ with(sources: expected_sources,
45
+ configuration: Reek::Configuration::AppConfiguration,
46
+ options: Reek::CLI::Options)
50
47
  end
51
48
 
52
- context 'and input was not piped' do
53
- before do
54
- allow_any_instance_of(IO).to receive(:tty?).and_return(true)
55
- end
49
+ context 'when a stdin filename is provided' do
50
+ let(:app) { described_class.new ['--stdin-filename', 'foo.rb'] }
56
51
 
57
- it 'uses working directory as source' do
58
- expected_sources = Reek::Source::SourceLocator.new(['.']).sources
52
+ it 'assumes that filename' do
53
+ expected_sources = a_collection_containing_exactly(have_attributes(origin: 'foo.rb'))
59
54
  app.execute
60
55
  expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
61
56
  with(sources: expected_sources,
62
57
  configuration: Reek::Configuration::AppConfiguration,
63
58
  options: Reek::CLI::Options)
64
59
  end
60
+ end
61
+ end
65
62
 
66
- context 'when source files are excluded through configuration' do
67
- let(:app) { described_class.new ['--config', 'some_file.reek'] }
63
+ context 'when no source files given and no input was piped' do
64
+ before do
65
+ allow_any_instance_of(IO).to receive(:tty?).and_return(true)
66
+ end
68
67
 
69
- before do
70
- allow(Reek::Configuration::AppConfiguration).
71
- to receive(:from_path).
72
- with(Pathname.new('some_file.reek')).
73
- and_return configuration
74
- end
68
+ it 'uses working directory as source' do
69
+ expected_sources = Reek::Source::SourceLocator.new(['.']).sources
70
+ app.execute
71
+ expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
72
+ with(sources: expected_sources,
73
+ configuration: Reek::Configuration::AppConfiguration,
74
+ options: Reek::CLI::Options)
75
+ end
75
76
 
76
- it 'uses configuration for excluded paths' do
77
- expected_sources = Reek::Source::SourceLocator.
78
- new(['.'], configuration: configuration).sources
79
- expect(expected_sources).not_to include(path_excluded_in_configuration)
77
+ context 'when source files are excluded through configuration' do
78
+ let(:app) { described_class.new ['--config', 'some_file.reek'] }
80
79
 
81
- app.execute
80
+ before do
81
+ allow(Reek::Configuration::AppConfiguration).
82
+ to receive(:from_path).
83
+ with(Pathname.new('some_file.reek')).
84
+ and_return configuration
85
+ end
82
86
 
83
- expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
84
- with(sources: expected_sources,
85
- configuration: configuration,
86
- options: Reek::CLI::Options)
87
- end
87
+ it 'uses configuration for excluded paths' do
88
+ expected_sources = Reek::Source::SourceLocator.
89
+ new(['.'], configuration: configuration).sources
90
+ expect(expected_sources).not_to include(path_excluded_in_configuration)
91
+
92
+ app.execute
93
+
94
+ expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
95
+ with(sources: expected_sources,
96
+ configuration: configuration,
97
+ options: Reek::CLI::Options)
88
98
  end
89
99
  end
90
100
  end
@@ -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 }
@@ -21,7 +22,7 @@ RSpec.describe Reek::CLI::Command::TodoListCommand do
21
22
  allow(File).to receive(:write).with(described_class::FILE_NAME, String)
22
23
  end
23
24
 
24
- context 'smells found' do
25
+ context 'when smells are found' do
25
26
  let(:source_file) { SMELLY_FILE }
26
27
 
27
28
  it 'shows a proper message' do
@@ -37,14 +38,15 @@ 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
45
47
  end
46
48
 
47
- context 'no smells found' do
49
+ context 'when no smells re found' do
48
50
  let(:source_file) { CLEAN_FILE }
49
51
 
50
52
  it 'shows a proper message' do
@@ -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
@@ -3,7 +3,7 @@ require_lib 'reek/code_comment'
3
3
 
4
4
  RSpec.describe Reek::CodeComment do
5
5
  context 'with an empty comment' do
6
- let(:comment) { FactoryGirl.build(:code_comment, comment: '') }
6
+ let(:comment) { build(:code_comment, comment: '') }
7
7
 
8
8
  it 'is not descriptive' do
9
9
  expect(comment).not_to be_descriptive
@@ -14,33 +14,33 @@ RSpec.describe Reek::CodeComment do
14
14
  end
15
15
  end
16
16
 
17
- context 'comment checks' do
17
+ describe '#descriptive' do
18
18
  it 'rejects an empty comment' do
19
- comment = FactoryGirl.build(:code_comment, comment: '#')
19
+ comment = build(:code_comment, comment: '#')
20
20
  expect(comment).not_to be_descriptive
21
21
  end
22
22
 
23
23
  it 'rejects a 1-word comment' do
24
- comment = FactoryGirl.build(:code_comment, comment: "# alpha\n# ")
24
+ comment = build(:code_comment, comment: "# alpha\n# ")
25
25
  expect(comment).not_to be_descriptive
26
26
  end
27
27
 
28
28
  it 'accepts a 2-word comment' do
29
- comment = FactoryGirl.build(:code_comment, comment: '# alpha bravo ')
29
+ comment = build(:code_comment, comment: '# alpha bravo ')
30
30
  expect(comment).to be_descriptive
31
31
  end
32
32
 
33
33
  it 'accepts a multi-word comment' do
34
- comment = FactoryGirl.build(:code_comment, comment: "# alpha bravo \n# charlie \n # delta ")
34
+ comment = build(:code_comment, comment: "# alpha bravo \n# charlie \n # delta ")
35
35
  expect(comment).to be_descriptive
36
36
  end
37
37
  end
38
38
 
39
- context 'good comment config' do
39
+ describe 'good comment config' do
40
40
  it 'parses hashed options' do
41
41
  comment = '# :reek:DuplicateMethodCall { enabled: false }'
42
- config = FactoryGirl.build(:code_comment,
43
- comment: comment).config
42
+ config = build(:code_comment,
43
+ comment: comment).config
44
44
 
45
45
  expect(config).to include('DuplicateMethodCall')
46
46
  expect(config['DuplicateMethodCall']).to include('enabled')
@@ -49,8 +49,8 @@ RSpec.describe Reek::CodeComment do
49
49
 
50
50
  it "supports hashed options with the legacy separator ':' after the smell detector" do
51
51
  comment = '# :reek:DuplicateMethodCall: { enabled: false }'
52
- config = FactoryGirl.build(:code_comment,
53
- comment: comment).config
52
+ config = build(:code_comment,
53
+ comment: comment).config
54
54
 
55
55
  expect(config).to include('DuplicateMethodCall')
56
56
  expect(config['DuplicateMethodCall']).to include('enabled')
@@ -62,7 +62,7 @@ RSpec.describe Reek::CodeComment do
62
62
  # :reek:DuplicateMethodCall { enabled: false }
63
63
  # :reek:NestedIterators { enabled: true }
64
64
  EOF
65
- config = FactoryGirl.build(:code_comment, comment: comment).config
65
+ config = build(:code_comment, comment: comment).config
66
66
 
67
67
  expect(config).to include('DuplicateMethodCall', 'NestedIterators')
68
68
  expect(config['DuplicateMethodCall']).to include('enabled')
@@ -75,7 +75,7 @@ RSpec.describe Reek::CodeComment do
75
75
  comment = <<-EOF
76
76
  #:reek:DuplicateMethodCall { enabled: false } and :reek:NestedIterators { enabled: true }
77
77
  EOF
78
- config = FactoryGirl.build(:code_comment, comment: comment).config
78
+ config = build(:code_comment, comment: comment).config
79
79
 
80
80
  expect(config).to include('DuplicateMethodCall', 'NestedIterators')
81
81
  expect(config['DuplicateMethodCall']).to include('enabled')
@@ -86,7 +86,7 @@ RSpec.describe Reek::CodeComment do
86
86
 
87
87
  it 'parses multiple unhashed options on the same line' do
88
88
  comment = '# :reek:DuplicateMethodCall and :reek:NestedIterators'
89
- config = FactoryGirl.build(:code_comment, comment: comment).config
89
+ config = build(:code_comment, comment: comment).config
90
90
 
91
91
  expect(config).to include('DuplicateMethodCall', 'NestedIterators')
92
92
  expect(config['DuplicateMethodCall']).to include('enabled')
@@ -97,7 +97,7 @@ RSpec.describe Reek::CodeComment do
97
97
 
98
98
  it 'disables the smell if no options are specifed' do
99
99
  comment = '# :reek:DuplicateMethodCall'
100
- config = FactoryGirl.build(:code_comment, comment: comment).config
100
+ config = build(:code_comment, comment: comment).config
101
101
 
102
102
  expect(config).to include('DuplicateMethodCall')
103
103
  expect(config['DuplicateMethodCall']).to include('enabled')
@@ -105,8 +105,8 @@ RSpec.describe Reek::CodeComment do
105
105
  end
106
106
 
107
107
  it 'ignores smells after a space' do
108
- config = FactoryGirl.build(:code_comment,
109
- comment: '# :reek: DuplicateMethodCall').config
108
+ config = build(:code_comment,
109
+ comment: '# :reek: DuplicateMethodCall').config
110
110
  expect(config).not_to include('DuplicateMethodCall')
111
111
  end
112
112
 
@@ -117,7 +117,7 @@ RSpec.describe Reek::CodeComment do
117
117
  # :reek:NestedIterators { enabled: true }
118
118
  # comment
119
119
  EOF
120
- comment = FactoryGirl.build(:code_comment, comment: original_comment)
120
+ comment = build(:code_comment, comment: original_comment)
121
121
 
122
122
  expect(comment.send(:sanitized_comment)).to eq('Actual comment')
123
123
  end
@@ -125,66 +125,59 @@ RSpec.describe Reek::CodeComment do
125
125
  end
126
126
 
127
127
  RSpec.describe Reek::CodeComment::CodeCommentValidator do
128
- context 'bad detector' do
128
+ context 'when the comment contains an unknown detector name' do
129
129
  it 'raises BadDetectorInCommentError' do
130
130
  expect do
131
- FactoryGirl.build(:code_comment,
132
- comment: '# :reek:DoesNotExist')
131
+ build(:code_comment,
132
+ comment: '# :reek:DoesNotExist')
133
133
  end.to raise_error(Reek::Errors::BadDetectorInCommentError)
134
134
  end
135
135
  end
136
136
 
137
- context 'unparsable detector configuration' do
137
+ context 'when the comment contains an unparsable detector configuration' do
138
138
  it 'raises GarbageDetectorConfigurationInCommentError' do
139
139
  expect do
140
140
  comment = '# :reek:UncommunicativeMethodName { thats: a: bad: config }'
141
- FactoryGirl.build(:code_comment, comment: comment)
141
+ build(:code_comment, comment: comment)
142
142
  end.to raise_error(Reek::Errors::GarbageDetectorConfigurationInCommentError)
143
143
  end
144
144
  end
145
145
 
146
146
  describe 'validating configuration keys' do
147
- context 'basic options mispelled' do
147
+ context 'when basic options are mispelled' do
148
148
  it 'raises BadDetectorConfigurationKeyInCommentError' do
149
149
  expect do
150
150
  # exclude -> exlude and enabled -> nabled
151
151
  comment = '# :reek:UncommunicativeMethodName { exlude: alfa, nabled: true }'
152
- FactoryGirl.build(:code_comment, comment: comment)
152
+ build(:code_comment, comment: comment)
153
153
  end.to raise_error(Reek::Errors::BadDetectorConfigurationKeyInCommentError)
154
154
  end
155
155
  end
156
156
 
157
- context 'basic options not mispelled' do
157
+ context 'when basic options are not mispelled' do
158
158
  it 'does not raise' do
159
159
  expect do
160
160
  comment = '# :reek:UncommunicativeMethodName { exclude: alfa, enabled: true }'
161
- FactoryGirl.build(:code_comment, comment: comment)
162
- end.not_to raise_error
163
- end
164
-
165
- it 'does not raise on regexps' do
166
- expect do
167
- comment = '# :reek:UncommunicativeMethodName { exclude: !ruby/regexp /alfa/ }'
168
- FactoryGirl.build(:code_comment, comment: comment)
161
+ build(:code_comment, comment: comment)
169
162
  end.not_to raise_error
170
163
  end
171
164
  end
172
165
 
173
- context 'unknown custom options' do
166
+ context 'when unknown custom options are specified' do
174
167
  it 'raises BadDetectorConfigurationKeyInCommentError' do
175
168
  expect do
176
169
  # max_copies -> mx_copies and min_clump_size -> mn_clump_size
177
170
  comment = '# :reek:DataClump { mx_copies: 4, mn_clump_size: 3 }'
178
- FactoryGirl.build(:code_comment, comment: comment)
171
+ build(:code_comment, comment: comment)
179
172
  end.to raise_error(Reek::Errors::BadDetectorConfigurationKeyInCommentError)
180
173
  end
181
174
  end
182
175
 
183
- context 'valid custom options' do
176
+ context 'when valid custom options are specified' do
184
177
  it 'does not raise' do
185
178
  expect do
186
179
  comment = '# :reek:DataClump { max_copies: 4, min_clump_size: 3 }'
187
- FactoryGirl.build(:code_comment, comment: comment)
180
+ build(:code_comment, comment: comment)
188
181
  end.not_to raise_error
189
182
  end
190
183
  end
@@ -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
@@ -75,36 +78,40 @@ RSpec.describe Reek::Configuration::AppConfiguration do
75
78
  end
76
79
 
77
80
  describe '#directive_for' do
78
- context 'multiple directory directives and no default directive present' do
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
- context 'directory directive and default directive present' do
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 '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