reek 2.0.4 → 3.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 (275) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +13 -0
  3. data/.rubocop.yml +47 -0
  4. data/.travis.yml +31 -0
  5. data/.yardopts +3 -6
  6. data/CHANGELOG +24 -0
  7. data/CONTRIBUTING.md +111 -0
  8. data/Gemfile +16 -0
  9. data/README.md +112 -59
  10. data/bin/reek +2 -2
  11. data/config/cucumber.yml +3 -0
  12. data/config/defaults.reek +0 -1
  13. data/docs/API.md +79 -0
  14. data/docs/Attribute.md +43 -0
  15. data/docs/Basic-Smell-Options.md +44 -0
  16. data/docs/Boolean-Parameter.md +52 -0
  17. data/docs/Class-Variable.md +40 -0
  18. data/docs/Code-Smells.md +34 -0
  19. data/docs/Command-Line-Options.md +84 -0
  20. data/docs/Configuration-Files.md +49 -0
  21. data/docs/Control-Couple.md +22 -0
  22. data/docs/Control-Parameter.md +29 -0
  23. data/docs/Data-Clump.md +44 -0
  24. data/docs/Duplicate-Method-Call.md +49 -0
  25. data/docs/Feature-Envy.md +49 -0
  26. data/docs/How-reek-works-internally.md +114 -0
  27. data/docs/Irresponsible-Module.md +39 -0
  28. data/docs/Large-Class.md +20 -0
  29. data/docs/Long-Parameter-List.md +38 -0
  30. data/docs/Long-Yield-List.md +36 -0
  31. data/docs/Module-Initialize.md +62 -0
  32. data/docs/Nested-Iterators.md +38 -0
  33. data/docs/Nil-Check.md +39 -0
  34. data/docs/Prima-Donna-Method.md +53 -0
  35. data/docs/RSpec-matchers.md +137 -0
  36. data/docs/Rake-Task.md +58 -0
  37. data/docs/Reek-Driven-Development.md +37 -0
  38. data/docs/Repeated-Conditional.md +44 -0
  39. data/docs/Simulated-Polymorphism.md +16 -0
  40. data/docs/Smell-Suppression.md +32 -0
  41. data/docs/Too-Many-Instance-Variables.md +43 -0
  42. data/docs/Too-Many-Methods.md +55 -0
  43. data/docs/Too-Many-Statements.md +50 -0
  44. data/docs/Uncommunicative-Method-Name.md +24 -0
  45. data/docs/Uncommunicative-Module-Name.md +23 -0
  46. data/docs/Uncommunicative-Name.md +16 -0
  47. data/docs/Uncommunicative-Parameter-Name.md +24 -0
  48. data/docs/Uncommunicative-Variable-Name.md +24 -0
  49. data/docs/Unused-Parameters.md +27 -0
  50. data/docs/Utility-Function.md +44 -0
  51. data/docs/Versioning-Policy.md +7 -0
  52. data/docs/YAML-Reports.md +111 -0
  53. data/docs/yard_plugin.rb +14 -0
  54. data/features/{ruby_api/api.feature → command_line_interface/basic_usage.feature} +6 -5
  55. data/features/command_line_interface/options.feature +1 -0
  56. data/features/command_line_interface/smell_selection.feature +4 -8
  57. data/features/command_line_interface/smells_count.feature +25 -32
  58. data/features/command_line_interface/stdin.feature +2 -2
  59. data/features/configuration_files/masking_smells.feature +30 -41
  60. data/features/configuration_files/overrides_defaults.feature +5 -3
  61. data/features/configuration_loading.feature +26 -23
  62. data/features/programmatic_access.feature +43 -0
  63. data/features/rake_task/rake_task.feature +25 -22
  64. data/features/reports/json.feature +24 -26
  65. data/features/reports/reports.feature +77 -103
  66. data/features/reports/yaml.feature +26 -20
  67. data/features/samples.feature +26 -31
  68. data/features/step_definitions/.rubocop.yml +5 -0
  69. data/features/step_definitions/reek_steps.rb +16 -28
  70. data/features/step_definitions/sample_file_steps.rb +158 -0
  71. data/features/support/env.rb +16 -27
  72. data/lib/reek/{source → ast}/ast_node_class_map.rb +11 -12
  73. data/lib/reek/ast/node.rb +132 -0
  74. data/lib/reek/{core → ast}/object_refs.rb +2 -1
  75. data/lib/reek/ast/reference_collector.rb +32 -0
  76. data/lib/reek/{source → ast}/sexp_extensions.rb +43 -7
  77. data/lib/reek/ast/sexp_formatter.rb +31 -0
  78. data/lib/reek/cli/application.rb +5 -4
  79. data/lib/reek/cli/command.rb +2 -1
  80. data/lib/reek/cli/input.rb +6 -5
  81. data/lib/reek/cli/option_interpreter.rb +13 -9
  82. data/lib/reek/cli/options.rb +16 -8
  83. data/lib/reek/cli/reek_command.rb +4 -3
  84. data/lib/reek/cli/silencer.rb +14 -0
  85. data/lib/reek/{core → cli}/warning_collector.rb +2 -1
  86. data/lib/reek/code_comment.rb +36 -0
  87. data/lib/reek/configuration/app_configuration.rb +18 -3
  88. data/lib/reek/configuration/configuration_file_finder.rb +18 -32
  89. data/lib/reek/{core → context}/code_context.rb +8 -6
  90. data/lib/reek/{core → context}/method_context.rb +11 -5
  91. data/lib/reek/{core → context}/module_context.rb +9 -4
  92. data/lib/reek/{core/stop_context.rb → context/root_context.rb} +4 -2
  93. data/lib/reek/{core → context}/singleton_method_context.rb +3 -6
  94. data/lib/reek/examiner.rb +32 -29
  95. data/lib/reek/report/formatter.rb +70 -0
  96. data/lib/reek/report/heading_formatter.rb +45 -0
  97. data/lib/reek/report/location_formatter.rb +35 -0
  98. data/lib/reek/report/report.rb +198 -0
  99. data/lib/reek/smells/attribute.rb +41 -11
  100. data/lib/reek/smells/boolean_parameter.rb +4 -2
  101. data/lib/reek/smells/class_variable.rb +4 -2
  102. data/lib/reek/smells/control_parameter.rb +4 -2
  103. data/lib/reek/smells/data_clump.rb +4 -3
  104. data/lib/reek/smells/duplicate_method_call.rb +15 -5
  105. data/lib/reek/smells/feature_envy.rb +8 -2
  106. data/lib/reek/smells/irresponsible_module.rb +13 -8
  107. data/lib/reek/smells/long_parameter_list.rb +6 -4
  108. data/lib/reek/smells/long_yield_list.rb +4 -2
  109. data/lib/reek/smells/module_initialize.rb +4 -2
  110. data/lib/reek/smells/nested_iterators.rb +4 -2
  111. data/lib/reek/smells/nil_check.rb +6 -3
  112. data/lib/reek/smells/prima_donna_method.rb +21 -12
  113. data/lib/reek/smells/repeated_conditional.rb +7 -4
  114. data/lib/reek/{core → smells}/smell_configuration.rb +3 -1
  115. data/lib/reek/smells/smell_detector.rb +11 -5
  116. data/lib/reek/{core → smells}/smell_repository.rb +9 -5
  117. data/lib/reek/smells/smell_warning.rb +101 -0
  118. data/lib/reek/smells/too_many_instance_variables.rb +4 -2
  119. data/lib/reek/smells/too_many_methods.rb +4 -2
  120. data/lib/reek/smells/too_many_statements.rb +4 -2
  121. data/lib/reek/smells/uncommunicative_method_name.rb +4 -2
  122. data/lib/reek/smells/uncommunicative_module_name.rb +4 -2
  123. data/lib/reek/smells/uncommunicative_parameter_name.rb +4 -2
  124. data/lib/reek/smells/uncommunicative_variable_name.rb +4 -2
  125. data/lib/reek/smells/unused_parameters.rb +4 -2
  126. data/lib/reek/smells/utility_function.rb +11 -22
  127. data/lib/reek/smells.rb +24 -11
  128. data/lib/reek/source/source_code.rb +69 -12
  129. data/lib/reek/source/source_locator.rb +34 -19
  130. data/lib/reek/spec/should_reek.rb +4 -3
  131. data/lib/reek/spec/should_reek_of.rb +2 -1
  132. data/lib/reek/spec/should_reek_only_of.rb +4 -3
  133. data/lib/reek/spec.rb +3 -3
  134. data/lib/reek/tree_dresser.rb +32 -0
  135. data/lib/reek/tree_walker.rb +182 -0
  136. data/lib/reek/version.rb +1 -1
  137. data/lib/reek.rb +3 -3
  138. data/reek.gemspec +18 -25
  139. data/spec/factories/factories.rb +4 -2
  140. data/spec/gem/updates_spec.rb +1 -1
  141. data/spec/gem/yard_spec.rb +2 -2
  142. data/spec/quality/reek_source_spec.rb +3 -3
  143. data/spec/reek/{source/sexp_node_spec.rb → ast/node_spec.rb} +4 -6
  144. data/spec/reek/{core → ast}/object_refs_spec.rb +4 -6
  145. data/spec/reek/{source → ast}/reference_collector_spec.rb +27 -19
  146. data/spec/reek/{source → ast}/sexp_extensions_spec.rb +7 -19
  147. data/spec/reek/{source → ast}/sexp_formatter_spec.rb +13 -8
  148. data/spec/reek/cli/option_interpreter_spec.rb +15 -0
  149. data/spec/reek/cli/options_spec.rb +19 -0
  150. data/spec/reek/cli/warning_collector_spec.rb +28 -0
  151. data/spec/reek/{source/code_comment_spec.rb → code_comment_spec.rb} +19 -17
  152. data/spec/reek/configuration/app_configuration_spec.rb +37 -26
  153. data/spec/reek/configuration/configuration_file_finder_spec.rb +67 -21
  154. data/spec/reek/{core → context}/code_context_spec.rb +18 -21
  155. data/spec/reek/{core → context}/method_context_spec.rb +33 -27
  156. data/spec/reek/{core → context}/module_context_spec.rb +5 -7
  157. data/spec/reek/context/root_context_spec.rb +14 -0
  158. data/spec/reek/context/singleton_method_context_spec.rb +17 -0
  159. data/spec/reek/examiner_spec.rb +9 -50
  160. data/spec/reek/{cli → report}/html_report_spec.rb +6 -9
  161. data/spec/reek/report/json_report_spec.rb +20 -0
  162. data/spec/reek/{cli → report}/text_report_spec.rb +16 -19
  163. data/spec/reek/report/xml_report_spec.rb +34 -0
  164. data/spec/reek/report/yaml_report_spec.rb +20 -0
  165. data/spec/reek/smells/attribute_spec.rb +93 -88
  166. data/spec/reek/smells/behaves_like_variable_detector.rb +1 -1
  167. data/spec/reek/smells/boolean_parameter_spec.rb +31 -5
  168. data/spec/reek/smells/class_variable_spec.rb +10 -10
  169. data/spec/reek/smells/control_parameter_spec.rb +5 -5
  170. data/spec/reek/smells/data_clump_spec.rb +6 -6
  171. data/spec/reek/smells/duplicate_method_call_spec.rb +7 -7
  172. data/spec/reek/smells/feature_envy_spec.rb +12 -13
  173. data/spec/reek/smells/irresponsible_module_spec.rb +28 -32
  174. data/spec/reek/smells/long_parameter_list_spec.rb +7 -7
  175. data/spec/reek/smells/long_yield_list_spec.rb +6 -6
  176. data/spec/reek/smells/module_initialize_spec.rb +4 -4
  177. data/spec/reek/smells/nested_iterators_spec.rb +6 -6
  178. data/spec/reek/smells/nil_check_spec.rb +6 -6
  179. data/spec/reek/smells/prima_donna_method_spec.rb +8 -5
  180. data/spec/reek/smells/repeated_conditional_spec.rb +18 -17
  181. data/spec/reek/{core → smells}/smell_configuration_spec.rb +5 -7
  182. data/spec/reek/smells/smell_detector_shared.rb +6 -7
  183. data/spec/reek/smells/smell_repository_spec.rb +29 -0
  184. data/spec/reek/{smell_warning_spec.rb → smells/smell_warning_spec.rb} +7 -9
  185. data/spec/reek/smells/too_many_instance_variables_spec.rb +5 -5
  186. data/spec/reek/smells/too_many_methods_spec.rb +12 -8
  187. data/spec/reek/smells/too_many_statements_spec.rb +10 -9
  188. data/spec/reek/smells/uncommunicative_method_name_spec.rb +5 -5
  189. data/spec/reek/smells/uncommunicative_module_name_spec.rb +8 -8
  190. data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +18 -6
  191. data/spec/reek/smells/uncommunicative_variable_name_spec.rb +10 -7
  192. data/spec/reek/smells/unused_parameters_spec.rb +4 -4
  193. data/spec/reek/smells/utility_function_spec.rb +65 -39
  194. data/spec/reek/source/source_code_spec.rb +10 -10
  195. data/spec/reek/source/source_locator_spec.rb +30 -0
  196. data/spec/reek/spec/should_reek_of_spec.rb +9 -25
  197. data/spec/reek/spec/should_reek_only_of_spec.rb +4 -7
  198. data/spec/reek/spec/should_reek_spec.rb +4 -32
  199. data/spec/reek/tree_dresser_spec.rb +16 -0
  200. data/spec/reek/{core/tree_walker_spec.rb → tree_walker_spec.rb} +5 -7
  201. data/spec/samples/checkstyle.xml +2 -0
  202. data/spec/samples/configuration/with_excluded_paths.reek +4 -0
  203. data/spec/samples/{overrides/masked/lower.reek → masked_by_dotfile/.reek} +3 -1
  204. data/spec/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +5 -0
  205. data/spec/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +2 -0
  206. data/spec/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +6 -0
  207. data/spec/samples/{ruby20_syntax.rb → unusual_syntax.rb} +8 -0
  208. data/spec/spec_helper.rb +21 -10
  209. data/tasks/develop.rake +2 -2
  210. data/tasks/reek.rake +1 -1
  211. metadata +158 -141
  212. data/features/support/hooks.rb +0 -15
  213. data/lib/reek/cli/report/formatter.rb +0 -69
  214. data/lib/reek/cli/report/heading_formatter.rb +0 -45
  215. data/lib/reek/cli/report/location_formatter.rb +0 -34
  216. data/lib/reek/cli/report/report.rb +0 -131
  217. data/lib/reek/core/tree_walker.rb +0 -180
  218. data/lib/reek/smell_warning.rb +0 -87
  219. data/lib/reek/source/ast_node.rb +0 -38
  220. data/lib/reek/source/code_comment.rb +0 -37
  221. data/lib/reek/source/core_extras.rb +0 -46
  222. data/lib/reek/source/reference_collector.rb +0 -27
  223. data/lib/reek/source/sexp_formatter.rb +0 -22
  224. data/lib/reek/source/sexp_node.rb +0 -79
  225. data/lib/reek/source/source_file.rb +0 -16
  226. data/lib/reek/source/source_repository.rb +0 -45
  227. data/lib/reek/source/tree_dresser.rb +0 -24
  228. data/lib/reek/source.rb +0 -16
  229. data/spec/reek/cli/json_report_spec.rb +0 -20
  230. data/spec/reek/cli/option_interperter_spec.rb +0 -14
  231. data/spec/reek/cli/yaml_report_spec.rb +0 -23
  232. data/spec/reek/core/singleton_method_context_spec.rb +0 -9
  233. data/spec/reek/core/smell_repository_spec.rb +0 -17
  234. data/spec/reek/core/stop_context_spec.rb +0 -17
  235. data/spec/reek/core/warning_collector_spec.rb +0 -30
  236. data/spec/reek/source/object_source_spec.rb +0 -20
  237. data/spec/reek/source/tree_dresser_spec.rb +0 -18
  238. data/spec/samples/config/allow_duplication.reek +0 -3
  239. data/spec/samples/config/deeper_nested_iterators.reek +0 -3
  240. data/spec/samples/configuration_loading/minimal_dirty.rb +0 -4
  241. data/spec/samples/configuration_loading/reek-test-run-disable_smells.reek +0 -7
  242. data/spec/samples/configuration_loading/reek-test-run-enable_smells.reek +0 -7
  243. data/spec/samples/corrupt_config_file/corrupt.reek +0 -1
  244. data/spec/samples/corrupt_config_file/dirty.rb +0 -8
  245. data/spec/samples/demo/demo.rb +0 -8
  246. data/spec/samples/empty_config_file/dirty.rb +0 -8
  247. data/spec/samples/empty_config_file/empty.reek +0 -0
  248. data/spec/samples/inline_config/dirty.rb +0 -16
  249. data/spec/samples/inline_config/masked.reek +0 -7
  250. data/spec/samples/mask_some/dirty.rb +0 -8
  251. data/spec/samples/mask_some/some.reek +0 -8
  252. data/spec/samples/masked/dirty.rb +0 -8
  253. data/spec/samples/masked/masked.reek +0 -5
  254. data/spec/samples/minimal_smelly_and_masked/config.reek +0 -7
  255. data/spec/samples/minimal_smelly_and_masked/minimal_dirty.rb +0 -4
  256. data/spec/samples/mixed_results/clean_one.rb +0 -7
  257. data/spec/samples/mixed_results/clean_three.rb +0 -7
  258. data/spec/samples/mixed_results/clean_two.rb +0 -7
  259. data/spec/samples/mixed_results/dirty_one.rb +0 -8
  260. data/spec/samples/mixed_results/dirty_two.rb +0 -8
  261. data/spec/samples/not_quite_masked/dirty.rb +0 -8
  262. data/spec/samples/not_quite_masked/masked.reek +0 -5
  263. data/spec/samples/not_quite_masked/smelly.rb +0 -3
  264. data/spec/samples/one_smelly_file/dirty.rb +0 -3
  265. data/spec/samples/overrides/masked/dirty.rb +0 -8
  266. data/spec/samples/overrides/upper.reek +0 -5
  267. data/spec/samples/overrides_defaults/camel_case.rb +0 -14
  268. data/spec/samples/overrides_defaults/config.reek +0 -6
  269. data/spec/samples/ruby21_syntax.rb +0 -5
  270. data/spec/samples/standard_smelly/dirty.rb +0 -8
  271. data/spec/samples/standard_smelly/minimal_dirty.rb +0 -4
  272. data/spec/samples/three_smelly_files/dirty_one.rb +0 -3
  273. data/spec/samples/three_smelly_files/dirty_three.rb +0 -5
  274. data/spec/samples/three_smelly_files/dirty_two.rb +0 -4
  275. /data/spec/samples/{simple_configuration.reek → configuration/simple_configuration.reek} +0 -0
@@ -0,0 +1,19 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ require_relative '../../../lib/reek/cli/options'
4
+
5
+ RSpec.describe Reek::CLI::Options do
6
+ describe '#initialize' do
7
+ it 'should enable colors when stdout is a TTY' do
8
+ allow($stdout).to receive_messages(tty?: false)
9
+ options = Reek::CLI::Options.new.parse
10
+ expect(options.colored).to be false
11
+ end
12
+
13
+ it 'should not enable colors when stdout is not a TTY' do
14
+ allow($stdout).to receive_messages(tty?: true)
15
+ options = Reek::CLI::Options.new.parse
16
+ expect(options.colored).to be true
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/cli/warning_collector'
3
+ require_relative '../../../lib/reek/smells/smell_warning'
4
+
5
+ RSpec.describe Reek::CLI::WarningCollector do
6
+ before(:each) do
7
+ @collector = described_class.new
8
+ end
9
+
10
+ context 'when empty' do
11
+ it 'reports no warnings' do
12
+ expect(@collector.warnings).to eq([])
13
+ end
14
+ end
15
+
16
+ context 'with one warning' do
17
+ before :each do
18
+ @warning = Reek::Smells::SmellWarning.new(Reek::Smells::FeatureEnvy.new(''),
19
+ context: 'fred',
20
+ lines: [1, 2, 3],
21
+ message: 'hello')
22
+ @collector.found_smell(@warning)
23
+ end
24
+ it 'reports that warning' do
25
+ expect(@collector.warnings).to eq([@warning])
26
+ end
27
+ end
28
+ end
@@ -1,12 +1,10 @@
1
- require 'spec_helper'
2
- require 'reek/source/code_comment'
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/reek/code_comment'
3
3
 
4
- include Reek::Source
5
-
6
- describe CodeComment do
4
+ RSpec.describe Reek::CodeComment do
7
5
  context 'with an empty comment' do
8
6
  before :each do
9
- @comment = CodeComment.new('')
7
+ @comment = described_class.new('')
10
8
  end
11
9
  it 'is not descriptive' do
12
10
  expect(@comment).not_to be_descriptive
@@ -18,34 +16,37 @@ describe CodeComment do
18
16
 
19
17
  context 'comment checks' do
20
18
  it 'rejects an empty comment' do
21
- expect(CodeComment.new('#')).not_to be_descriptive
19
+ expect(described_class.new('#')).not_to be_descriptive
22
20
  end
23
21
  it 'rejects a 1-word comment' do
24
- expect(CodeComment.new("# fred\n# ")).not_to be_descriptive
22
+ expect(described_class.new("# fred\n# ")).not_to be_descriptive
25
23
  end
26
24
  it 'accepts a 2-word comment' do
27
- expect(CodeComment.new('# fred here ')).to be_descriptive
25
+ expect(described_class.new('# fred here ')).to be_descriptive
28
26
  end
29
27
  it 'accepts a multi-word comment' do
30
- expect(CodeComment.new("# fred here \n# with \n # biscuits ")).to be_descriptive
28
+ comment = "# fred here \n# with \n # biscuits "
29
+ expect(described_class.new(comment)).to be_descriptive
31
30
  end
32
31
  end
33
32
 
34
33
  context 'comment config' do
35
34
  it 'parses hashed options' do
36
- config = CodeComment.new('# :reek:Duplication: { enabled: false }').config
35
+ comment = '# :reek:Duplication: { enabled: false }'
36
+ config = described_class.new(comment).config
37
37
  expect(config).to include('Duplication')
38
38
  expect(config['Duplication']).to include('enabled')
39
39
  expect(config['Duplication']['enabled']).to be_falsey
40
40
  end
41
41
  it 'parses hashed options with ruby names' do
42
- config = CodeComment.new('# :reek:nested_iterators: { enabled: true }').config
42
+ comment = '# :reek:nested_iterators: { enabled: true }'
43
+ config = described_class.new(comment).config
43
44
  expect(config).to include('NestedIterators')
44
45
  expect(config['NestedIterators']).to include('enabled')
45
46
  expect(config['NestedIterators']['enabled']).to be_truthy
46
47
  end
47
48
  it 'parses multiple hashed options' do
48
- config = CodeComment.new('
49
+ config = described_class.new('
49
50
  # :reek:Duplication: { enabled: false }
50
51
  :reek:nested_iterators: { enabled: true }
51
52
  ').config
@@ -56,7 +57,7 @@ describe CodeComment do
56
57
  expect(config['NestedIterators']['enabled']).to be_truthy
57
58
  end
58
59
  it 'parses multiple hashed options on the same line' do
59
- config = CodeComment.new('
60
+ config = described_class.new('
60
61
  #:reek:Duplication: { enabled: false } and :reek:nested_iterators: { enabled: true }
61
62
  ').config
62
63
  expect(config).to include('Duplication', 'NestedIterators')
@@ -66,7 +67,8 @@ describe CodeComment do
66
67
  expect(config['NestedIterators']['enabled']).to be_truthy
67
68
  end
68
69
  it 'parses multiple unhashed options on the same line' do
69
- config = CodeComment.new('# :reek:Duplication and :reek:nested_iterators').config
70
+ comment = '# :reek:Duplication and :reek:nested_iterators'
71
+ config = described_class.new(comment).config
70
72
  expect(config).to include('Duplication', 'NestedIterators')
71
73
  expect(config['Duplication']).to include('enabled')
72
74
  expect(config['Duplication']['enabled']).to be_falsey
@@ -74,13 +76,13 @@ describe CodeComment do
74
76
  expect(config['NestedIterators']['enabled']).to be_falsey
75
77
  end
76
78
  it 'disables the smell if no options are specifed' do
77
- config = CodeComment.new('# :reek:Duplication').config
79
+ config = described_class.new('# :reek:Duplication').config
78
80
  expect(config).to include('Duplication')
79
81
  expect(config['Duplication']).to include('enabled')
80
82
  expect(config['Duplication']['enabled']).to be_falsey
81
83
  end
82
84
  it 'ignores smells after a space' do
83
- config = CodeComment.new('# :reek: Duplication').config
85
+ config = described_class.new('# :reek: Duplication').config
84
86
  expect(config).not_to include('Duplication')
85
87
  end
86
88
  end
@@ -1,12 +1,9 @@
1
- require 'spec_helper'
2
- require 'reek/configuration/app_configuration'
3
- require 'reek/core/smell_repository'
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/configuration/app_configuration'
3
+ require_relative '../../../lib/reek/smells/smell_repository'
4
4
 
5
- include Reek::Configuration
6
- include Reek::Core
7
-
8
- describe AppConfiguration do
9
- let(:sample_configuration_path) { 'spec/samples/simple_configuration.reek' }
5
+ RSpec.describe Reek::Configuration::AppConfiguration do
6
+ let(:sample_configuration_path) { 'spec/samples/configuration/simple_configuration.reek' }
10
7
  let(:sample_configuration_loaded) do
11
8
  {
12
9
  'UncommunicativeVariableName' => { 'enabled' => false },
@@ -15,31 +12,32 @@ describe AppConfiguration do
15
12
  end
16
13
  let(:default_configuration) { Hash.new }
17
14
 
18
- after(:each) { AppConfiguration.reset }
15
+ after(:each) { described_class.reset }
19
16
 
20
17
  describe '.initialize_with' do
21
18
  it 'loads a configuration file if it can find one' do
22
- allow(ConfigurationFileFinder).to receive(:find).and_return sample_configuration_path
23
- expect(AppConfiguration.configuration).to eq(default_configuration)
19
+ finder = Reek::Configuration::ConfigurationFileFinder
20
+ allow(finder).to receive(:find).and_return sample_configuration_path
21
+ expect(described_class.configuration).to eq(default_configuration)
24
22
 
25
- AppConfiguration.initialize_with(nil)
26
- expect(AppConfiguration.configuration).to eq(sample_configuration_loaded)
23
+ described_class.initialize_with(nil)
24
+ expect(described_class.configuration).to eq(sample_configuration_loaded)
27
25
  end
28
26
 
29
27
  it 'leaves the default configuration untouched if it can\'t find one' do
30
- allow(ConfigurationFileFinder).to receive(:find).and_return nil
31
- expect(AppConfiguration.configuration).to eq(default_configuration)
28
+ allow(Reek::Configuration::ConfigurationFileFinder).to receive(:find).and_return nil
29
+ expect(described_class.configuration).to eq(default_configuration)
32
30
 
33
- AppConfiguration.initialize_with(nil)
34
- expect(AppConfiguration.configuration).to eq(default_configuration)
31
+ described_class.initialize_with(nil)
32
+ expect(described_class.configuration).to eq(default_configuration)
35
33
  end
36
34
  end
37
35
 
38
36
  describe '.configure_smell_repository' do
39
37
  it 'should configure a given smell_repository' do
40
- AppConfiguration.load_from_file(sample_configuration_path)
41
- smell_repository = SmellRepository.new('def m; end')
42
- AppConfiguration.configure_smell_repository smell_repository
38
+ described_class.load_from_file(sample_configuration_path)
39
+ smell_repository = Reek::Smells::SmellRepository.new('def m; end')
40
+ described_class.configure_smell_repository smell_repository
43
41
 
44
42
  expect(smell_repository.detectors[Reek::Smells::DataClump]).to be_enabled
45
43
  expect(smell_repository.detectors[Reek::Smells::UncommunicativeVariableName]).
@@ -48,20 +46,33 @@ describe AppConfiguration do
48
46
  end
49
47
  end
50
48
 
49
+ describe '.exclude_paths' do
50
+ let(:config_path) { 'spec/samples/configuration/with_excluded_paths.reek' }
51
+
52
+ it 'should return all paths to exclude' do
53
+ with_test_config(config_path) do
54
+ expect(described_class.exclude_paths).to eq [
55
+ 'spec/samples/source_with_exclude_paths/ignore_me',
56
+ 'spec/samples/source_with_exclude_paths/nested/ignore_me_as_well'
57
+ ]
58
+ end
59
+ end
60
+ end
61
+
51
62
  describe '.load_from_file' do
52
63
  it 'loads the configuration from given file' do
53
- AppConfiguration.load_from_file(sample_configuration_path)
54
- expect(AppConfiguration.configuration).to eq(sample_configuration_loaded)
64
+ described_class.load_from_file(sample_configuration_path)
65
+ expect(described_class.configuration).to eq(sample_configuration_loaded)
55
66
  end
56
67
  end
57
68
 
58
69
  describe '.reset' do
59
70
  it 'resets the configuration' do
60
- AppConfiguration.load_from_file(sample_configuration_path)
71
+ described_class.load_from_file(sample_configuration_path)
61
72
 
62
- expect(AppConfiguration.configuration).to eq(sample_configuration_loaded)
63
- AppConfiguration.reset
64
- expect(AppConfiguration.configuration).to eq(default_configuration)
73
+ expect(described_class.configuration).to eq(sample_configuration_loaded)
74
+ described_class.reset
75
+ expect(described_class.configuration).to eq(default_configuration)
65
76
  end
66
77
  end
67
78
  end
@@ -1,34 +1,80 @@
1
- require 'spec_helper'
2
- require 'reek/cli/application'
1
+ # encoding: UTF-8
3
2
 
4
- include Reek::Cli
5
- include Reek::Configuration
3
+ require 'fileutils'
4
+ require 'pathname'
5
+ require 'tmpdir'
6
+ require_relative '../../spec_helper'
6
7
 
7
- describe ConfigurationFileFinder do
8
+ RSpec.describe Reek::Configuration::ConfigurationFileFinder do
8
9
  describe '.find' do
9
- let(:sample_config_path) { Pathname.new('spec/samples/simple_configuration.reek') }
10
- let(:config_path_same_level) { Pathname.new('spec/samples/simple_configuration.reek') }
11
- let(:options_with_config_file) { double(config_file: sample_config_path) }
12
- let(:options_without_config_file) { double(config_file: nil) }
10
+ it 'returns the config_file if it’s set' do
11
+ config_file = double
12
+ options = double(config_file: config_file)
13
+ found = described_class.find(options: options)
14
+ expect(found).to eq(config_file)
15
+ end
16
+
17
+ it 'returns the file in current dir if config_file is nil' do
18
+ options = double(config_file: nil)
19
+ current = Pathname.new('spec/samples')
20
+ found = described_class.find(options: options, current: current)
21
+ expect(found).to eq(Pathname.new('spec/samples/exceptions.reek'))
22
+ end
23
+
24
+ it 'returns the file in current dir if options is nil' do
25
+ current = Pathname.new('spec/samples')
26
+ found = described_class.find(current: current)
27
+ expect(found).to eq(Pathname.new('spec/samples/exceptions.reek'))
28
+ end
13
29
 
14
- it 'should return the config file we passed as cli option if given' do
15
- expect(ConfigurationFileFinder.find(options_with_config_file)).to eq(sample_config_path)
30
+ it 'returns the file in a parent dir if none in current dir' do
31
+ current = Pathname.new('spec/samples/no_config_file')
32
+ found = described_class.find(current: current)
33
+ expect(found).to eq(Pathname.new('spec/samples/exceptions.reek'))
16
34
  end
17
35
 
18
- it 'should return the first configuration file it can find in the current directory' do
19
- allow(ConfigurationFileFinder).to receive(:detect_or_traverse_up).
20
- and_return config_path_same_level
36
+ it 'returns the file even if it’s just ‘.reek’' do
37
+ current = Pathname.new('spec/samples/masked_by_dotfile')
38
+ found = described_class.find(current: current)
39
+ expect(found).to eq(Pathname.new('spec/samples/masked_by_dotfile/.reek'))
40
+ end
41
+
42
+ it 'returns the file in home if traversing from the current dir fails' do
43
+ skip_if_a_config_in_tempdir
44
+ Dir.mktmpdir do |tempdir|
45
+ current = Pathname.new(tempdir)
46
+ home = Pathname.new('spec/samples')
47
+ found = described_class.find(current: current, home: home)
48
+ expect(found).to eq(Pathname.new('spec/samples/exceptions.reek'))
49
+ end
50
+ end
51
+
52
+ it 'returns nil when there are no files to find' do
53
+ skip_if_a_config_in_tempdir
54
+ Dir.mktmpdir do |tempdir|
55
+ current = Pathname.new(tempdir)
56
+ home = Pathname.new(tempdir)
57
+ found = described_class.find(current: current, home: home)
58
+ expect(found).to be_nil
59
+ end
60
+ end
21
61
 
22
- expect(ConfigurationFileFinder.find(options_without_config_file)).
23
- to eq(config_path_same_level)
62
+ it 'works with paths that need escaping' do
63
+ Dir.mktmpdir("ma\ngic d*r") do |tempdir|
64
+ config = Pathname.new("#{tempdir}/ma\ngic f*le.reek")
65
+ subdir = Pathname.new("#{tempdir}/ma\ngic subd*r")
66
+ FileUtils.touch config
67
+ FileUtils.mkdir subdir
68
+ found = described_class.find(current: subdir)
69
+ expect(found).to eq(config)
70
+ end
24
71
  end
25
72
 
26
- it 'should look in the HOME directory lastly' do
27
- allow(ConfigurationFileFinder).to receive(:configuration_by_cli).and_return nil
28
- allow(ConfigurationFileFinder).to receive(:configuration_in_file_system).and_return nil
29
- expect(ConfigurationFileFinder).to receive(:configuration_in_home_directory).once
73
+ private
30
74
 
31
- ConfigurationFileFinder.find nil
75
+ def skip_if_a_config_in_tempdir
76
+ found = described_class.find(current: Pathname.new(Dir.tmpdir))
77
+ skip "skipped: #{found} exists and would fail this test" if found
32
78
  end
33
79
  end
34
80
  end
@@ -1,11 +1,9 @@
1
- require 'spec_helper'
2
- require 'reek/core/method_context'
3
- require 'reek/core/module_context'
4
- require 'reek/core/stop_context'
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/context/method_context'
3
+ require_relative '../../../lib/reek/context/module_context'
4
+ require_relative '../../../lib/reek/context/root_context'
5
5
 
6
- include Reek::Core
7
-
8
- describe CodeContext do
6
+ RSpec.describe Reek::Context::CodeContext do
9
7
  context 'name recognition' do
10
8
  before :each do
11
9
  @exp_name = 'random_name' # SMELL: could use a String.random here
@@ -13,8 +11,7 @@ describe CodeContext do
13
11
  @exp = double('exp')
14
12
  allow(@exp).to receive(:name).and_return(@exp_name)
15
13
  allow(@exp).to receive(:full_name).and_return(@full_name)
16
- allow(@exp).to receive(:comments).and_return('')
17
- @ctx = CodeContext.new(nil, @exp)
14
+ @ctx = Reek::Context::CodeContext.new(nil, @exp)
18
15
  end
19
16
  it 'gets its short name from the exp' do
20
17
  expect(@ctx.name).to eq(@exp_name)
@@ -44,7 +41,7 @@ describe CodeContext do
44
41
  @outer_name = 'another_random sting'
45
42
  allow(outer).to receive(:full_name).at_least(:once).and_return(@outer_name)
46
43
  allow(outer).to receive(:config).and_return({})
47
- @ctx = CodeContext.new(outer, @exp)
44
+ @ctx = Reek::Context::CodeContext.new(outer, @exp)
48
45
  end
49
46
  it 'creates the correct full name' do
50
47
  expect(@ctx.full_name).to eq("#{@full_name}")
@@ -60,10 +57,10 @@ describe CodeContext do
60
57
 
61
58
  context 'generics' do
62
59
  it 'should pass unknown method calls down the stack' do
63
- stop = StopContext.new
60
+ stop = Reek::Context::RootContext.new
64
61
  def stop.bananas(arg1, arg2) arg1 + arg2 + 43 end
65
- element = ModuleContext.new(stop, s(:module, :mod, nil))
66
- element = MethodContext.new(element, s(:def, :bad, s(:args), nil))
62
+ element = Reek::Context::ModuleContext.new(stop, s(:module, :mod, nil))
63
+ element = Reek::Context::MethodContext.new(element, s(:def, :bad, s(:args), nil))
67
64
  expect(element.bananas(17, -5)).to eq(55)
68
65
  end
69
66
  end
@@ -73,8 +70,8 @@ describe CodeContext do
73
70
  before :each do
74
71
  @module_name = 'Emptiness'
75
72
  src = "module #{@module_name}; end"
76
- ast = src.to_reek_source.syntax_tree
77
- @ctx = CodeContext.new(nil, ast)
73
+ ast = Reek::Source::SourceCode.from(src).syntax_tree
74
+ @ctx = Reek::Context::CodeContext.new(nil, ast)
78
75
  end
79
76
 
80
77
  it 'yields no calls' do
@@ -105,8 +102,8 @@ describe CodeContext do
105
102
  @module_name = 'Loneliness'
106
103
  @method_name = 'calloo'
107
104
  src = "module #{@module_name}; def #{@method_name}; puts('hello') end; end"
108
- ast = src.to_reek_source.syntax_tree
109
- @ctx = CodeContext.new(nil, ast)
105
+ ast = Reek::Source::SourceCode.from(src).syntax_tree
106
+ @ctx = Reek::Context::CodeContext.new(nil, ast)
110
107
  end
111
108
  it 'yields no ifs' do
112
109
  @ctx.each_node(:if, []) { |exp| raise "#{exp} yielded by empty module!" }
@@ -157,8 +154,8 @@ class Scrunch
157
154
  end
158
155
  EOS
159
156
 
160
- ast = src.to_reek_source.syntax_tree
161
- ctx = CodeContext.new(nil, ast)
157
+ ast = Reek::Source::SourceCode.from(src).syntax_tree
158
+ ctx = Reek::Context::CodeContext.new(nil, ast)
162
159
  expect(ctx.each_node(:if, []).length).to eq(3)
163
160
  end
164
161
  end
@@ -166,12 +163,12 @@ EOS
166
163
  describe '#config_for' do
167
164
  let(:expression) { double('exp') }
168
165
  let(:outer) { nil }
169
- let(:context) { CodeContext.new(outer, expression) }
166
+ let(:context) { Reek::Context::CodeContext.new(outer, expression) }
170
167
  let(:sniffer) { double('sniffer') }
171
168
 
172
169
  before :each do
173
170
  allow(sniffer).to receive(:smell_type).and_return('DuplicateMethodCall')
174
- allow(expression).to receive(:comments).and_return(
171
+ allow(expression).to receive(:full_comment).and_return(
175
172
  ':reek:DuplicateMethodCall: { allow_calls: [ puts ] }')
176
173
  end
177
174
 
@@ -1,14 +1,12 @@
1
- require 'spec_helper'
2
- require 'reek/core/method_context'
3
- require 'reek/core/stop_context'
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/context/method_context'
3
+ require_relative '../../../lib/reek/context/root_context'
4
4
 
5
- include Reek::Core
6
-
7
- describe MethodContext, 'matching' do
5
+ RSpec.describe Reek::Context::MethodContext, 'matching' do
8
6
  before :each do
9
7
  exp = double('exp').as_null_object
10
8
  expect(exp).to receive(:full_name).at_least(:once).and_return('mod')
11
- @element = MethodContext.new(StopContext.new, exp)
9
+ @element = Reek::Context::MethodContext.new(Reek::Context::RootContext.new, exp)
12
10
  end
13
11
 
14
12
  it 'should recognise itself in a collection of names' do
@@ -22,33 +20,41 @@ describe MethodContext, 'matching' do
22
20
  end
23
21
  end
24
22
 
25
- describe MethodContext do
26
- it 'should record ivars as refs to self' do
27
- mctx = MethodContext.new(StopContext.new, s(:def, :feed, s(:args), nil))
28
- expect(mctx.envious_receivers).to eq([])
29
- mctx.record_call_to(s(:send, s(:ivar, :@cow), :feed_to))
30
- expect(mctx.envious_receivers).to eq([])
23
+ RSpec.describe Reek::Context::MethodContext do
24
+ let(:mc) do
25
+ sexp = s(:def, :foo, s(:args, s(:arg, :bar)), nil)
26
+ Reek::Context::MethodContext.new(Reek::Context::RootContext.new, sexp)
31
27
  end
32
28
 
33
- it 'should count calls to self' do
34
- mctx = MethodContext.new(StopContext.new, s(:def, :equals, s(:args), nil))
35
- mctx.refs.record_reference_to([:lvar, :other])
36
- mctx.record_call_to(s(:send, s(:self), :thing))
37
- expect(mctx.envious_receivers).to be_empty
38
- end
29
+ describe '#envious_receivers' do
30
+ it 'should ignore ivars as refs to self' do
31
+ mc.record_call_to s(:send, s(:ivar, :@cow), :feed_to)
32
+ expect(mc.envious_receivers).to be_empty
33
+ end
34
+
35
+ it 'should ignore explicit calls to self' do
36
+ mc.refs.record_reference_to [:lvar, :other]
37
+ mc.record_call_to s(:send, s(:self), :thing)
38
+ expect(mc.envious_receivers).to be_empty
39
+ end
40
+
41
+ it 'should ignore implicit calls to self' do
42
+ mc.record_call_to s(:send, s(:lvar, :text), :each, s(:arglist))
43
+ mc.record_call_to s(:send, nil, :shelve, s(:arglist))
44
+ expect(mc.envious_receivers).to be_empty
45
+ end
39
46
 
40
- it 'should recognise a call on self' do
41
- mc = MethodContext.new(StopContext.new, s(:def, :deep, s(:args), nil))
42
- mc.record_call_to(s(:send, s(:lvar, :text), :each, s(:arglist)))
43
- mc.record_call_to(s(:send, nil, :shelve, s(:arglist)))
44
- expect(mc.envious_receivers).to be_empty
47
+ it 'should record envious calls' do
48
+ mc.record_call_to s(:send, s(:lvar, :bar), :baz)
49
+ expect(mc.envious_receivers).to eq(bar: 1)
50
+ end
45
51
  end
46
52
  end
47
53
 
48
- describe MethodParameters, 'default assignments' do
54
+ RSpec.describe Reek::Context::MethodParameters, 'default assignments' do
49
55
  def assignments_from(src)
50
- exp = src.to_reek_source.syntax_tree
51
- ctx = MethodContext.new(StopContext.new, exp)
56
+ exp = Reek::Source::SourceCode.from(src).syntax_tree
57
+ ctx = Reek::Context::MethodContext.new(Reek::Context::RootContext.new, exp)
52
58
  ctx.parameters.default_assignments
53
59
  end
54
60
 
@@ -1,10 +1,8 @@
1
- require 'spec_helper'
2
- require 'reek/core/module_context'
3
- require 'reek/core/stop_context'
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/context/module_context'
3
+ require_relative '../../../lib/reek/context/root_context'
4
4
 
5
- include Reek::Core
6
-
7
- describe ModuleContext do
5
+ RSpec.describe Reek::Context::ModuleContext do
8
6
  it 'should report module name for smell in method' do
9
7
  expect('
10
8
  module Fred
@@ -21,7 +19,7 @@ module Fred
21
19
  end
22
20
  end
23
21
 
24
- describe ModuleContext do
22
+ RSpec.describe Reek::Context::ModuleContext do
25
23
  it 'should recognise global constant' do
26
24
  expect('# module for test
27
25
  module ::Global
@@ -0,0 +1,14 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/context/root_context'
3
+
4
+ RSpec.describe Reek::Context::RootContext do
5
+ before :each do
6
+ @root = Reek::Context::RootContext.new
7
+ end
8
+
9
+ context 'full_name' do
10
+ it 'reports full context' do
11
+ expect(@root.full_name).to eq('')
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/reek/context/singleton_method_context'
3
+ require_relative '../../../lib/reek/context/root_context'
4
+
5
+ RSpec.describe Reek::Context::SingletonMethodContext do
6
+ let(:smc) do
7
+ sexp = s(:def, :foo, s(:args, s(:arg, :bar)), nil)
8
+ Reek::Context::SingletonMethodContext.new(Reek::Context::RootContext.new, sexp)
9
+ end
10
+
11
+ describe '#envious_receivers' do
12
+ it 'should not record envious calls' do
13
+ smc.record_call_to s(:send, s(:lvar, :bar), :baz)
14
+ expect(smc.envious_receivers).to be_empty
15
+ end
16
+ end
17
+ end