reek 5.0.2 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -70
  3. data/.rubocop_todo.yml +63 -0
  4. data/.simplecov +4 -1
  5. data/CHANGELOG.md +5 -0
  6. data/Gemfile +12 -17
  7. data/README.md +21 -29
  8. data/Rakefile +2 -2
  9. data/docs/templates/default/docstring/setup.rb +3 -0
  10. data/features/command_line_interface/options.feature +5 -3
  11. data/features/configuration_files/schema_validation.feature +3 -3
  12. data/features/configuration_files/show_configuration_file.feature +44 -0
  13. data/features/rake_task/rake_task.feature +1 -1
  14. data/features/reports/json.feature +3 -3
  15. data/features/reports/reports.feature +4 -4
  16. data/features/reports/yaml.feature +3 -3
  17. data/features/rspec_matcher.feature +1 -0
  18. data/features/step_definitions/sample_file_steps.rb +6 -8
  19. data/features/todo_list.feature +39 -26
  20. data/lib/reek.rb +7 -0
  21. data/lib/reek/ast/node.rb +4 -0
  22. data/lib/reek/ast/sexp_extensions/if.rb +20 -0
  23. data/lib/reek/ast/sexp_extensions/methods.rb +1 -0
  24. data/lib/reek/cli/application.rb +25 -0
  25. data/lib/reek/cli/command/todo_list_command.rb +17 -7
  26. data/lib/reek/cli/options.rb +21 -14
  27. data/lib/reek/code_comment.rb +2 -0
  28. data/lib/reek/configuration/app_configuration.rb +0 -3
  29. data/lib/reek/configuration/configuration_converter.rb +4 -4
  30. data/lib/reek/configuration/directory_directives.rb +1 -0
  31. data/lib/reek/configuration/schema_validator.rb +1 -0
  32. data/lib/reek/context/method_context.rb +1 -0
  33. data/lib/reek/context/module_context.rb +5 -4
  34. data/lib/reek/context/visibility_tracker.rb +7 -4
  35. data/lib/reek/context_builder.rb +1 -0
  36. data/lib/reek/detector_repository.rb +1 -0
  37. data/lib/reek/errors/incomprehensible_source_error.rb +2 -2
  38. data/lib/reek/errors/syntax_error.rb +4 -0
  39. data/lib/reek/examiner.rb +1 -0
  40. data/lib/reek/report/text_report.rb +1 -0
  41. data/lib/reek/smell_detectors/control_parameter.rb +13 -107
  42. data/lib/reek/smell_detectors/control_parameter_helpers/call_in_condition_finder.rb +91 -0
  43. data/lib/reek/smell_detectors/control_parameter_helpers/candidate.rb +38 -0
  44. data/lib/reek/smell_detectors/control_parameter_helpers/control_parameter_finder.rb +94 -0
  45. data/lib/reek/smell_detectors/duplicate_method_call.rb +1 -0
  46. data/lib/reek/smell_detectors/feature_envy.rb +2 -0
  47. data/lib/reek/smell_detectors/irresponsible_module.rb +1 -0
  48. data/lib/reek/smell_detectors/long_parameter_list.rb +1 -0
  49. data/lib/reek/smell_detectors/manual_dispatch.rb +1 -0
  50. data/lib/reek/smell_detectors/missing_safe_method.rb +1 -0
  51. data/lib/reek/smell_detectors/nested_iterators.rb +1 -0
  52. data/lib/reek/smell_detectors/repeated_conditional.rb +1 -0
  53. data/lib/reek/smell_detectors/too_many_instance_variables.rb +1 -0
  54. data/lib/reek/smell_detectors/too_many_methods.rb +1 -0
  55. data/lib/reek/smell_detectors/too_many_statements.rb +1 -0
  56. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +2 -0
  57. data/lib/reek/smell_detectors/unused_parameters.rb +1 -0
  58. data/lib/reek/source/source_locator.rb +1 -0
  59. data/lib/reek/spec/should_reek_of.rb +2 -2
  60. data/lib/reek/spec/should_reek_only_of.rb +1 -0
  61. data/lib/reek/spec/smell_matcher.rb +1 -0
  62. data/lib/reek/tree_dresser.rb +1 -0
  63. data/lib/reek/version.rb +1 -1
  64. data/samples/smelly_source/ruby.rb +368 -0
  65. data/spec/factories/factories.rb +10 -9
  66. data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +17 -0
  67. data/spec/quality/documentation_spec.rb +40 -0
  68. data/spec/reek/ast/sexp_extensions_spec.rb +20 -20
  69. data/spec/reek/cli/application_spec.rb +29 -0
  70. data/spec/reek/cli/command/todo_list_command_spec.rb +64 -46
  71. data/spec/reek/configuration/app_configuration_spec.rb +8 -8
  72. data/spec/reek/configuration/configuration_file_finder_spec.rb +3 -3
  73. data/spec/reek/configuration/schema_validator_spec.rb +10 -10
  74. data/spec/reek/detector_repository_spec.rb +2 -2
  75. data/spec/reek/smell_detectors/control_parameter_spec.rb +17 -0
  76. data/spec/reek/source/source_locator_spec.rb +0 -2
  77. data/spec/spec_helper.rb +2 -0
  78. data/tasks/configuration.rake +2 -1
  79. data/tasks/test.rake +4 -0
  80. metadata +11 -5
  81. data/ataru_setup.rb +0 -13
  82. data/tasks/ataru.rake +0 -5
@@ -7,7 +7,7 @@ FactoryBot.define do
7
7
  factory :smell_detector, class: Reek::SmellDetectors::BaseDetector do
8
8
  skip_create
9
9
  transient do
10
- smell_type 'FeatureEnvy'
10
+ smell_type { 'FeatureEnvy' }
11
11
  end
12
12
 
13
13
  initialize_with do
@@ -18,11 +18,12 @@ FactoryBot.define do
18
18
  factory :smell_warning, class: Reek::SmellWarning do
19
19
  skip_create
20
20
  smell_detector
21
- context 'self'
22
- source 'dummy_file'
23
- lines [42]
24
- message 'smell warning message'
25
- parameters({})
21
+ context { 'self' }
22
+
23
+ source { 'dummy_file' }
24
+ lines { [42] }
25
+ message { 'smell warning message' }
26
+ parameters { {} }
26
27
 
27
28
  initialize_with do
28
29
  new(smell_detector,
@@ -35,9 +36,9 @@ FactoryBot.define do
35
36
  end
36
37
 
37
38
  factory :code_comment, class: Reek::CodeComment do
38
- comment ''
39
- line 1
40
- source 'string'
39
+ comment { '' }
40
+ line { 1 }
41
+ source { 'string' }
41
42
  initialize_with do
42
43
  new comment: comment,
43
44
  line: line,
@@ -0,0 +1,17 @@
1
+ require_relative '../../../spec_helper'
2
+ require_lib 'reek/examiner'
3
+
4
+ RSpec.describe 'Runtime speed' do
5
+ let(:source_directory) { SAMPLES_DIR.join('smelly_source') }
6
+
7
+ it 'runs on our smelly sources in less than 5 seconds' do
8
+ expect do
9
+ source_directory.each_entry do |entry|
10
+ next if %w(. ..).include?(entry.to_s)
11
+
12
+ examiner = Reek::Examiner.new entry.to_path
13
+ examiner.smells.size
14
+ end
15
+ end.to perform_under(5).sec
16
+ end
17
+ end
@@ -0,0 +1,40 @@
1
+ require_relative '../spec_helper'
2
+ require 'kramdown'
3
+
4
+ RSpec.describe 'Documentation' do
5
+ root = File.expand_path('../..', __dir__)
6
+ files = Dir.glob(File.join(root, '*.md')) + Dir.glob(File.join(root, 'docs', '*.md'))
7
+
8
+ files.each do |file|
9
+ describe "from #{file}" do
10
+ text = File.read(file)
11
+ doc = Kramdown::Document.new(text, input: 'GFM')
12
+ blocks = doc.root.children
13
+
14
+ blocks.each do |block|
15
+ # Only consider code blocks with language 'ruby'.
16
+ next unless [:codeblock, :codespan].include?(block.type)
17
+ next unless block.attr['class'] == 'language-ruby'
18
+
19
+ it "has a valid sample at #{block.options[:location] + 1}" do
20
+ code = block.value.strip
21
+
22
+ # Replace lines of the form `<expression> # => <result>` with
23
+ # assertions.
24
+ #
25
+ # For example,
26
+ #
27
+ # 2 + 2 # => 4
28
+ #
29
+ # will be replaced by
30
+ #
31
+ # assert_equal(4, 2 + 2)
32
+ #
33
+ spec_code = code.gsub(/(^.+) # ?=> (.+$)/, 'assert_equal(\2, \1)')
34
+
35
+ eval spec_code # rubocop:disable Security/Eval
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -25,15 +25,15 @@ RSpec.describe Reek::AST::SexpExtensions::DefNode do
25
25
  context 'with 1 parameter' do
26
26
  let(:node) do
27
27
  sexp(:def, :hello,
28
- sexp(:args, sexp(:arg, :param)))
28
+ sexp(:args, sexp(:arg, :parameter)))
29
29
  end
30
30
 
31
31
  it 'has 1 arg name' do
32
- expect(node.arg_names).to eq [:param]
32
+ expect(node.arg_names).to eq [:parameter]
33
33
  end
34
34
 
35
35
  it 'has 1 parameter name' do
36
- expect(node.parameter_names).to eq [:param]
36
+ expect(node.parameter_names).to eq [:parameter]
37
37
  end
38
38
 
39
39
  it 'includes outer scope in its full name' do
@@ -49,16 +49,16 @@ RSpec.describe Reek::AST::SexpExtensions::DefNode do
49
49
  let(:node) do
50
50
  sexp(:def, :hello,
51
51
  sexp(:args,
52
- sexp(:arg, :param),
52
+ sexp(:arg, :parameter),
53
53
  sexp(:blockarg, :blk)))
54
54
  end
55
55
 
56
56
  it 'has 1 arg name' do
57
- expect(node.arg_names).to eq [:param]
57
+ expect(node.arg_names).to eq [:parameter]
58
58
  end
59
59
 
60
60
  it 'has 2 parameter names' do
61
- expect(node.parameter_names).to eq [:param, :blk]
61
+ expect(node.parameter_names).to eq [:parameter, :blk]
62
62
  end
63
63
 
64
64
  it 'includes outer scope in its full name' do
@@ -74,15 +74,15 @@ RSpec.describe Reek::AST::SexpExtensions::DefNode do
74
74
  let(:node) do
75
75
  sexp(:def, :hello,
76
76
  sexp(:args,
77
- sexp(:optarg, :param, sexp(:array))))
77
+ sexp(:optarg, :parameter, sexp(:array))))
78
78
  end
79
79
 
80
80
  it 'has 1 arg name' do
81
- expect(node.arg_names).to eq [:param]
81
+ expect(node.arg_names).to eq [:parameter]
82
82
  end
83
83
 
84
84
  it 'has 1 parameter name' do
85
- expect(node.parameter_names).to eq [:param]
85
+ expect(node.parameter_names).to eq [:parameter]
86
86
  end
87
87
 
88
88
  it 'includes outer scope in its full name' do
@@ -168,15 +168,15 @@ RSpec.describe Reek::AST::SexpExtensions::DefsNode do
168
168
  context 'with 1 parameter' do
169
169
  let(:node) do
170
170
  sexp(:defs, sexp(:lvar, :obj), :hello,
171
- sexp(:args, sexp(:arg, :param)))
171
+ sexp(:args, sexp(:arg, :parameter)))
172
172
  end
173
173
 
174
174
  it 'has 1 arg name' do
175
- expect(node.arg_names).to eq [:param]
175
+ expect(node.arg_names).to eq [:parameter]
176
176
  end
177
177
 
178
178
  it 'has 1 parameter name' do
179
- expect(node.parameter_names).to eq [:param]
179
+ expect(node.parameter_names).to eq [:parameter]
180
180
  end
181
181
 
182
182
  it 'includes outer scope in its full name' do
@@ -192,16 +192,16 @@ RSpec.describe Reek::AST::SexpExtensions::DefsNode do
192
192
  let(:node) do
193
193
  sexp(:defs, sexp(:lvar, :obj), :hello,
194
194
  sexp(:args,
195
- sexp(:arg, :param),
195
+ sexp(:arg, :parameter),
196
196
  sexp(:blockarg, :blk)))
197
197
  end
198
198
 
199
199
  it 'has 1 arg name' do
200
- expect(node.arg_names).to eq [:param]
200
+ expect(node.arg_names).to eq [:parameter]
201
201
  end
202
202
 
203
203
  it 'has 2 parameter names' do
204
- expect(node.parameter_names).to eq [:param, :blk]
204
+ expect(node.parameter_names).to eq [:parameter, :blk]
205
205
  end
206
206
 
207
207
  it 'includes outer scope in its full name' do
@@ -217,15 +217,15 @@ RSpec.describe Reek::AST::SexpExtensions::DefsNode do
217
217
  let(:node) do
218
218
  sexp(:defs, sexp(:lvar, :obj), :hello,
219
219
  sexp(:args,
220
- sexp(:optarg, :param, sexp(:array))))
220
+ sexp(:optarg, :parameter, sexp(:array))))
221
221
  end
222
222
 
223
223
  it 'has 1 arg name' do
224
- expect(node.arg_names).to eq [:param]
224
+ expect(node.arg_names).to eq [:parameter]
225
225
  end
226
226
 
227
227
  it 'has 1 parameter name' do
228
- expect(node.parameter_names).to eq [:param]
228
+ expect(node.parameter_names).to eq [:parameter]
229
229
  end
230
230
 
231
231
  it 'includes outer scope in its full name' do
@@ -355,10 +355,10 @@ RSpec.describe Reek::AST::SexpExtensions::BlockNode do
355
355
  end
356
356
 
357
357
  context 'with 1 parameter' do
358
- let(:node) { sexp(:block, sexp(:send, nil, :map), sexp(:args, :param), nil) }
358
+ let(:node) { sexp(:block, sexp(:send, nil, :map), sexp(:args, :parameter), nil) }
359
359
 
360
360
  it 'has 1 parameter name' do
361
- expect(node.parameter_names).to eq [:param]
361
+ expect(node.parameter_names).to eq [:parameter]
362
362
  end
363
363
  end
364
364
 
@@ -136,4 +136,33 @@ RSpec.describe Reek::CLI::Application do
136
136
  end
137
137
  end
138
138
  end
139
+
140
+ describe 'show configuration path' do
141
+ let(:app) { described_class.new ['--show-configuration-path', '.'] }
142
+
143
+ around do |example|
144
+ Dir.mktmpdir('/tmp') do |tmp|
145
+ Dir.chdir(tmp) do
146
+ example.run
147
+ end
148
+ end
149
+ end
150
+
151
+ context 'when not using any configuration file' do
152
+ it 'prints that we are not using any configuration file' do
153
+ expect do
154
+ app.execute
155
+ end.to output("Not using any configuration file.\n").to_stdout
156
+ end
157
+ end
158
+
159
+ context 'with a default configuration file' do
160
+ it 'prints that we are using the default configuration file' do
161
+ FileUtils.touch '.reek.yml'
162
+ expect do
163
+ app.execute
164
+ end.to output("Using '.reek.yml' as configuration file.\n").to_stdout
165
+ end
166
+ end
167
+ end
139
168
  end
@@ -4,65 +4,83 @@ require_lib 'reek/cli/options'
4
4
  require_lib 'reek/configuration/app_configuration'
5
5
 
6
6
  RSpec.describe Reek::CLI::Command::TodoListCommand do
7
- let(:nil_check) { build :smell_detector, smell_type: :NilCheck }
8
- let(:nested_iterators) { build :smell_detector, smell_type: :NestedIterators }
7
+ let(:existing_configuration) do
8
+ <<-EOS.strip_heredoc
9
+ ---
10
+ detectors:
11
+ UncommunicativeMethodName:
12
+ exclude:
13
+ - Smelly#x
14
+ EOS
15
+ end
9
16
 
10
- describe '#execute' do
11
- let(:options) { Reek::CLI::Options.new [] }
12
- let(:configuration) { instance_double 'Reek::Configuration::AppConfiguration' }
13
- let(:sources) { [source_file] }
17
+ let(:smelly_file) do
18
+ <<-EOS
19
+ # Smelly class
20
+ class Smelly
21
+ # This will reek of UncommunicativeMethodName
22
+ def x
23
+ y = 10 # This will reek of UncommunicativeVariableName
24
+ end
25
+ end
26
+ EOS
27
+ end
14
28
 
15
- let(:command) do
16
- described_class.new(options: options,
17
- sources: sources,
18
- configuration: configuration)
19
- end
29
+ let(:new_configuration_file) do
30
+ <<-EOS.strip_heredoc
31
+ # Auto generated by Reeks --todo flag
32
+ ---
33
+ detectors:
34
+ UncommunicativeMethodName:
35
+ exclude:
36
+ - Smelly#x
37
+ UncommunicativeVariableName:
38
+ exclude:
39
+ - Smelly#x
40
+ EOS
41
+ end
20
42
 
21
- before do
22
- allow(File).to receive(:write).with(described_class::FILE_NAME, String)
43
+ describe '#execute on smelly source' do
44
+ around do |example|
45
+ Dir.mktmpdir('/tmp') do |tmp|
46
+ Dir.chdir(tmp) do
47
+ File.write SMELLY_FILE.basename, smelly_file
48
+ example.run
49
+ end
50
+ end
23
51
  end
24
52
 
25
- context 'when smells are found' do
26
- let(:source_file) { SMELLY_FILE }
53
+ context 'with default configuration file' do
54
+ let(:default_configuration_file_name) { Reek::DEFAULT_CONFIGURATION_FILE_NAME }
27
55
 
28
- it 'shows a proper message' do
29
- expected = "\n'.todo.reek' generated! You can now use this as a starting point for your configuration.\n"
30
- expect { command.execute }.to output(expected).to_stdout
31
- end
56
+ context 'when does not exist yet' do
57
+ it 'creates it' do
58
+ Reek::CLI::Silencer.silently { todo_command.execute }
32
59
 
33
- it 'returns a success code' do
34
- result = Reek::CLI::Silencer.silently { command.execute }
35
- expect(result).to eq(Reek::CLI::Status::DEFAULT_SUCCESS_EXIT_CODE)
60
+ actual_content = File.read(default_configuration_file_name)
61
+ expect(actual_content).to match(new_configuration_file)
62
+ end
36
63
  end
37
64
 
38
- it 'writes a todo file with exclusions for each smell' do
39
- Reek::CLI::Silencer.silently { command.execute }
40
- expected_yaml = {
41
- Reek::Configuration::AppConfiguration::DETECTORS_KEY =>
42
- { 'UncommunicativeMethodName' => { 'exclude' => ['Smelly#x'] },
43
- 'UncommunicativeVariableName' => { 'exclude' => ['Smelly#x'] } }
44
- }.to_yaml
45
- expect(File).to have_received(:write).with(described_class::FILE_NAME, expected_yaml)
46
- end
47
- end
65
+ context 'when exists already' do
66
+ it 'does not update the configuration' do
67
+ File.write default_configuration_file_name, existing_configuration
68
+ command = todo_command
48
69
 
49
- context 'when no smells re found' do
50
- let(:source_file) { CLEAN_FILE }
51
-
52
- it 'shows a proper message' do
53
- expected = "\n'.todo.reek' not generated because there were no smells found!\n"
54
- expect { command.execute }.to output(expected).to_stdout
55
- end
70
+ Reek::CLI::Silencer.silently { command.execute }
56
71
 
57
- it 'returns a success code' do
58
- result = Reek::CLI::Silencer.silently { command.execute }
59
- expect(result).to eq Reek::CLI::Status::DEFAULT_SUCCESS_EXIT_CODE
72
+ actual_content = File.read(default_configuration_file_name)
73
+ expect(actual_content).to match(existing_configuration)
74
+ end
60
75
  end
76
+ end
61
77
 
62
- it 'does not write a todo file' do
63
- Reek::CLI::Silencer.silently { command.execute }
64
- expect(File).not_to have_received(:write)
65
- end
78
+ def todo_command(options: Reek::CLI::Options.new([]),
79
+ sources: [Pathname.new(SMELLY_FILE.basename.to_s)],
80
+ configuration: Reek::Configuration::AppConfiguration.default)
81
+ described_class.new options: options,
82
+ sources: sources,
83
+ configuration: configuration
66
84
  end
67
85
  end
68
86
  end
@@ -22,18 +22,18 @@ RSpec.describe Reek::Configuration::AppConfiguration do
22
22
  end
23
23
 
24
24
  let(:default_directive_value) do
25
- { described_class::DETECTORS_KEY =>
25
+ { Reek::DETECTORS_KEY =>
26
26
  { 'IrresponsibleModule' => { 'enabled' => false } } }
27
27
  end
28
28
 
29
29
  let(:directory_directives_value) do
30
- { described_class::DIRECTORIES_KEY =>
30
+ { Reek::DIRECTORIES_KEY =>
31
31
  { 'samples/three_clean_files' =>
32
32
  { 'UtilityFunction' => { 'enabled' => false } } } }
33
33
  end
34
34
 
35
35
  let(:exclude_paths_value) do
36
- { described_class::EXCLUDE_PATHS_KEY =>
36
+ { Reek::EXCLUDE_PATHS_KEY =>
37
37
  ['samples/two_smelly_files',
38
38
  'samples/source_with_non_ruby_files'] }
39
39
  end
@@ -85,7 +85,7 @@ RSpec.describe Reek::Configuration::AppConfiguration do
85
85
  let(:expected_result) { { Reek::SmellDetectors::Attribute => { enabled: true } } }
86
86
 
87
87
  let(:directory_directives) do
88
- { described_class::DIRECTORIES_KEY =>
88
+ { Reek::DIRECTORIES_KEY =>
89
89
  {
90
90
  'samples/two_smelly_files' => baz_config,
91
91
  'samples/three_clean_files' => bang_config
@@ -104,9 +104,9 @@ RSpec.describe Reek::Configuration::AppConfiguration do
104
104
 
105
105
  let(:configuration_as_hash) do
106
106
  {
107
- described_class::DIRECTORIES_KEY =>
107
+ Reek::DIRECTORIES_KEY =>
108
108
  { directory => { TooManyStatements: { max_statements: 8 } } },
109
- described_class::DETECTORS_KEY => {
109
+ Reek::DETECTORS_KEY => {
110
110
  IrresponsibleModule: { enabled: false },
111
111
  TooManyStatements: { max_statements: 15 }
112
112
  }
@@ -128,10 +128,10 @@ RSpec.describe Reek::Configuration::AppConfiguration do
128
128
 
129
129
  let(:configuration_as_hash) do
130
130
  {
131
- described_class::DETECTORS_KEY => {
131
+ Reek::DETECTORS_KEY => {
132
132
  IrresponsibleModule: { enabled: false }
133
133
  },
134
- described_class::DIRECTORIES_KEY =>
134
+ Reek::DIRECTORIES_KEY =>
135
135
  { 'spec/samples/two_smelly_files' => { Attribute: { enabled: false } } }
136
136
  }
137
137
  end
@@ -98,7 +98,7 @@ RSpec.describe Reek::Configuration::ConfigurationFileFinder do
98
98
  describe '.load_from_file' do
99
99
  let(:sample_configuration_loaded) do
100
100
  {
101
- Reek::Configuration::AppConfiguration::DETECTORS_KEY => {
101
+ Reek::DETECTORS_KEY => {
102
102
  'UncommunicativeVariableName' => { 'enabled' => false },
103
103
  'UncommunicativeMethodName' => { 'enabled' => false }
104
104
  }
@@ -123,7 +123,7 @@ RSpec.describe Reek::Configuration::ConfigurationFileFinder do
123
123
  let(:configuration) do
124
124
  described_class.
125
125
  load_from_file(CONFIGURATION_DIR.join('accepts_rejects_and_excludes_for_detectors.reek.yml')).
126
- fetch(Reek::Configuration::AppConfiguration::DETECTORS_KEY)
126
+ fetch(Reek::DETECTORS_KEY)
127
127
  end
128
128
 
129
129
  let(:expected) do
@@ -166,7 +166,7 @@ RSpec.describe Reek::Configuration::ConfigurationFileFinder do
166
166
  let(:configuration) do
167
167
  described_class.
168
168
  load_from_file(CONFIGURATION_DIR.join('accepts_rejects_and_excludes_for_directory_directives.reek.yml')).
169
- fetch(Reek::Configuration::AppConfiguration::DIRECTORIES_KEY)
169
+ fetch(Reek::DIRECTORIES_KEY)
170
170
  end
171
171
 
172
172
  let(:expected) do