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
@@ -6,7 +6,7 @@ RSpec.describe Reek::Configuration::DefaultDirective do
6
6
  let(:directives) { {}.extend(described_class) }
7
7
 
8
8
  it 'adds a smell configuration' do
9
- directives.add :UncommunicativeVariableName, enabled: false
9
+ directives.add(UncommunicativeVariableName: { enabled: false })
10
10
  expect(directives).to eq(Reek::SmellDetectors::UncommunicativeVariableName => { enabled: false })
11
11
  end
12
12
  end
@@ -1,4 +1,5 @@
1
1
  require_relative '../../spec_helper'
2
+ require_lib 'reek/errors/config_file_error'
2
3
  require_lib 'reek/configuration/directory_directives'
3
4
 
4
5
  RSpec.describe Reek::Configuration::DirectoryDirectives do
@@ -32,12 +33,10 @@ RSpec.describe Reek::Configuration::DirectoryDirectives do
32
33
  end
33
34
 
34
35
  context 'when one of given paths is a file' do
35
- let(:file_as_path) { SAMPLES_PATH.join('inline.rb') }
36
+ let(:file_as_path) { SAMPLES_DIR.join('smelly_source').join('inline.rb') }
36
37
 
37
38
  it 'raises an error' do
38
- Reek::CLI::Silencer.silently do
39
- expect { directives.add(file_as_path, {}) }.to raise_error(SystemExit)
40
- end
39
+ expect { directives.add(file_as_path => nil) }.to raise_error(Reek::Errors::ConfigFileError)
41
40
  end
42
41
  end
43
42
  end
@@ -1,4 +1,5 @@
1
1
  require_relative '../../spec_helper'
2
+ require_lib 'reek/errors/config_file_error'
2
3
  require_lib 'reek/configuration/excluded_paths'
3
4
 
4
5
  RSpec.describe Reek::Configuration::ExcludedPaths do
@@ -6,13 +7,12 @@ RSpec.describe Reek::Configuration::ExcludedPaths do
6
7
  let(:exclusions) { [].extend(described_class) }
7
8
 
8
9
  context 'when one of given paths is a file' do
9
- let(:file_as_path) { SAMPLES_PATH.join('inline.rb') }
10
- let(:paths) { [SAMPLES_PATH, file_as_path] }
10
+ let(:smelly_source_dir) { SAMPLES_DIR.join('smelly_source') }
11
+ let(:file_as_path) { smelly_source_dir.join('inline.rb') }
12
+ let(:paths) { [smelly_source_dir, file_as_path] }
11
13
 
12
14
  it 'raises an error if one of the given paths is a file' do
13
- Reek::CLI::Silencer.silently do
14
- expect { exclusions.add(paths) }.to raise_error(SystemExit)
15
- end
15
+ expect { exclusions.add(paths) }.to raise_error(Reek::Errors::ConfigFileError)
16
16
  end
17
17
  end
18
18
  end
@@ -0,0 +1,33 @@
1
+ require_relative '../../spec_helper'
2
+ require_lib 'reek/configuration/rake_task_converter'
3
+
4
+ RSpec.describe Reek::Configuration::RakeTaskConverter do
5
+ describe 'convert' do
6
+ let(:configuration_for_smell_detector) do
7
+ {
8
+ 'exclude' => [/Klass#foobar$/, /^Klass#omg$/],
9
+ 'reject' => [/^[a-z]$/, /[0-9]$/, /[A-Z]/],
10
+ 'accept' => [/^_$/]
11
+ }
12
+ end
13
+
14
+ let(:expected_exclude) { ['/Klass#foobar$/', '/^Klass#omg$/'] }
15
+ let(:expected_reject) { ['/^[a-z]$/', '/[0-9]$/', '/[A-Z]/'] }
16
+ let(:expected_accept) { ['/^_$/'] }
17
+
18
+ it 'converts exclude regexes to strings' do
19
+ converted_configuration = described_class.convert configuration_for_smell_detector
20
+ expect(converted_configuration['exclude']).to eq(expected_exclude)
21
+ end
22
+
23
+ it 'converts reject regexes to strings' do
24
+ converted_configuration = described_class.convert configuration_for_smell_detector
25
+ expect(converted_configuration['reject']).to eq(expected_reject)
26
+ end
27
+
28
+ it 'converts accept regexes to strings' do
29
+ converted_configuration = described_class.convert configuration_for_smell_detector
30
+ expect(converted_configuration['accept']).to eq(expected_accept)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,165 @@
1
+ require_relative '../../spec_helper'
2
+ require_lib 'reek/configuration/schema_validator'
3
+ require_lib 'reek/errors/config_file_error'
4
+
5
+ RSpec.describe Reek::Configuration::SchemaValidator do
6
+ describe 'validate' do
7
+ subject(:validator) { described_class.new configuration }
8
+
9
+ context 'when configuration is valid' do
10
+ let(:configuration) do
11
+ {
12
+ Reek::Configuration::AppConfiguration::DETECTORS_KEY => {
13
+ 'UncommunicativeVariableName' => { 'enabled' => false },
14
+ 'UncommunicativeMethodName' => { 'enabled' => false }
15
+ }
16
+ }
17
+ end
18
+
19
+ it 'returns nil' do
20
+ expect(validator.validate).to eq(nil)
21
+ end
22
+ end
23
+
24
+ context 'when detector is invalid' do
25
+ let(:configuration) do
26
+ {
27
+ Reek::Configuration::AppConfiguration::DETECTORS_KEY => {
28
+ 'DoesNotExist' => { 'enabled' => false }
29
+ }
30
+ }
31
+ end
32
+
33
+ it 'raises an error' do
34
+ message = %r{\[/detectors/DoesNotExist\] key 'DoesNotExist:' is undefined}
35
+ expect { validator.validate }.to raise_error(Reek::Errors::ConfigFileError, message)
36
+ end
37
+ end
38
+
39
+ context 'when `enabled` has a non-boolean value' do
40
+ let(:configuration) do
41
+ {
42
+ Reek::Configuration::AppConfiguration::DETECTORS_KEY => {
43
+ 'FeatureEnvy' => { 'enabled' => 'foo' }
44
+ }
45
+ }
46
+ end
47
+
48
+ it 'raises an error' do
49
+ message = %r{\[/detectors/FeatureEnvy/enabled\] 'foo': not a boolean}
50
+ expect { validator.validate }.to raise_error(Reek::Errors::ConfigFileError, message)
51
+ end
52
+ end
53
+
54
+ context 'when detector has an unknown option' do
55
+ let(:configuration) do
56
+ {
57
+ Reek::Configuration::AppConfiguration::DETECTORS_KEY => {
58
+ 'DataClump' => { 'does_not_exist' => 42 }
59
+ }
60
+ }
61
+ end
62
+
63
+ it 'raises an error' do
64
+ message = %r{\[/detectors/DataClump/does_not_exist\] key 'does_not_exist:' is undefined}
65
+ expect { validator.validate }.to raise_error(Reek::Errors::ConfigFileError, message)
66
+ end
67
+ end
68
+
69
+ context 'when `exclude`, `reject` and `accept`' do
70
+ %w(exclude reject accept).each do |attribute|
71
+ context 'when a scalar' do
72
+ let(:configuration) do
73
+ {
74
+ Reek::Configuration::AppConfiguration::DETECTORS_KEY => {
75
+ 'UncommunicativeMethodName' => { attribute => 42 }
76
+ }
77
+ }
78
+ end
79
+
80
+ it 'raises an error' do
81
+ message = %r{\[/detectors/UncommunicativeMethodName/#{attribute}\] '42': not a sequence}
82
+ expect { validator.validate }.to raise_error(Reek::Errors::ConfigFileError, message)
83
+ end
84
+ end
85
+
86
+ context 'when types are mixed' do
87
+ let(:configuration) do
88
+ {
89
+ Reek::Configuration::AppConfiguration::DETECTORS_KEY => {
90
+ 'UncommunicativeMethodName' => { attribute => [42, 'foo'] }
91
+ }
92
+ }
93
+ end
94
+
95
+ it 'raises an error' do
96
+ message = %r{\[/detectors/UncommunicativeMethodName/#{attribute}/0\] '42': not a string}
97
+ expect { validator.validate }.to raise_error(Reek::Errors::ConfigFileError, message)
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ context 'when `exclude_paths` is a scalar' do
104
+ let(:configuration) do
105
+ {
106
+ Reek::Configuration::AppConfiguration::EXCLUDE_PATHS_KEY => 42
107
+ }
108
+ end
109
+
110
+ it 'raises an error' do
111
+ message = %r{\[/exclude_paths\] '42': not a sequence}
112
+ expect { validator.validate }.to raise_error(Reek::Errors::ConfigFileError, message)
113
+ end
114
+ end
115
+
116
+ context 'when `exclude_paths` mixes types' do
117
+ let(:configuration) do
118
+ {
119
+ Reek::Configuration::AppConfiguration::EXCLUDE_PATHS_KEY => [42, 'foo']
120
+ }
121
+ end
122
+
123
+ it 'raises an error' do
124
+ message = %r{\[/exclude_paths/0\] '42': not a string}
125
+ expect { validator.validate }.to raise_error(Reek::Errors::ConfigFileError, message)
126
+ end
127
+ end
128
+
129
+ context 'with directory directives' do
130
+ context 'when bad detector' do
131
+ let(:configuration) do
132
+ {
133
+ Reek::Configuration::AppConfiguration::DIRECTORIES_KEY => {
134
+ 'web_app/app/helpers' => {
135
+ 'Bar' => { 'enabled' => false }
136
+ }
137
+ }
138
+ }
139
+ end
140
+
141
+ it 'raises an error' do
142
+ message = %r{\[/directories/web_app/app/helpers/Bar\] key 'Bar:' is undefined}
143
+ expect { validator.validate }.to raise_error(Reek::Errors::ConfigFileError, message)
144
+ end
145
+ end
146
+
147
+ context 'when unknown attribute' do
148
+ let(:configuration) do
149
+ {
150
+ Reek::Configuration::AppConfiguration::DIRECTORIES_KEY => {
151
+ 'web_app/app/controllers' => {
152
+ 'NestedIterators' => { 'foo' => false }
153
+ }
154
+ }
155
+ }
156
+ end
157
+
158
+ it 'raises an error' do
159
+ message = %r{\[/directories/web_app/app/controllers/NestedIterators/foo\] key 'foo:' is undefined}
160
+ expect { validator.validate }.to raise_error(Reek::Errors::ConfigFileError, message)
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
@@ -121,7 +121,7 @@ RSpec.describe Reek::Context::CodeContext do
121
121
  describe '#config_for' do
122
122
  let(:src) do
123
123
  <<-EOS
124
- # :reek:DuplicateMethodCall: { allow_calls: [ puts ] }')
124
+ # :reek:DuplicateMethodCall { allow_calls: [ puts ] }')
125
125
  def repeated_greeting
126
126
  puts 'Hello!'
127
127
  puts 'Hello!'
@@ -46,7 +46,7 @@ RSpec.describe Reek::Examiner do
46
46
  filter_by_smells: [],
47
47
  configuration: configuration)
48
48
  end
49
- let(:path) { CONFIG_PATH.join('partial_mask.reek') }
49
+ let(:path) { CONFIGURATION_DIR.join('partial_mask.reek') }
50
50
  let(:expected_first_smell) { 'UncommunicativeVariableName' }
51
51
 
52
52
  it_behaves_like 'one smell found'
@@ -195,6 +195,33 @@ RSpec.describe Reek::Examiner do
195
195
  end
196
196
  end
197
197
 
198
+ context 'with a source that triggers a syntax error' do
199
+ let(:examiner) { described_class.new(source) }
200
+ let(:source) do
201
+ <<-SRC.strip_heredoc
202
+ 1 2 3
203
+ SRC
204
+ end
205
+
206
+ it 'does not raise an error during initialization' do
207
+ expect { examiner }.not_to raise_error
208
+ end
209
+
210
+ it 'raises an encoding error when asked for smells' do
211
+ expect { examiner.smells }.to raise_error Reek::Errors::SyntaxError
212
+ end
213
+
214
+ it 'explains the origin of the error' do
215
+ message = "Source 'string' cannot be processed by Reek due to a syntax error in the source file."
216
+ expect { examiner.smells }.to raise_error.with_message(/#{message}/)
217
+ end
218
+
219
+ it 'shows the original exception class' do
220
+ expect { examiner.smells }.
221
+ to raise_error { |it| expect(it.long_message).to match(/Parser::SyntaxError/) }
222
+ end
223
+ end
224
+
198
225
  context 'with a source that triggers an encoding error' do
199
226
  let(:examiner) { described_class.new(source) }
200
227
  let(:source) do
@@ -1,7 +1,6 @@
1
1
  require_relative '../../spec_helper'
2
2
  require_lib 'reek/examiner'
3
3
  require_lib 'reek/report/json_report'
4
- require_lib 'reek/report/formatter'
5
4
 
6
5
  require 'json'
7
6
  require 'stringio'
@@ -34,58 +33,26 @@ RSpec.describe Reek::Report::JSONReport do
34
33
  expected = JSON.parse <<-EOS
35
34
  [
36
35
  {
37
- "context": "simple",
38
- "lines": [1],
39
- "message": "has the parameter name 'a'",
40
- "smell_type": "UncommunicativeParameterName",
41
- "source": "string",
42
- "name": "a"
36
+ "context": "simple",
37
+ "lines": [1],
38
+ "message": "has the parameter name 'a'",
39
+ "smell_type": "UncommunicativeParameterName",
40
+ "source": "string",
41
+ "name": "a",
42
+ "documentation_link": "https://github.com/troessner/reek/blob/v#{Reek::Version::STRING}/docs/Uncommunicative-Parameter-Name.md"
43
43
  },
44
44
  {
45
- "context": "simple",
46
- "lines": [1],
47
- "message": "doesn't depend on instance state (maybe move it to another class?)",
48
- "smell_type": "UtilityFunction",
49
- "source": "string"
45
+ "context": "simple",
46
+ "lines": [1],
47
+ "message": "doesn't depend on instance state (maybe move it to another class?)",
48
+ "smell_type": "UtilityFunction",
49
+ "source": "string",
50
+ "documentation_link": "https://github.com/troessner/reek/blob/v#{Reek::Version::STRING}/docs/Utility-Function.md"
50
51
  }
51
52
  ]
52
53
  EOS
53
54
 
54
55
  expect(result).to eq expected
55
56
  end
56
-
57
- context 'with link formatter' do
58
- let(:options) { { warning_formatter: Reek::Report::Formatter::WikiLinkWarningFormatter.new } }
59
-
60
- it 'prints documentation links' do
61
- out = StringIO.new
62
- instance.show(out)
63
- out.rewind
64
- result = JSON.parse(out.read)
65
- expected = JSON.parse <<-EOS
66
- [
67
- {
68
- "context": "simple",
69
- "lines": [1],
70
- "message": "has the parameter name 'a'",
71
- "smell_type": "UncommunicativeParameterName",
72
- "source": "string",
73
- "name": "a",
74
- "wiki_link": "https://github.com/troessner/reek/blob/v#{Reek::Version::STRING}/docs/Uncommunicative-Parameter-Name.md"
75
- },
76
- {
77
- "context": "simple",
78
- "lines": [1],
79
- "message": "doesn't depend on instance state (maybe move it to another class?)",
80
- "smell_type": "UtilityFunction",
81
- "source": "string",
82
- "wiki_link": "https://github.com/troessner/reek/blob/v#{Reek::Version::STRING}/docs/Utility-Function.md"
83
- }
84
- ]
85
- EOS
86
-
87
- expect(result).to eq expected
88
- end
89
- end
90
57
  end
91
58
  end
@@ -1,7 +1,7 @@
1
- require_relative '../../../spec_helper'
2
- require_lib 'reek/report/formatter'
1
+ require_relative '../../spec_helper'
2
+ require_lib 'reek/report/location_formatter'
3
3
 
4
- RSpec.describe Reek::Report::Formatter::BlankLocationFormatter do
4
+ RSpec.describe Reek::Report::BlankLocationFormatter do
5
5
  let(:warning) { build(:smell_warning, lines: [11, 9, 250, 100]) }
6
6
 
7
7
  describe '.format' do
@@ -11,7 +11,7 @@ RSpec.describe Reek::Report::Formatter::BlankLocationFormatter do
11
11
  end
12
12
  end
13
13
 
14
- RSpec.describe Reek::Report::Formatter::DefaultLocationFormatter do
14
+ RSpec.describe Reek::Report::DefaultLocationFormatter do
15
15
  let(:warning) { build(:smell_warning, lines: [11, 9, 250, 100]) }
16
16
 
17
17
  describe '.format' do
@@ -21,7 +21,7 @@ RSpec.describe Reek::Report::Formatter::DefaultLocationFormatter do
21
21
  end
22
22
  end
23
23
 
24
- RSpec.describe Reek::Report::Formatter::SingleLineLocationFormatter do
24
+ RSpec.describe Reek::Report::SingleLineLocationFormatter do
25
25
  let(:warning) { build(:smell_warning, lines: [11, 9, 250, 100]) }
26
26
 
27
27
  describe '.format' do
@@ -1,7 +1,7 @@
1
- require_relative '../../../spec_helper'
2
- require_lib 'reek/report/formatter/progress_formatter'
1
+ require_relative '../../spec_helper'
2
+ require_lib 'reek/report/progress_formatter'
3
3
 
4
- RSpec.describe Reek::Report::Formatter::ProgressFormatter::Dots do
4
+ RSpec.describe Reek::Report::ProgressFormatter::Dots do
5
5
  let(:sources_count) { 23 }
6
6
  let(:formatter) { described_class.new(sources_count) }
7
7
 
@@ -37,7 +37,7 @@ RSpec.describe Reek::Report::Formatter::ProgressFormatter::Dots do
37
37
  end
38
38
  end
39
39
 
40
- RSpec.describe Reek::Report::Formatter::ProgressFormatter::Quiet do
40
+ RSpec.describe Reek::Report::ProgressFormatter::Quiet do
41
41
  let(:sources_count) { 23 }
42
42
  let(:formatter) { described_class.new(sources_count) }
43
43
 
@@ -1,15 +1,15 @@
1
1
  require_relative '../../spec_helper'
2
2
  require_lib 'reek/examiner'
3
3
  require_lib 'reek/report/text_report'
4
- require_lib 'reek/report/formatter'
4
+ require_lib 'reek/report/heading_formatter'
5
+ require_lib 'reek/report/simple_warning_formatter'
5
6
  require 'rainbow'
6
7
 
7
8
  RSpec.describe Reek::Report::TextReport do
8
9
  let(:report_options) do
9
10
  {
10
- warning_formatter: Reek::Report::Formatter::SimpleWarningFormatter.new,
11
- report_formatter: Reek::Report::Formatter,
12
- heading_formatter: Reek::Report::Formatter::QuietHeadingFormatter
11
+ warning_formatter: Reek::Report::SimpleWarningFormatter.new,
12
+ heading_formatter: Reek::Report::QuietHeadingFormatter
13
13
  }
14
14
  end
15
15
  let(:instance) { described_class.new report_options }