reek 3.2.1 → 3.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Rakefile +0 -1
- data/config/defaults.reek +1 -1
- data/features/samples.feature +17 -16
- data/lib/reek.rb +0 -1
- data/lib/reek/ast/ast_node_class_map.rb +5 -1
- data/lib/reek/ast/node.rb +10 -3
- data/lib/reek/ast/object_refs.rb +11 -5
- data/lib/reek/ast/reference_collector.rb +6 -2
- data/lib/reek/ast/sexp_extensions.rb +42 -1
- data/lib/reek/ast/sexp_formatter.rb +2 -1
- data/lib/reek/cli/application.rb +12 -9
- data/lib/reek/cli/command.rb +6 -0
- data/lib/reek/cli/input.rb +4 -4
- data/lib/reek/cli/option_interpreter.rb +11 -7
- data/lib/reek/cli/options.rb +42 -40
- data/lib/reek/cli/reek_command.rb +3 -3
- data/lib/reek/cli/silencer.rb +12 -3
- data/lib/reek/cli/warning_collector.rb +8 -3
- data/lib/reek/code_comment.rb +6 -1
- data/lib/reek/configuration/app_configuration.rb +65 -100
- data/lib/reek/configuration/configuration_file_finder.rb +4 -13
- data/lib/reek/configuration/configuration_validator.rb +35 -0
- data/lib/reek/configuration/default_directive.rb +12 -0
- data/lib/reek/configuration/directory_directives.rb +54 -0
- data/lib/reek/configuration/excluded_paths.rb +18 -0
- data/lib/reek/context/code_context.rb +19 -17
- data/lib/reek/examiner.rb +9 -7
- data/lib/reek/rake/task.rb +12 -22
- data/lib/reek/report/formatter.rb +6 -1
- data/lib/reek/report/report.rb +22 -13
- data/lib/reek/smells/attribute.rb +6 -53
- data/lib/reek/smells/control_parameter.rb +21 -13
- data/lib/reek/smells/data_clump.rb +17 -9
- data/lib/reek/smells/duplicate_method_call.rb +12 -6
- data/lib/reek/smells/long_parameter_list.rb +2 -2
- data/lib/reek/smells/long_yield_list.rb +4 -4
- data/lib/reek/smells/nested_iterators.rb +4 -2
- data/lib/reek/smells/nil_check.rb +6 -2
- data/lib/reek/smells/repeated_conditional.rb +3 -3
- data/lib/reek/smells/smell_configuration.rb +17 -7
- data/lib/reek/smells/smell_detector.rb +24 -11
- data/lib/reek/smells/smell_repository.rb +1 -1
- data/lib/reek/smells/smell_warning.rb +6 -6
- data/lib/reek/smells/too_many_instance_variables.rb +2 -2
- data/lib/reek/smells/too_many_methods.rb +4 -4
- data/lib/reek/smells/too_many_statements.rb +4 -4
- data/lib/reek/smells/uncommunicative_method_name.rb +5 -5
- data/lib/reek/smells/uncommunicative_module_name.rb +6 -6
- data/lib/reek/smells/uncommunicative_parameter_name.rb +8 -4
- data/lib/reek/smells/uncommunicative_variable_name.rb +9 -5
- data/lib/reek/smells/utility_function.rb +1 -1
- data/lib/reek/source/source_code.rb +5 -1
- data/lib/reek/source/source_locator.rb +3 -2
- data/lib/reek/spec.rb +3 -3
- data/lib/reek/spec/should_reek.rb +10 -5
- data/lib/reek/spec/should_reek_of.rb +9 -6
- data/lib/reek/spec/should_reek_only_of.rb +13 -8
- data/lib/reek/tree_dresser.rb +6 -2
- data/lib/reek/tree_walker.rb +40 -32
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +1 -1
- data/spec/reek/ast/node_spec.rb +1 -2
- data/spec/reek/ast/object_refs_spec.rb +40 -42
- data/spec/reek/ast/sexp_extensions_spec.rb +98 -104
- data/spec/reek/cli/warning_collector_spec.rb +8 -12
- data/spec/reek/code_comment_spec.rb +3 -5
- data/spec/reek/configuration/app_configuration_spec.rb +43 -57
- data/spec/reek/configuration/configuration_file_finder_spec.rb +5 -7
- data/spec/reek/configuration/default_directive_spec.rb +13 -0
- data/spec/reek/configuration/directory_directives_spec.rb +89 -0
- data/spec/reek/configuration/excluded_paths_spec.rb +30 -0
- data/spec/reek/context/code_context_spec.rb +63 -62
- data/spec/reek/context/method_context_spec.rb +8 -12
- data/spec/reek/context/module_context_spec.rb +1 -1
- data/spec/reek/context/root_context_spec.rb +3 -7
- data/spec/reek/examiner_spec.rb +14 -25
- data/spec/reek/smells/attribute_spec.rb +2 -4
- data/spec/reek/smells/boolean_parameter_spec.rb +5 -7
- data/spec/reek/smells/class_variable_spec.rb +29 -44
- data/spec/reek/smells/control_parameter_spec.rb +7 -9
- data/spec/reek/smells/data_clump_spec.rb +25 -32
- data/spec/reek/smells/duplicate_method_call_spec.rb +8 -7
- data/spec/reek/smells/feature_envy_spec.rb +16 -17
- data/spec/reek/smells/irresponsible_module_spec.rb +2 -4
- data/spec/reek/smells/long_parameter_list_spec.rb +6 -9
- data/spec/reek/smells/long_yield_list_spec.rb +6 -9
- data/spec/reek/smells/nested_iterators_spec.rb +14 -16
- data/spec/reek/smells/repeated_conditional_spec.rb +25 -25
- data/spec/reek/smells/smell_configuration_spec.rb +32 -27
- data/spec/reek/smells/smell_detector_shared.rb +12 -13
- data/spec/reek/smells/smell_warning_spec.rb +54 -58
- data/spec/reek/smells/too_many_instance_variables_spec.rb +9 -9
- data/spec/reek/smells/too_many_methods_spec.rb +13 -14
- data/spec/reek/smells/too_many_statements_spec.rb +8 -10
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +8 -9
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +12 -13
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +7 -10
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +16 -20
- data/spec/reek/smells/utility_function_spec.rb +11 -15
- data/spec/reek/source/source_code_spec.rb +6 -11
- data/spec/reek/spec/should_reek_of_spec.rb +19 -30
- data/spec/reek/spec/should_reek_only_of_spec.rb +28 -34
- data/spec/reek/tree_walker_spec.rb +14 -2
- data/spec/spec_helper.rb +2 -3
- data/tasks/test.rake +0 -5
- metadata +10 -6
- data/docs/Configuration-Files.md +0 -49
- data/spec/gem/updates_spec.rb +0 -25
- data/spec/gem/yard_spec.rb +0 -11
- data/spec/reek/smells/behaves_like_variable_detector.rb +0 -39
@@ -3,26 +3,22 @@ require_relative '../../../lib/reek/cli/warning_collector'
|
|
3
3
|
require_relative '../../../lib/reek/smells/smell_warning'
|
4
4
|
|
5
5
|
RSpec.describe Reek::CLI::WarningCollector do
|
6
|
-
|
7
|
-
@collector = described_class.new
|
8
|
-
end
|
6
|
+
let(:collector) { described_class.new }
|
9
7
|
|
10
8
|
context 'when empty' do
|
11
9
|
it 'reports no warnings' do
|
12
|
-
expect(
|
10
|
+
expect(collector.warnings).to eq([])
|
13
11
|
end
|
14
12
|
end
|
15
13
|
|
16
14
|
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
15
|
it 'reports that warning' do
|
25
|
-
|
16
|
+
warning = Reek::Smells::SmellWarning.new(Reek::Smells::FeatureEnvy.new(''),
|
17
|
+
context: 'fred',
|
18
|
+
lines: [1, 2, 3],
|
19
|
+
message: 'hello')
|
20
|
+
collector.found_smell(warning)
|
21
|
+
expect(collector.warnings).to eq([warning])
|
26
22
|
end
|
27
23
|
end
|
28
24
|
end
|
@@ -3,14 +3,12 @@ require_relative '../../lib/reek/code_comment'
|
|
3
3
|
|
4
4
|
RSpec.describe Reek::CodeComment do
|
5
5
|
context 'with an empty comment' do
|
6
|
-
|
7
|
-
@comment = described_class.new('')
|
8
|
-
end
|
6
|
+
let(:comment) { described_class.new('') }
|
9
7
|
it 'is not descriptive' do
|
10
|
-
expect(
|
8
|
+
expect(comment).not_to be_descriptive
|
11
9
|
end
|
12
10
|
it 'has an empty config' do
|
13
|
-
expect(
|
11
|
+
expect(comment.config).to be_empty
|
14
12
|
end
|
15
13
|
end
|
16
14
|
|
@@ -1,13 +1,19 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
require_relative '../../spec_helper'
|
3
3
|
require_relative '../../../lib/reek/configuration/app_configuration'
|
4
|
-
require_relative '../../../lib/reek/
|
5
|
-
require_relative '../../../lib/reek/
|
4
|
+
require_relative '../../../lib/reek/configuration/directory_directives'
|
5
|
+
require_relative '../../../lib/reek/configuration/default_directive'
|
6
|
+
require_relative '../../../lib/reek/configuration/excluded_paths'
|
6
7
|
|
7
8
|
RSpec.describe Reek::Configuration::AppConfiguration do
|
8
|
-
describe '#
|
9
|
-
|
10
|
-
|
9
|
+
describe '#new' do
|
10
|
+
it 'raises NotImplementedError' do
|
11
|
+
expect { subject }.to raise_error(NotImplementedError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'factory methods' do
|
16
|
+
let(:expected_excluded_paths) do
|
11
17
|
[SAMPLES_PATH.join('two_smelly_files'),
|
12
18
|
SAMPLES_PATH.join('source_with_non_ruby_files')]
|
13
19
|
end
|
@@ -19,13 +25,28 @@ RSpec.describe Reek::Configuration::AppConfiguration do
|
|
19
25
|
{ Reek::Smells::UtilityFunction => { 'enabled' => false } } }
|
20
26
|
end
|
21
27
|
|
22
|
-
|
23
|
-
|
24
|
-
|
28
|
+
describe '#from_path' do
|
29
|
+
let(:full_configuration_path) { SAMPLES_PATH.join('configuration/full_configuration.reek') }
|
30
|
+
|
31
|
+
it 'properly loads configuration and processes it' do
|
32
|
+
config = described_class.from_path full_configuration_path
|
33
|
+
|
34
|
+
expect(config.send(:excluded_paths)).to eq(expected_excluded_paths)
|
35
|
+
expect(config.send(:default_directive)).to eq(expected_default_directive)
|
36
|
+
expect(config.send(:directory_directives)).to eq(expected_directory_directives)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#from_map' do
|
41
|
+
it 'properly sets the configuration' do
|
42
|
+
config = described_class.from_map(directory_directives: expected_directory_directives,
|
43
|
+
default_directive: expected_default_directive,
|
44
|
+
excluded_paths: expected_excluded_paths)
|
25
45
|
|
26
|
-
|
27
|
-
|
28
|
-
|
46
|
+
expect(config.send(:excluded_paths)).to eq(expected_excluded_paths)
|
47
|
+
expect(config.send(:default_directive)).to eq(expected_default_directive)
|
48
|
+
expect(config.send(:directory_directives)).to eq(expected_directory_directives)
|
49
|
+
end
|
29
50
|
end
|
30
51
|
end
|
31
52
|
|
@@ -43,64 +64,29 @@ RSpec.describe Reek::Configuration::AppConfiguration do
|
|
43
64
|
let(:source_via) { 'foo/bar/bang/dummy.rb' }
|
44
65
|
|
45
66
|
it 'returns the corresponding directive' do
|
46
|
-
|
47
|
-
expect(
|
67
|
+
configuration = described_class.from_map directory_directives: directory_directives
|
68
|
+
expect(configuration.directive_for(source_via)).to eq(bang_config)
|
48
69
|
end
|
49
70
|
end
|
50
71
|
|
51
72
|
context 'our source is not in a directory for which we have a directive' do
|
52
|
-
let(:
|
73
|
+
let(:irresponsible_module_config) do
|
74
|
+
{ Reek::Smells::IrresponsibleModule => { enabled: false } }
|
75
|
+
end
|
76
|
+
let(:attribute_config) { { Reek::Smells::Attribute => { enabled: false } } }
|
53
77
|
let(:default_directive) do
|
54
|
-
|
78
|
+
irresponsible_module_config
|
55
79
|
end
|
56
80
|
let(:directory_directives) do
|
57
|
-
{ Pathname.new('foo/bar/baz')
|
81
|
+
{ Pathname.new('foo/bar/baz') => attribute_config }
|
58
82
|
end
|
59
83
|
let(:source_via) { 'foo/bar/bang/dummy.rb' }
|
60
84
|
|
61
85
|
it 'returns the default directive' do
|
62
|
-
|
63
|
-
|
64
|
-
expect(
|
86
|
+
configuration = described_class.from_map directory_directives: directory_directives,
|
87
|
+
default_directive: default_directive
|
88
|
+
expect(configuration.directive_for(source_via)).to eq(irresponsible_module_config)
|
65
89
|
end
|
66
90
|
end
|
67
91
|
end
|
68
|
-
|
69
|
-
describe '#best_directory_match_for' do
|
70
|
-
let(:directory_directives) do
|
71
|
-
{
|
72
|
-
Pathname.new('foo/bar/baz') => {},
|
73
|
-
Pathname.new('foo/bar') => {},
|
74
|
-
Pathname.new('bar/boo') => {}
|
75
|
-
}
|
76
|
-
end
|
77
|
-
|
78
|
-
before do
|
79
|
-
allow(subject).to receive(:directory_directives).and_return directory_directives
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'returns the corresponding directory when source_base_dir is a leaf' do
|
83
|
-
source_base_dir = 'foo/bar/baz/bang'
|
84
|
-
hit = subject.send :best_directory_match_for, source_base_dir
|
85
|
-
expect(hit.to_s).to eq('foo/bar/baz')
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'returns the corresponding directory when source_base_dir is in the middle of the tree' do
|
89
|
-
source_base_dir = 'foo/bar'
|
90
|
-
hit = subject.send :best_directory_match_for, source_base_dir
|
91
|
-
expect(hit.to_s).to eq('foo/bar')
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'returns nil we are on top at the top of the and all other directories are below' do
|
95
|
-
source_base_dir = 'foo'
|
96
|
-
hit = subject.send :best_directory_match_for, source_base_dir
|
97
|
-
expect(hit).to be_nil
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'returns nil when there source_base_dir is not part of any directory directive at all' do
|
101
|
-
source_base_dir = 'non/existent'
|
102
|
-
hit = subject.send :best_directory_match_for, source_base_dir
|
103
|
-
expect(hit).to be_nil
|
104
|
-
end
|
105
|
-
end
|
106
92
|
end
|
@@ -7,16 +7,14 @@ require_relative '../../spec_helper'
|
|
7
7
|
|
8
8
|
RSpec.describe Reek::Configuration::ConfigurationFileFinder do
|
9
9
|
describe '.find' do
|
10
|
-
it 'returns the
|
11
|
-
|
12
|
-
|
13
|
-
found
|
14
|
-
expect(found).to eq(config_file)
|
10
|
+
it 'returns the path if it’s set' do
|
11
|
+
path = Pathname.new 'foo/bar'
|
12
|
+
found = described_class.find(path: path)
|
13
|
+
expect(found).to eq(path)
|
15
14
|
end
|
16
15
|
|
17
16
|
it 'returns the file in current dir if config_file is nil' do
|
18
|
-
|
19
|
-
found = described_class.find(options: options, current: SAMPLES_PATH)
|
17
|
+
found = described_class.find(current: SAMPLES_PATH)
|
20
18
|
expect(found).to eq(SAMPLES_PATH.join('exceptions.reek'))
|
21
19
|
end
|
22
20
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
require_relative '../../../lib/reek/configuration/default_directive'
|
3
|
+
|
4
|
+
RSpec.describe Reek::Configuration::DefaultDirective do
|
5
|
+
describe '#add' do
|
6
|
+
subject { {}.extend(described_class) }
|
7
|
+
|
8
|
+
it 'adds a smell configuration' do
|
9
|
+
subject.add :UncommunicativeVariableName, enabled: false
|
10
|
+
expect(subject).to eq(Reek::Smells::UncommunicativeVariableName => { enabled: false })
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
require_relative '../../../lib/reek/configuration/directory_directives'
|
3
|
+
|
4
|
+
RSpec.describe Reek::Configuration::DirectoryDirectives do
|
5
|
+
describe '#directive_for' do
|
6
|
+
let(:baz_config) { { Reek::Smells::IrresponsibleModule => { enabled: false } } }
|
7
|
+
let(:bang_config) { { Reek::Smells::Attribute => { enabled: true } } }
|
8
|
+
subject do
|
9
|
+
{
|
10
|
+
Pathname.new('foo/bar/baz') => baz_config,
|
11
|
+
Pathname.new('foo/bar/bang') => bang_config
|
12
|
+
}.extend(described_class)
|
13
|
+
end
|
14
|
+
let(:source_via) { 'foo/bar/bang/dummy.rb' }
|
15
|
+
|
16
|
+
context 'our source is in a directory for which we have a directive' do
|
17
|
+
it 'returns the corresponding directive' do
|
18
|
+
expect(subject.directive_for(source_via)).to eq(bang_config)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'our source is not in a directory for which we have a directive' do
|
23
|
+
it 'returns nil' do
|
24
|
+
expect(subject.directive_for('does/not/exist')).to eq(nil)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#add' do
|
30
|
+
subject do
|
31
|
+
{}.extend(described_class)
|
32
|
+
end
|
33
|
+
let(:empty_config) { Hash.new }
|
34
|
+
|
35
|
+
context 'one of given paths does not exist' do
|
36
|
+
let(:bogus_path) { Pathname('does/not/exist') }
|
37
|
+
|
38
|
+
it 'raises an error' do
|
39
|
+
Reek::CLI::Silencer.silently(stderr: true) do
|
40
|
+
expect { subject.add(bogus_path, {}) }.to raise_error(SystemExit)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'one of given paths is a file' do
|
46
|
+
let(:file_as_path) { SAMPLES_PATH.join('inline.rb') }
|
47
|
+
|
48
|
+
it 'raises an error' do
|
49
|
+
Reek::CLI::Silencer.silently(stderr: true) do
|
50
|
+
expect { subject.add(file_as_path, {}) }.to raise_error(SystemExit)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#best_match_for' do
|
57
|
+
subject do
|
58
|
+
{
|
59
|
+
Pathname.new('foo/bar/baz') => {},
|
60
|
+
Pathname.new('foo/bar') => {},
|
61
|
+
Pathname.new('bar/boo') => {}
|
62
|
+
}.extend(described_class)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns the corresponding directory when source_base_dir is a leaf' do
|
66
|
+
source_base_dir = 'foo/bar/baz/bang'
|
67
|
+
hit = subject.send :best_match_for, source_base_dir
|
68
|
+
expect(hit.to_s).to eq('foo/bar/baz')
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'returns the corresponding directory when source_base_dir is in the middle of the tree' do
|
72
|
+
source_base_dir = 'foo/bar'
|
73
|
+
hit = subject.send :best_match_for, source_base_dir
|
74
|
+
expect(hit.to_s).to eq('foo/bar')
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns nil we are on top of the tree and all other directories are below' do
|
78
|
+
source_base_dir = 'foo'
|
79
|
+
hit = subject.send :best_match_for, source_base_dir
|
80
|
+
expect(hit).to be_nil
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'returns nil when source_base_dir is not part of any directory directive at all' do
|
84
|
+
source_base_dir = 'non/existent'
|
85
|
+
hit = subject.send :best_match_for, source_base_dir
|
86
|
+
expect(hit).to be_nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
require_relative '../../../lib/reek/configuration/excluded_paths'
|
3
|
+
|
4
|
+
RSpec.describe Reek::Configuration::ExcludedPaths do
|
5
|
+
describe '#add' do
|
6
|
+
subject { [].extend(described_class) }
|
7
|
+
|
8
|
+
context 'one of the given paths does not exist' do
|
9
|
+
let(:bogus_path) { Pathname('does/not/exist') }
|
10
|
+
let(:paths) { [SAMPLES_PATH, bogus_path] }
|
11
|
+
|
12
|
+
it 'raises an error' do
|
13
|
+
Reek::CLI::Silencer.silently(stderr: true) do
|
14
|
+
expect { subject.add(paths) }.to raise_error(SystemExit)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'one of given paths is a file' do
|
20
|
+
let(:file_as_path) { SAMPLES_PATH.join('inline.rb') }
|
21
|
+
let(:paths) { [SAMPLES_PATH, file_as_path] }
|
22
|
+
|
23
|
+
it 'raises an error if one of the given paths is a file' do
|
24
|
+
Reek::CLI::Silencer.silently(stderr: true) do
|
25
|
+
expect { subject.add(paths) }.to raise_error(SystemExit)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -4,107 +4,109 @@ require_relative '../../../lib/reek/context/module_context'
|
|
4
4
|
|
5
5
|
RSpec.describe Reek::Context::CodeContext do
|
6
6
|
context 'name recognition' do
|
7
|
+
let(:ctx) { Reek::Context::CodeContext.new(nil, exp) }
|
8
|
+
let(:exp) { double('exp') }
|
9
|
+
let(:exp_name) { 'random_name' }
|
10
|
+
let(:full_name) { "::::::::::::::::::::#{exp_name}" }
|
11
|
+
|
7
12
|
before :each do
|
8
|
-
|
9
|
-
|
10
|
-
@exp = double('exp')
|
11
|
-
allow(@exp).to receive(:name).and_return(@exp_name)
|
12
|
-
allow(@exp).to receive(:full_name).and_return(@full_name)
|
13
|
-
@ctx = Reek::Context::CodeContext.new(nil, @exp)
|
13
|
+
allow(exp).to receive(:name).and_return(exp_name)
|
14
|
+
allow(exp).to receive(:full_name).and_return(full_name)
|
14
15
|
end
|
16
|
+
|
15
17
|
it 'gets its short name from the exp' do
|
16
|
-
expect(
|
18
|
+
expect(ctx.name).to eq(exp_name)
|
17
19
|
end
|
18
20
|
it 'does not match an empty list' do
|
19
|
-
expect(
|
21
|
+
expect(ctx.matches?([])).to eq(false)
|
20
22
|
end
|
21
23
|
it 'does not match when its own short name is not given' do
|
22
|
-
expect(
|
24
|
+
expect(ctx.matches?(['banana'])).to eq(false)
|
23
25
|
end
|
24
26
|
it 'does not let pipe-ended Strings make matching ignore the rest' do
|
25
|
-
expect(
|
27
|
+
expect(ctx.matches?(['banana|'])).to eq(false)
|
26
28
|
end
|
27
29
|
it 'recognises its own short name' do
|
28
|
-
expect(
|
30
|
+
expect(ctx.matches?(['banana', exp_name])).to eq(true)
|
29
31
|
end
|
30
32
|
it 'recognises its short name as a regex' do
|
31
|
-
expect(
|
33
|
+
expect(ctx.matches?([/banana/, /#{exp_name}/])).to eq(true)
|
32
34
|
end
|
33
35
|
it 'does not blow up on []-ended Strings' do
|
34
|
-
expect(
|
36
|
+
expect(ctx.matches?(['banana[]', exp_name])).to eq(true)
|
35
37
|
end
|
36
38
|
|
37
39
|
context 'when there is an outer' do
|
38
|
-
let(:
|
40
|
+
let(:ctx) { Reek::Context::CodeContext.new(outer, exp) }
|
41
|
+
let(:outer_name) { 'another_random sting' }
|
42
|
+
let(:outer) { double('outer') }
|
43
|
+
|
39
44
|
before :each do
|
40
|
-
|
41
|
-
allow(outer).to receive(:full_name).at_least(:once).and_return(@outer_name)
|
45
|
+
allow(outer).to receive(:full_name).at_least(:once).and_return(outer_name)
|
42
46
|
allow(outer).to receive(:config).and_return({})
|
43
|
-
@ctx = Reek::Context::CodeContext.new(outer, @exp)
|
44
47
|
end
|
48
|
+
|
45
49
|
it 'creates the correct full name' do
|
46
|
-
expect(
|
50
|
+
expect(ctx.full_name).to eq(full_name)
|
47
51
|
end
|
48
52
|
it 'recognises its own full name' do
|
49
|
-
expect(
|
53
|
+
expect(ctx.matches?(['banana', full_name])).to eq(true)
|
50
54
|
end
|
51
55
|
it 'recognises its full name as a regex' do
|
52
|
-
expect(
|
56
|
+
expect(ctx.matches?([/banana/, /#{full_name}/])).to eq(true)
|
53
57
|
end
|
54
58
|
end
|
55
59
|
end
|
56
60
|
|
57
61
|
context 'enumerating syntax elements' do
|
58
62
|
context 'in an empty module' do
|
59
|
-
|
60
|
-
|
61
|
-
src = "module #{@module_name}; end"
|
63
|
+
let(:ctx) do
|
64
|
+
src = 'module Emptiness; end'
|
62
65
|
ast = Reek::Source::SourceCode.from(src).syntax_tree
|
63
|
-
|
66
|
+
Reek::Context::CodeContext.new(nil, ast)
|
64
67
|
end
|
65
68
|
|
66
69
|
it 'yields no calls' do
|
67
|
-
|
70
|
+
ctx.each_node(:send, []) { |exp| raise "#{exp} yielded by empty module!" }
|
68
71
|
end
|
69
72
|
|
70
73
|
it 'yields one module' do
|
71
74
|
mods = 0
|
72
|
-
|
75
|
+
ctx.each_node(:module, []) { |_exp| mods += 1 }
|
73
76
|
expect(mods).to eq(1)
|
74
77
|
end
|
75
78
|
|
76
79
|
it "yields the module's full AST" do
|
77
|
-
|
78
|
-
expect(exp).to eq(s(:module, s(:const, nil,
|
80
|
+
ctx.each_node(:module, []) do |exp|
|
81
|
+
expect(exp).to eq(s(:module, s(:const, nil, :Emptiness), nil))
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
82
85
|
context 'with no block' do
|
83
86
|
it 'returns an empty array of ifs' do
|
84
|
-
expect(
|
87
|
+
expect(ctx.each_node(:if, [])).to be_empty
|
85
88
|
end
|
86
89
|
end
|
87
90
|
end
|
88
91
|
|
89
92
|
context 'with a nested element' do
|
90
|
-
|
91
|
-
|
92
|
-
@method_name = 'calloo'
|
93
|
-
src = "module #{@module_name}; def #{@method_name}; puts('hello') end; end"
|
93
|
+
let(:ctx) do
|
94
|
+
src = "module Loneliness; def calloo; puts('hello') end; end"
|
94
95
|
ast = Reek::Source::SourceCode.from(src).syntax_tree
|
95
|
-
|
96
|
+
Reek::Context::CodeContext.new(nil, ast)
|
96
97
|
end
|
98
|
+
|
97
99
|
it 'yields no ifs' do
|
98
|
-
|
100
|
+
ctx.each_node(:if, []) { |exp| raise "#{exp} yielded by empty module!" }
|
99
101
|
end
|
100
102
|
it 'yields one module' do
|
101
|
-
expect(
|
103
|
+
expect(ctx.each_node(:module, []).length).to eq(1)
|
102
104
|
end
|
103
105
|
|
104
106
|
it "yields the module's full AST" do
|
105
|
-
|
107
|
+
ctx.each_node(:module, []) do |exp|
|
106
108
|
expect(exp).to eq s(:module,
|
107
|
-
s(:const, nil,
|
109
|
+
s(:const, nil, :Loneliness),
|
108
110
|
s(:def, :calloo,
|
109
111
|
s(:args),
|
110
112
|
s(:send, nil, :puts, s(:str, 'hello'))))
|
@@ -112,37 +114,36 @@ RSpec.describe Reek::Context::CodeContext do
|
|
112
114
|
end
|
113
115
|
|
114
116
|
it 'yields one method' do
|
115
|
-
expect(
|
117
|
+
expect(ctx.each_node(:def, []).length).to eq(1)
|
116
118
|
end
|
117
119
|
|
118
120
|
it "yields the method's full AST" do
|
119
|
-
|
121
|
+
ctx.each_node(:def, []) { |exp| expect(exp[1]).to eq(:calloo) }
|
120
122
|
end
|
121
123
|
|
122
124
|
context 'pruning the traversal' do
|
123
125
|
it 'ignores the call inside the method' do
|
124
|
-
expect(
|
126
|
+
expect(ctx.each_node(:send, [:def])).to be_empty
|
125
127
|
end
|
126
128
|
end
|
127
129
|
end
|
128
130
|
|
129
131
|
it 'finds 3 ifs in a class' do
|
130
|
-
src =
|
131
|
-
class Scrunch
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
end
|
144
|
-
EOS
|
145
|
-
|
132
|
+
src = <<-EOS
|
133
|
+
class Scrunch
|
134
|
+
def first
|
135
|
+
return @field == :sym ? 0 : 3;
|
136
|
+
end
|
137
|
+
def second
|
138
|
+
if @field == :sym
|
139
|
+
@other += " quarts"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
def third
|
143
|
+
raise 'flu!' unless @field == :sym
|
144
|
+
end
|
145
|
+
end
|
146
|
+
EOS
|
146
147
|
ast = Reek::Source::SourceCode.from(src).syntax_tree
|
147
148
|
ctx = Reek::Context::CodeContext.new(nil, ast)
|
148
149
|
expect(ctx.each_node(:if, []).length).to eq(3)
|
@@ -152,11 +153,11 @@ EOS
|
|
152
153
|
describe '#config_for' do
|
153
154
|
let(:src) do
|
154
155
|
<<-EOS
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
156
|
+
# :reek:DuplicateMethodCall: { allow_calls: [ puts ] }')
|
157
|
+
def repeated_greeting
|
158
|
+
puts 'Hello!'
|
159
|
+
puts 'Hello!'
|
160
|
+
end
|
160
161
|
EOS
|
161
162
|
end
|
162
163
|
let(:expression) { Reek::Source::SourceCode.from(src).syntax_tree }
|