reek 4.7.3 → 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 (248) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -12
  3. data/.rubocop.yml +18 -3
  4. data/.simplecov +1 -0
  5. data/.travis.yml +3 -4
  6. data/.yardopts +1 -1
  7. data/CHANGELOG.md +45 -0
  8. data/Gemfile +4 -4
  9. data/README.md +134 -104
  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/Instance-Variable-Assumption.md +1 -1
  20. data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
  21. data/docs/Rake-Task.md +1 -1
  22. data/docs/Reek-4-to-Reek-5-migration.md +193 -0
  23. data/docs/Reek-Driven-Development.md +1 -1
  24. data/docs/Uncommunicative-Method-Name.md +45 -6
  25. data/docs/Uncommunicative-Module-Name.md +49 -7
  26. data/docs/Uncommunicative-Parameter-Name.md +43 -5
  27. data/docs/Uncommunicative-Variable-Name.md +73 -2
  28. data/docs/Unused-Private-Method.md +2 -2
  29. data/docs/defaults.reek.yml +129 -0
  30. data/docs/yard_plugin.rb +1 -0
  31. data/features/command_line_interface/basic_usage.feature +2 -2
  32. data/features/command_line_interface/options.feature +46 -4
  33. data/features/command_line_interface/show_progress.feature +4 -4
  34. data/features/command_line_interface/smell_selection.feature +1 -1
  35. data/features/command_line_interface/smells_count.feature +6 -6
  36. data/features/command_line_interface/stdin.feature +30 -8
  37. data/features/configuration_files/accept_setting.feature +45 -28
  38. data/features/configuration_files/directory_specific_directives.feature +78 -73
  39. data/features/configuration_files/exclude_directives.feature +11 -10
  40. data/features/configuration_files/exclude_paths_directives.feature +4 -4
  41. data/features/configuration_files/masking_smells.feature +38 -9
  42. data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
  43. data/features/configuration_files/reject_setting.feature +52 -41
  44. data/features/configuration_files/schema_validation.feature +59 -0
  45. data/features/configuration_files/unused_private_method.feature +18 -16
  46. data/features/configuration_loading.feature +53 -10
  47. data/features/configuration_via_source_comments/erroneous_source_comments.feature +2 -2
  48. data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
  49. data/features/locales.feature +2 -2
  50. data/features/rake_task/rake_task.feature +15 -15
  51. data/features/reports/json.feature +3 -3
  52. data/features/reports/reports.feature +34 -34
  53. data/features/reports/yaml.feature +3 -3
  54. data/features/rspec_matcher.feature +9 -1
  55. data/features/samples.feature +287 -287
  56. data/features/step_definitions/reek_steps.rb +4 -0
  57. data/features/step_definitions/sample_file_steps.rb +9 -4
  58. data/features/support/env.rb +2 -2
  59. data/features/todo_list.feature +26 -23
  60. data/lib/reek/ast/node.rb +40 -55
  61. data/lib/reek/ast/object_refs.rb +1 -1
  62. data/lib/reek/ast/reference_collector.rb +2 -4
  63. data/lib/reek/ast/sexp_extensions/case.rb +1 -1
  64. data/lib/reek/ast/sexp_extensions/if.rb +8 -1
  65. data/lib/reek/ast/sexp_extensions/logical_operators.rb +1 -1
  66. data/lib/reek/ast/sexp_extensions/methods.rb +4 -6
  67. data/lib/reek/cli/application.rb +4 -3
  68. data/lib/reek/cli/command/report_command.rb +1 -2
  69. data/lib/reek/cli/command/todo_list_command.rb +8 -8
  70. data/lib/reek/cli/options.rb +29 -14
  71. data/lib/reek/cli/silencer.rb +14 -3
  72. data/lib/reek/code_comment.rb +14 -16
  73. data/lib/reek/configuration/app_configuration.rb +32 -28
  74. data/lib/reek/configuration/configuration_converter.rb +110 -0
  75. data/lib/reek/configuration/configuration_file_finder.rb +15 -40
  76. data/lib/reek/configuration/configuration_validator.rb +12 -23
  77. data/lib/reek/configuration/default_directive.rb +17 -3
  78. data/lib/reek/configuration/directory_directives.rb +17 -11
  79. data/lib/reek/configuration/excluded_paths.rb +1 -1
  80. data/lib/reek/configuration/rake_task_converter.rb +29 -0
  81. data/lib/reek/configuration/schema.yml +210 -0
  82. data/lib/reek/configuration/schema_validator.rb +38 -0
  83. data/lib/reek/context/attribute_context.rb +1 -1
  84. data/lib/reek/context/code_context.rb +8 -11
  85. data/lib/reek/context/method_context.rb +7 -12
  86. data/lib/reek/context/module_context.rb +4 -4
  87. data/lib/reek/context_builder.rb +11 -11
  88. data/lib/reek/detector_repository.rb +6 -0
  89. data/lib/reek/documentation_link.rb +28 -0
  90. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +13 -12
  91. data/lib/reek/errors/bad_detector_in_comment_error.rb +11 -10
  92. data/lib/reek/errors/base_error.rb +3 -0
  93. data/lib/reek/errors/config_file_error.rb +11 -0
  94. data/lib/reek/errors/encoding_error.rb +16 -11
  95. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +11 -10
  96. data/lib/reek/errors/incomprehensible_source_error.rb +20 -22
  97. data/lib/reek/errors/syntax_error.rb +41 -0
  98. data/lib/reek/examiner.rb +19 -25
  99. data/lib/reek/logging_error_handler.rb +7 -5
  100. data/lib/reek/rake/task.rb +3 -3
  101. data/lib/reek/report/base_report.rb +8 -12
  102. data/lib/reek/report/code_climate/code_climate_configuration.rb +1 -1
  103. data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -10
  104. data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
  105. data/lib/reek/report/heading_formatter.rb +54 -0
  106. data/lib/reek/report/json_report.rb +1 -1
  107. data/lib/reek/report/location_formatter.rb +40 -0
  108. data/lib/reek/report/progress_formatter.rb +79 -0
  109. data/lib/reek/report/simple_warning_formatter.rb +34 -0
  110. data/lib/reek/report/text_report.rb +1 -2
  111. data/lib/reek/report/xml_report.rb +3 -3
  112. data/lib/reek/report/yaml_report.rb +1 -1
  113. data/lib/reek/report.rb +15 -10
  114. data/lib/reek/smell_configuration.rb +2 -2
  115. data/lib/reek/smell_detectors/attribute.rb +0 -1
  116. data/lib/reek/smell_detectors/base_detector.rb +9 -12
  117. data/lib/reek/smell_detectors/boolean_parameter.rb +0 -1
  118. data/lib/reek/smell_detectors/class_variable.rb +3 -11
  119. data/lib/reek/smell_detectors/control_parameter.rb +17 -32
  120. data/lib/reek/smell_detectors/data_clump.rb +3 -4
  121. data/lib/reek/smell_detectors/duplicate_method_call.rb +6 -7
  122. data/lib/reek/smell_detectors/feature_envy.rb +1 -1
  123. data/lib/reek/smell_detectors/instance_variable_assumption.rb +1 -10
  124. data/lib/reek/smell_detectors/irresponsible_module.rb +0 -1
  125. data/lib/reek/smell_detectors/long_parameter_list.rb +1 -2
  126. data/lib/reek/smell_detectors/long_yield_list.rb +2 -3
  127. data/lib/reek/smell_detectors/manual_dispatch.rb +3 -3
  128. data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +6 -7
  129. data/lib/reek/smell_detectors/module_initialize.rb +1 -2
  130. data/lib/reek/smell_detectors/nested_iterators.rb +6 -6
  131. data/lib/reek/smell_detectors/nil_check.rb +0 -1
  132. data/lib/reek/smell_detectors/repeated_conditional.rb +3 -4
  133. data/lib/reek/smell_detectors/subclassed_from_core_class.rb +0 -1
  134. data/lib/reek/smell_detectors/too_many_constants.rb +2 -3
  135. data/lib/reek/smell_detectors/too_many_instance_variables.rb +1 -2
  136. data/lib/reek/smell_detectors/too_many_methods.rb +1 -2
  137. data/lib/reek/smell_detectors/too_many_statements.rb +1 -2
  138. data/lib/reek/smell_detectors/uncommunicative_method_name.rb +2 -3
  139. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +2 -3
  140. data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +2 -3
  141. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +6 -7
  142. data/lib/reek/smell_detectors/unused_parameters.rb +0 -1
  143. data/lib/reek/smell_detectors/unused_private_method.rb +0 -1
  144. data/lib/reek/smell_detectors/utility_function.rb +2 -3
  145. data/lib/reek/smell_detectors.rb +1 -2
  146. data/lib/reek/smell_warning.rb +15 -8
  147. data/lib/reek/source/source_code.rb +50 -72
  148. data/lib/reek/source/source_locator.rb +7 -7
  149. data/lib/reek/spec/should_reek.rb +2 -2
  150. data/lib/reek/spec/should_reek_of.rb +9 -16
  151. data/lib/reek/spec/should_reek_only_of.rb +4 -4
  152. data/lib/reek/spec.rb +6 -6
  153. data/lib/reek/tree_dresser.rb +5 -5
  154. data/lib/reek/version.rb +1 -1
  155. data/reek.gemspec +5 -5
  156. data/samples/checkstyle.xml +1 -1
  157. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
  158. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
  159. data/samples/configuration/full_configuration.reek +8 -4
  160. data/samples/configuration/full_mask.reek +5 -4
  161. data/samples/configuration/partial_mask.reek +3 -2
  162. data/samples/configuration/regular_configuration/.reek.yml +4 -0
  163. data/samples/paths.rb +5 -4
  164. data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
  165. data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
  166. data/spec/factories/factories.rb +2 -13
  167. data/spec/reek/ast/node_spec.rb +103 -10
  168. data/spec/reek/ast/reference_collector_spec.rb +1 -1
  169. data/spec/reek/ast/sexp_extensions_spec.rb +2 -2
  170. data/spec/reek/cli/application_spec.rb +50 -38
  171. data/spec/reek/cli/command/todo_list_command_spec.rb +6 -4
  172. data/spec/reek/cli/silencer_spec.rb +28 -0
  173. data/spec/reek/code_comment_spec.rb +31 -38
  174. data/spec/reek/configuration/app_configuration_spec.rb +46 -33
  175. data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -49
  176. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  177. data/spec/reek/configuration/directory_directives_spec.rb +6 -7
  178. data/spec/reek/configuration/excluded_paths_spec.rb +6 -6
  179. data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
  180. data/spec/reek/configuration/schema_validator_spec.rb +165 -0
  181. data/spec/reek/context/code_context_spec.rb +60 -96
  182. data/spec/reek/context/ghost_context_spec.rb +1 -1
  183. data/spec/reek/context/root_context_spec.rb +1 -1
  184. data/spec/reek/documentation_link_spec.rb +20 -0
  185. data/spec/reek/errors/base_error_spec.rb +13 -0
  186. data/spec/reek/examiner_spec.rb +100 -30
  187. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -80
  188. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
  189. data/spec/reek/report/json_report_spec.rb +13 -46
  190. data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
  191. data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
  192. data/spec/reek/report/text_report_spec.rb +4 -4
  193. data/spec/reek/report/xml_report_spec.rb +3 -3
  194. data/spec/reek/report/yaml_report_spec.rb +9 -38
  195. data/spec/reek/report_spec.rb +3 -3
  196. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +2 -2
  197. data/spec/reek/smell_detectors/class_variable_spec.rb +26 -32
  198. data/spec/reek/smell_detectors/control_parameter_spec.rb +34 -4
  199. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +3 -3
  200. data/spec/reek/smell_detectors/feature_envy_spec.rb +47 -2
  201. data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +9 -9
  202. data/spec/reek/smell_detectors/module_initialize_spec.rb +14 -0
  203. data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
  204. data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
  205. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
  206. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
  207. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
  208. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +6 -4
  209. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +9 -9
  210. data/spec/reek/smell_detectors/unused_parameters_spec.rb +3 -3
  211. data/spec/reek/smell_detectors/unused_private_method_spec.rb +10 -10
  212. data/spec/reek/smell_detectors/utility_function_spec.rb +5 -5
  213. data/spec/reek/smell_warning_spec.rb +12 -8
  214. data/spec/reek/source/source_code_spec.rb +17 -43
  215. data/spec/reek/source/source_locator_spec.rb +17 -17
  216. data/spec/reek/spec/should_reek_of_spec.rb +7 -11
  217. data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
  218. data/spec/reek/spec/should_reek_spec.rb +3 -3
  219. data/spec/reek/spec/smell_matcher_spec.rb +3 -3
  220. data/spec/reek/tree_dresser_spec.rb +12 -17
  221. data/spec/spec_helper.rb +6 -17
  222. data/tasks/configuration.rake +8 -5
  223. metadata +71 -41
  224. data/defaults.reek +0 -131
  225. data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
  226. data/lib/reek/report/formatter/heading_formatter.rb +0 -52
  227. data/lib/reek/report/formatter/location_formatter.rb +0 -42
  228. data/lib/reek/report/formatter/progress_formatter.rb +0 -81
  229. data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
  230. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -36
  231. data/lib/reek/report/formatter.rb +0 -33
  232. data/lib/reek/smell_detectors/syntax.rb +0 -37
  233. data/samples/configuration/non_public_modifiers_mask.reek +0 -3
  234. data/samples/smelly_with_inline_mask.rb +0 -8
  235. data/samples/smelly_with_modifiers.rb +0 -12
  236. data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
  237. data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
  238. data/spec/reek/smell_detectors/syntax_spec.rb +0 -17
  239. /data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
  240. /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
  241. /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
  242. /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
  243. /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
  244. /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
  245. /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
  246. /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
  247. /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
  248. /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
data/reek.gemspec CHANGED
@@ -5,7 +5,6 @@ Gem::Specification.new do |s|
5
5
  s.version = Reek::Version::STRING
6
6
 
7
7
  s.authors = ['Kevin Rutherford', 'Timo Roessner', 'Matijs van Zuijlen', 'Piotr Szotkowski']
8
- s.default_executable = 'reek'
9
8
  s.description =
10
9
  'Reek is a tool that examines Ruby classes, modules and methods and reports ' \
11
10
  'any code smells it finds.'
@@ -15,12 +14,13 @@ Gem::Specification.new do |s|
15
14
  s.extra_rdoc_files = ['CHANGELOG.md', 'License.txt']
16
15
  s.files = `git ls-files -z`.split("\0")
17
16
  s.executables = s.files.grep(%r{^bin/}).map { |path| File.basename(path) }
18
- s.homepage = 'https://github.com/troessner/reek/wiki'
17
+ s.homepage = 'https://github.com/troessner/reek'
19
18
  s.rdoc_options = %w(--main README.md -x assets/|bin/|config/|features/|spec/|tasks/)
20
- s.required_ruby_version = '>= 2.1.0'
19
+ s.required_ruby_version = '>= 2.3.0'
21
20
  s.summary = 'Code smell detector for Ruby'
22
21
 
23
22
  s.add_runtime_dependency 'codeclimate-engine-rb', '~> 0.4.0'
24
- s.add_runtime_dependency 'parser', '< 2.5', '>= 2.4.0.0'
25
- s.add_runtime_dependency 'rainbow', '~> 2.0'
23
+ s.add_runtime_dependency 'kwalify', '~> 0.7.0'
24
+ s.add_runtime_dependency 'parser', '< 2.6', '>= 2.5.0.0'
25
+ s.add_runtime_dependency 'rainbow', '>= 2.0', '< 4.0'
26
26
  end
@@ -1,6 +1,6 @@
1
1
  <?xml version='1.0'?>
2
2
  <checkstyle>
3
- <file name='samples/smelly.rb'>
3
+ <file name='samples/smelly_source/smelly.rb'>
4
4
  <error column='0' line='4' message='has the name &apos;x&apos;' severity='warning' source='UncommunicativeMethodName'/>
5
5
  <error column='0' line='5' message='has the variable name &apos;y&apos;' severity='warning' source='UncommunicativeVariableName'/>
6
6
  </file>
@@ -0,0 +1,29 @@
1
+ ---
2
+ detectors:
3
+ UnusedPrivateMethod:
4
+ exclude:
5
+ - "/exclude regexp/"
6
+ UncommunicativeMethodName:
7
+ reject:
8
+ - "reject name"
9
+ accept:
10
+ - "accept name"
11
+ UncommunicativeModuleName:
12
+ reject:
13
+ - "reject name 1"
14
+ - "reject name 2"
15
+ accept:
16
+ - "accept name 1"
17
+ - "accept name 2"
18
+ UncommunicativeParameterName:
19
+ reject:
20
+ - "reject name"
21
+ - "/reject regexp/"
22
+ accept:
23
+ - "accept name"
24
+ - "/accept regexp/"
25
+ UncommunicativeVariableName:
26
+ reject:
27
+ - "/^reject regexp$/"
28
+ accept:
29
+ - "/accept(.*)regexp/"
@@ -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
+
@@ -3,18 +3,7 @@ require_relative '../../lib/reek/smell_detectors/base_detector'
3
3
  require_relative '../../lib/reek/smell_warning'
4
4
  require_relative '../../lib/reek/cli/options'
5
5
 
6
- FactoryGirl.define do
7
- factory :method_context, class: Reek::Context::MethodContext do
8
- skip_create
9
- transient do
10
- source 'def foo; end'
11
- end
12
-
13
- initialize_with do
14
- new(nil, Reek::Source::SourceCode.from(source).syntax_tree)
15
- end
16
- end
17
-
6
+ FactoryBot.define do
18
7
  factory :smell_detector, class: Reek::SmellDetectors::BaseDetector do
19
8
  skip_create
20
9
  transient do
@@ -33,7 +22,7 @@ FactoryGirl.define do
33
22
  source 'dummy_file'
34
23
  lines [42]
35
24
  message 'smell warning message'
36
- parameters { {} }
25
+ parameters({})
37
26
 
38
27
  initialize_with do
39
28
  new(smell_detector,
@@ -2,6 +2,92 @@ require_relative '../../spec_helper'
2
2
  require_lib 'reek/ast/node'
3
3
 
4
4
  RSpec.describe Reek::AST::Node do
5
+ describe '#each_node' do
6
+ context 'with an empty module' do
7
+ let(:ast) do
8
+ src = 'module Emptiness; end'
9
+ Reek::Source::SourceCode.from(src).syntax_tree
10
+ end
11
+
12
+ it 'yields no calls' do
13
+ ast.each_node(:send, []) { |exp| raise "#{exp} yielded by empty module!" }
14
+ end
15
+
16
+ it 'yields one module' do
17
+ mods = 0
18
+ ast.each_node(:module, []) { |_exp| mods += 1 }
19
+ expect(mods).to eq(1)
20
+ end
21
+
22
+ it "yields the module's full AST" do
23
+ ast.each_node(:module, []) do |exp|
24
+ expect(exp).to eq(sexp(:module, sexp(:const, nil, :Emptiness), nil))
25
+ end
26
+ end
27
+
28
+ it 'returns an enumerator when no block is passed' do
29
+ expect(ast.each_node(:if)).to be_instance_of Enumerator
30
+ end
31
+ end
32
+
33
+ context 'with a nested element' do
34
+ let(:ast) do
35
+ src = "module Loneliness; def calloo; puts('hello') end; end"
36
+ Reek::Source::SourceCode.from(src).syntax_tree
37
+ end
38
+
39
+ it 'yields no ifs' do
40
+ ast.each_node(:if) { |exp| raise "#{exp} yielded by empty module!" }
41
+ end
42
+
43
+ it 'yields one module' do
44
+ expect(ast.each_node(:module).to_a.length).to eq(1)
45
+ end
46
+
47
+ it "yields the module's full AST" do
48
+ ast.each_node(:module) do |exp|
49
+ expect(exp).to eq sexp(:module,
50
+ sexp(:const, nil, :Loneliness),
51
+ sexp(:def, :calloo,
52
+ sexp(:args),
53
+ sexp(:send, nil, :puts, sexp(:str, 'hello'))))
54
+ end
55
+ end
56
+
57
+ it 'yields one method' do
58
+ expect(ast.each_node(:def).to_a.length).to eq(1)
59
+ end
60
+
61
+ it "yields the method's full AST" do
62
+ ast.each_node(:def, []) { |exp| expect(exp.children.first).to eq(:calloo) }
63
+ end
64
+
65
+ it 'ignores the call inside the method if the traversal is pruned' do
66
+ expect(ast.each_node(:send, [:def]).to_a).to be_empty
67
+ end
68
+ end
69
+
70
+ it 'finds 3 ifs in a class' do
71
+ src = <<-EOS
72
+ class Scrunch
73
+ def first
74
+ return @field == :sym ? 0 : 3;
75
+ end
76
+ def second
77
+ if @field == :sym
78
+ @other += " quarts"
79
+ end
80
+ end
81
+ def third
82
+ raise 'flu!' unless @field == :sym
83
+ end
84
+ end
85
+ EOS
86
+ ast = Reek::Source::SourceCode.from(src).syntax_tree
87
+ expect(ast.each_node(:if).to_a.length).to eq(3)
88
+ end
89
+ end
90
+
5
91
  describe '#format_to_ruby' do
6
92
  it 'returns #to_s if location is not present' do
7
93
  ast = sexp(:self)
@@ -56,7 +142,7 @@ RSpec.describe Reek::AST::Node do
56
142
  end
57
143
  end
58
144
 
59
- context 'hash' do
145
+ describe '#hash' do
60
146
  it 'hashes equal for equal sexps' do
61
147
  node1 = sexp(:def, :jim, sexp(:args), sexp(:send, sexp(:int, 4), :+, sexp(:send, nil, :fred)))
62
148
  node2 = sexp(:def, :jim, sexp(:args), sexp(:send, sexp(:int, 4), :+, sexp(:send, nil, :fred)))
@@ -77,8 +163,8 @@ RSpec.describe Reek::AST::Node do
77
163
  end
78
164
 
79
165
  describe '#line' do
80
- context 'source from file' do
81
- let(:file) { SAMPLES_PATH.join('smelly.rb') }
166
+ context 'with source from a file' do
167
+ let(:file) { SMELLY_FILE }
82
168
  let(:ast) { Reek::Source::SourceCode.from(file).syntax_tree }
83
169
 
84
170
  it 'returns the right line number' do
@@ -86,8 +172,8 @@ RSpec.describe Reek::AST::Node do
86
172
  end
87
173
  end
88
174
 
89
- context 'source from string' do
90
- let(:source) { File.read(SAMPLES_PATH.join('smelly.rb')) }
175
+ context 'with source from a string' do
176
+ let(:source) { File.read(SMELLY_FILE) }
91
177
  let(:ast) { Reek::Source::SourceCode.from(source).syntax_tree }
92
178
 
93
179
  it 'returns the right line number' do
@@ -97,17 +183,17 @@ RSpec.describe Reek::AST::Node do
97
183
  end
98
184
 
99
185
  describe '#source' do
100
- context 'source from file' do
101
- let(:file) { SAMPLES_PATH.join('smelly.rb') }
186
+ context 'with source from a file' do
187
+ let(:file) { SMELLY_FILE }
102
188
  let(:ast) { Reek::Source::SourceCode.from(file).syntax_tree }
103
189
 
104
190
  it 'returns the file name' do
105
- expect(ast.source).to eq(SAMPLES_PATH.join('smelly.rb').to_s)
191
+ expect(ast.source).to eq(SMELLY_FILE.to_s)
106
192
  end
107
193
  end
108
194
 
109
- context 'source from string' do
110
- let(:source) { File.read(SAMPLES_PATH.join('smelly.rb')) }
195
+ context 'with source from a string' do
196
+ let(:source) { File.read SMELLY_FILE }
111
197
  let(:ast) { Reek::Source::SourceCode.from(source).syntax_tree }
112
198
 
113
199
  it 'returns "string"' do
@@ -115,4 +201,11 @@ RSpec.describe Reek::AST::Node do
115
201
  end
116
202
  end
117
203
  end
204
+
205
+ describe '#name' do
206
+ it 'returns #to_s if no override is present' do
207
+ ast = sexp(:foo)
208
+ expect(ast.name).to eq ast.to_s
209
+ end
210
+ end
118
211
  end
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
2
2
  require_lib 'reek/ast/reference_collector'
3
3
 
4
4
  RSpec.describe Reek::AST::ReferenceCollector do
5
- context 'counting refs to self' do
5
+ describe '#num_refs_to_self' do
6
6
  def refs_to_self(src)
7
7
  syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
8
8
  described_class.new(syntax_tree).num_refs_to_self
@@ -107,7 +107,7 @@ RSpec.describe Reek::AST::SexpExtensions::DefNode do
107
107
  end
108
108
 
109
109
  it 'finds nodes in the body with #body_nodes' do
110
- expect(node.body_nodes([:first])).to eq [sexp(:first)]
110
+ expect(node.body_nodes([:first]).to_a).to eq [sexp(:first)]
111
111
  end
112
112
  end
113
113
 
@@ -374,7 +374,7 @@ end
374
374
  RSpec.describe Reek::AST::SexpExtensions::LambdaNode do
375
375
  let(:node) { sexp(:lambda) }
376
376
 
377
- context '#name' do
377
+ describe '#name' do
378
378
  it 'returns :lambda' do
379
379
  expect(node.name).to eq 'lambda'
380
380
  end
@@ -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
 
@@ -32,57 +32,69 @@ RSpec.describe Reek::CLI::Application do
32
32
  expect(app.execute).to eq 'foo'
33
33
  end
34
34
 
35
- context 'when no source files given' do
36
- context 'and input was piped' do
37
- before do
38
- allow_any_instance_of(IO).to receive(:tty?).and_return(false)
39
- 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
40
39
 
41
- it 'uses source form pipe' do
42
- app.execute
43
- expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
44
- with(sources: [$stdin],
45
- configuration: Reek::Configuration::AppConfiguration,
46
- options: Reek::CLI::Options)
47
- 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)
48
47
  end
49
48
 
50
- context 'and input was not piped' do
51
- before do
52
- allow_any_instance_of(IO).to receive(:tty?).and_return(true)
53
- end
49
+ context 'when a stdin filename is provided' do
50
+ let(:app) { described_class.new ['--stdin-filename', 'foo.rb'] }
54
51
 
55
- it 'uses working directory as source' do
56
- 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'))
57
54
  app.execute
58
55
  expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
59
56
  with(sources: expected_sources,
60
57
  configuration: Reek::Configuration::AppConfiguration,
61
58
  options: Reek::CLI::Options)
62
59
  end
60
+ end
61
+ end
63
62
 
64
- context 'when source files are excluded through configuration' do
65
- 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
66
67
 
67
- before do
68
- allow(Reek::Configuration::AppConfiguration).
69
- to receive(:from_path).
70
- with(Pathname.new('some_file.reek')).
71
- and_return configuration
72
- 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
73
76
 
74
- it 'uses configuration for excluded paths' do
75
- expected_sources = Reek::Source::SourceLocator.
76
- new(['.'], configuration: configuration).sources
77
- 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'] }
78
79
 
79
- 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
80
86
 
81
- expect(Reek::CLI::Command::ReportCommand).to have_received(:new).
82
- with(sources: expected_sources,
83
- configuration: configuration,
84
- options: Reek::CLI::Options)
85
- 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)
86
98
  end
87
99
  end
88
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