reek 4.5.0 → 4.6.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/.rubocop.yml +10 -7
- data/.travis.yml +13 -9
- data/CHANGELOG.md +36 -3
- data/Dockerfile +6 -5
- data/Gemfile +8 -7
- data/README.md +45 -27
- data/docs/How-To-Write-New-Detectors.md +6 -6
- data/docs/Irresponsible-Module.md +8 -1
- data/docs/Nil-Check.md +1 -1
- data/docs/Prima-Donna-Method.md +27 -0
- data/docs/RSpec-matchers.md +5 -10
- data/docs/Unused-Private-Method.md +27 -0
- data/docs/templates/default/docstring/setup.rb +1 -8
- data/features/command_line_interface/options.feature +5 -1
- data/features/command_line_interface/stdin.feature +1 -1
- data/features/configuration_files/exclude_paths_directives.feature +43 -0
- data/features/configuration_files/warn_about_multiple_configuration_files.feature +44 -0
- data/features/configuration_via_source_comments/erroneous_source_comments.feature +15 -0
- data/features/samples.feature +3 -8
- data/features/step_definitions/reek_steps.rb +5 -5
- data/features/todo_list.feature +1 -2
- data/lib/reek/ast/reference_collector.rb +2 -4
- data/lib/reek/ast/sexp_extensions/arguments.rb +0 -5
- data/lib/reek/ast/sexp_extensions/constant.rb +1 -0
- data/lib/reek/cli/application.rb +7 -8
- data/lib/reek/cli/command/report_command.rb +3 -1
- data/lib/reek/cli/options.rb +29 -13
- data/lib/reek/cli/status.rb +10 -0
- data/lib/reek/code_comment.rb +48 -6
- data/lib/reek/configuration/configuration_file_finder.rb +87 -27
- data/lib/reek/context/ghost_context.rb +1 -2
- data/lib/reek/context_builder.rb +26 -1
- data/lib/reek/detector_repository.rb +64 -0
- data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +37 -0
- data/lib/reek/errors/bad_detector_in_comment_error.rb +2 -1
- data/lib/reek/errors/base_error.rb +9 -0
- data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +2 -1
- data/lib/reek/errors/incomprehensible_source_error.rb +47 -0
- data/lib/reek/errors/parse_error.rb +19 -0
- data/lib/reek/examiner.rb +17 -41
- data/lib/reek/logging_error_handler.rb +15 -0
- data/lib/reek/report/code_climate/code_climate_configuration.rb +12 -0
- data/lib/reek/report/code_climate/code_climate_configuration.yml +156 -0
- data/lib/reek/report/code_climate/code_climate_fingerprint.rb +4 -2
- data/lib/reek/report/code_climate/code_climate_formatter.rb +2 -2
- data/lib/reek/smell_configuration.rb +64 -0
- data/lib/reek/smell_detectors/attribute.rb +0 -2
- data/lib/reek/smell_detectors/base_detector.rb +24 -4
- data/lib/reek/smell_detectors/boolean_parameter.rb +0 -1
- data/lib/reek/smell_detectors/class_variable.rb +0 -1
- data/lib/reek/smell_detectors/control_parameter.rb +0 -1
- data/lib/reek/smell_detectors/data_clump.rb +0 -1
- data/lib/reek/smell_detectors/duplicate_method_call.rb +0 -1
- data/lib/reek/smell_detectors/feature_envy.rb +0 -1
- data/lib/reek/smell_detectors/instance_variable_assumption.rb +0 -1
- data/lib/reek/smell_detectors/irresponsible_module.rb +0 -1
- data/lib/reek/smell_detectors/long_parameter_list.rb +0 -2
- data/lib/reek/smell_detectors/long_yield_list.rb +0 -1
- data/lib/reek/smell_detectors/manual_dispatch.rb +4 -6
- data/lib/reek/smell_detectors/module_initialize.rb +5 -8
- data/lib/reek/smell_detectors/nested_iterators.rb +0 -1
- data/lib/reek/smell_detectors/nil_check.rb +0 -1
- data/lib/reek/smell_detectors/prima_donna_method.rb +30 -1
- data/lib/reek/smell_detectors/repeated_conditional.rb +0 -1
- data/lib/reek/smell_detectors/subclassed_from_core_class.rb +0 -1
- data/lib/reek/smell_detectors/too_many_constants.rb +0 -1
- data/lib/reek/smell_detectors/too_many_instance_variables.rb +0 -1
- data/lib/reek/smell_detectors/too_many_methods.rb +0 -1
- data/lib/reek/smell_detectors/too_many_statements.rb +0 -1
- data/lib/reek/smell_detectors/uncommunicative_method_name.rb +0 -1
- data/lib/reek/smell_detectors/uncommunicative_module_name.rb +0 -1
- data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +0 -1
- data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +0 -1
- data/lib/reek/smell_detectors/unused_parameters.rb +0 -1
- data/lib/reek/smell_detectors/unused_private_method.rb +0 -2
- data/lib/reek/smell_detectors/utility_function.rb +0 -1
- data/lib/reek/smell_warning.rb +85 -0
- data/lib/reek/source/source_code.rb +2 -1
- data/lib/reek/source/source_locator.rb +15 -3
- data/lib/reek/spec/should_reek_of.rb +1 -1
- data/lib/reek/spec.rb +6 -4
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +1 -1
- data/samples/configuration/more_than_one_configuration_file/todo.reek +0 -0
- data/samples/configuration/single_configuration_file/.reek +0 -0
- data/spec/factories/factories.rb +2 -10
- data/spec/quality/reek_source_spec.rb +5 -3
- data/spec/reek/ast/reference_collector_spec.rb +0 -17
- data/spec/reek/cli/application_spec.rb +25 -1
- data/spec/reek/cli/command/report_command_spec.rb +2 -2
- data/spec/reek/cli/command/todo_list_command_spec.rb +14 -71
- data/spec/reek/cli/options_spec.rb +4 -0
- data/spec/reek/code_comment_spec.rb +47 -0
- data/spec/reek/configuration/configuration_file_finder_spec.rb +38 -15
- data/spec/reek/context/code_context_spec.rb +10 -10
- data/spec/reek/context/method_context_spec.rb +1 -1
- data/spec/reek/context/module_context_spec.rb +8 -4
- data/spec/reek/{smell_detectors/detector_repository_spec.rb → detector_repository_spec.rb} +3 -3
- data/spec/reek/examiner_spec.rb +39 -40
- data/spec/reek/logging_error_handler_spec.rb +24 -0
- data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +24 -0
- data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +9 -9
- data/spec/reek/report/yaml_report_spec.rb +4 -4
- data/spec/reek/{smell_detectors/smell_configuration_spec.rb → smell_configuration_spec.rb} +3 -3
- data/spec/reek/smell_detectors/base_detector_spec.rb +18 -0
- data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +2 -2
- data/spec/reek/smell_detectors/feature_envy_spec.rb +18 -8
- data/spec/reek/smell_detectors/manual_dispatch_spec.rb +13 -0
- data/spec/reek/smell_detectors/module_initialize_spec.rb +23 -2
- data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
- data/spec/reek/smell_detectors/prima_donna_method_spec.rb +12 -0
- data/spec/reek/smell_detectors/subclassed_from_core_class_spec.rb +0 -5
- data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +2 -2
- data/spec/reek/smell_detectors/unused_parameters_spec.rb +1 -1
- data/spec/reek/{smell_detectors/smell_warning_spec.rb → smell_warning_spec.rb} +9 -9
- data/spec/reek/source/source_code_spec.rb +6 -29
- data/spec/reek/source/source_locator_spec.rb +48 -16
- data/spec/reek/spec/should_reek_of_spec.rb +1 -1
- data/spec/reek/spec/should_reek_only_of_spec.rb +4 -4
- data/spec/spec_helper.rb +4 -3
- data/tasks/configuration.rake +2 -2
- metadata +26 -14
- data/lib/reek/smell_detectors/detector_repository.rb +0 -66
- data/lib/reek/smell_detectors/smell_configuration.rb +0 -66
- data/lib/reek/smell_detectors/smell_warning.rb +0 -88
- data/tasks/mutant.rake +0 -14
- /data/samples/configuration/{.reek → more_than_one_configuration_file/regular.reek} +0 -0
|
@@ -16,19 +16,19 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
|
|
|
16
16
|
source: 'a/ruby/source/file.rb')
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
it '
|
|
19
|
+
it 'computes the fingerprint' do
|
|
20
20
|
expect(computed).to eq expected_fingerprint
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
context 'with code at a specific location' do
|
|
25
25
|
let(:lines) { [1] }
|
|
26
|
-
|
|
26
|
+
it_behaves_like 'computes a fingerprint with no parameters'
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
context 'with code at a different location' do
|
|
30
30
|
let(:lines) { [5] }
|
|
31
|
-
|
|
31
|
+
it_behaves_like 'computes a fingerprint with no parameters'
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
context 'when the fingerprint should not be computed' do
|
|
@@ -41,7 +41,7 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
|
|
|
41
41
|
source: 'a/ruby/source/file.rb')
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
it '
|
|
44
|
+
it 'returns nil' do
|
|
45
45
|
expect(computed).to be_nil
|
|
46
46
|
end
|
|
47
47
|
end
|
|
@@ -66,14 +66,14 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
|
|
|
66
66
|
let(:name) { 'bravo' }
|
|
67
67
|
let(:expected_fingerprint) { '9c3fd378178118a67e9509f87cae24f9' }
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
it_behaves_like 'computes a fingerprint with identifying parameters'
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
context 'when the name is another thing it has another fingerprint' do
|
|
73
73
|
let(:name) { 'echo' }
|
|
74
74
|
let(:expected_fingerprint) { 'd2a6d2703ce04cca65e7300b7de4b89f' }
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
it_behaves_like 'computes a fingerprint with identifying parameters'
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
shared_examples_for 'computes a fingerprint with identifying and non-identifying parameters' do
|
|
@@ -98,7 +98,7 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
|
|
|
98
98
|
let(:lines) { [1, 7, 10, 13, 15] }
|
|
99
99
|
let(:expected_fingerprint) { '238733f4f51ba5473dcbe94a43ec5400' }
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
it_behaves_like 'computes a fingerprint with identifying and non-identifying parameters'
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
context 'when the non-identifying parameters change, it computes the same fingerprint' do
|
|
@@ -107,7 +107,7 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
|
|
|
107
107
|
let(:lines) { [1, 7, 10, 13, 15, 17, 19, 20, 25] }
|
|
108
108
|
let(:expected_fingerprint) { '238733f4f51ba5473dcbe94a43ec5400' }
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
it_behaves_like 'computes a fingerprint with identifying and non-identifying parameters'
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
context 'but when the identifying parameters change, it computes a different fingerprint' do
|
|
@@ -116,7 +116,7 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
|
|
|
116
116
|
let(:lines) { [1, 7, 10, 13, 15] }
|
|
117
117
|
let(:expected_fingerprint) { 'e0c35e9223cc19bdb9a04fb3e60573e1' }
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
it_behaves_like 'computes a fingerprint with identifying and non-identifying parameters'
|
|
120
120
|
end
|
|
121
121
|
end
|
|
122
122
|
end
|
|
@@ -30,8 +30,8 @@ RSpec.describe Reek::Report::YAMLReport do
|
|
|
30
30
|
out = StringIO.new
|
|
31
31
|
instance.show(out)
|
|
32
32
|
out.rewind
|
|
33
|
-
result = YAML.
|
|
34
|
-
expected = YAML.
|
|
33
|
+
result = YAML.safe_load(out.read)
|
|
34
|
+
expected = YAML.safe_load <<-EOS
|
|
35
35
|
---
|
|
36
36
|
- context: "simple"
|
|
37
37
|
lines:
|
|
@@ -57,8 +57,8 @@ RSpec.describe Reek::Report::YAMLReport do
|
|
|
57
57
|
out = StringIO.new
|
|
58
58
|
instance.show(out)
|
|
59
59
|
out.rewind
|
|
60
|
-
result = YAML.
|
|
61
|
-
expected = YAML.
|
|
60
|
+
result = YAML.safe_load(out.read)
|
|
61
|
+
expected = YAML.safe_load <<-EOS
|
|
62
62
|
---
|
|
63
63
|
- context: "simple"
|
|
64
64
|
lines:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
require_relative '
|
|
2
|
-
require_lib 'reek/
|
|
1
|
+
require_relative '../spec_helper'
|
|
2
|
+
require_lib 'reek/smell_configuration'
|
|
3
3
|
|
|
4
|
-
RSpec.describe Reek::
|
|
4
|
+
RSpec.describe Reek::SmellConfiguration do
|
|
5
5
|
context 'when overriding default configs' do
|
|
6
6
|
let(:base_config) do
|
|
7
7
|
{
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require_relative '../../spec_helper'
|
|
2
2
|
require_lib 'reek/smell_detectors/base_detector'
|
|
3
|
+
require_lib 'reek/smell_detectors/duplicate_method_call'
|
|
3
4
|
|
|
4
5
|
RSpec.describe Reek::SmellDetectors::BaseDetector do
|
|
5
6
|
describe '.todo_configuration_for' do
|
|
@@ -43,4 +44,21 @@ RSpec.describe Reek::SmellDetectors::BaseDetector do
|
|
|
43
44
|
expect(described_class.valid_detector?('Unknown')).to be false
|
|
44
45
|
end
|
|
45
46
|
end
|
|
47
|
+
|
|
48
|
+
describe '.to_detector' do
|
|
49
|
+
it 'returns the right detector' do
|
|
50
|
+
expect(described_class.to_detector('DuplicateMethodCall')).to eq(Reek::SmellDetectors::DuplicateMethodCall)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'raise NameError for an invalid detector name' do
|
|
54
|
+
expect { described_class.to_detector('Unknown') }.to raise_error(NameError)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe '.configuration_keys' do
|
|
59
|
+
it 'returns the right keys' do
|
|
60
|
+
expected_keys = Reek::SmellDetectors::DuplicateMethodCall.configuration_keys.to_a
|
|
61
|
+
expect(expected_keys).to eq([:enabled, :exclude, :max_calls, :allow_calls])
|
|
62
|
+
end
|
|
63
|
+
end
|
|
46
64
|
end
|
|
@@ -37,8 +37,8 @@ RSpec.describe Reek::SmellDetectors::DuplicateMethodCall do
|
|
|
37
37
|
EOS
|
|
38
38
|
|
|
39
39
|
expect(src).
|
|
40
|
-
to reek_of(:DuplicateMethodCall, lines: [3, 4], name:
|
|
41
|
-
and reek_of(:DuplicateMethodCall, lines: [8, 9], name:
|
|
40
|
+
to reek_of(:DuplicateMethodCall, lines: [3, 4], name: 'charlie.delta', count: 2).
|
|
41
|
+
and reek_of(:DuplicateMethodCall, lines: [8, 9], name: 'foxtrot.golf', count: 2)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
context 'with repeated method calls' do
|
|
@@ -33,8 +33,8 @@ RSpec.describe Reek::SmellDetectors::FeatureEnvy do
|
|
|
33
33
|
EOS
|
|
34
34
|
|
|
35
35
|
expect(src).
|
|
36
|
-
to reek_of(:FeatureEnvy, lines: [3, 3], name:
|
|
37
|
-
and reek_of(:FeatureEnvy, lines: [7, 7], name:
|
|
36
|
+
to reek_of(:FeatureEnvy, lines: [3, 3], name: 'charlie').
|
|
37
|
+
and reek_of(:FeatureEnvy, lines: [7, 7], name: 'hotel')
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
it 'does not report use of self' do
|
|
@@ -97,6 +97,16 @@ RSpec.describe Reek::SmellDetectors::FeatureEnvy do
|
|
|
97
97
|
expect(src).not_to reek_of(:FeatureEnvy)
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
+
it 'does not report parameter method called with super' do
|
|
101
|
+
src = 'def alfa(bravo) super(bravo.to_s); end'
|
|
102
|
+
expect(src).not_to reek_of(:FeatureEnvy)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it 'reports parameter method called with super and elsewhere' do
|
|
106
|
+
src = 'def alfa(bravo) bravo.charley; super(bravo.to_s); end'
|
|
107
|
+
expect(src).to reek_of(:FeatureEnvy)
|
|
108
|
+
end
|
|
109
|
+
|
|
100
110
|
it 'ignores multiple ivars' do
|
|
101
111
|
src = <<-EOS
|
|
102
112
|
def func
|
|
@@ -142,7 +152,7 @@ RSpec.describe Reek::SmellDetectors::FeatureEnvy do
|
|
|
142
152
|
and reek_of(:FeatureEnvy, name: 'bravo')
|
|
143
153
|
end
|
|
144
154
|
|
|
145
|
-
it 'is not
|
|
155
|
+
it 'is not fooled by duplication' do
|
|
146
156
|
src = <<-EOS
|
|
147
157
|
def alfa(bravo)
|
|
148
158
|
@charlie.delta(bravo.echo)
|
|
@@ -150,18 +160,18 @@ RSpec.describe Reek::SmellDetectors::FeatureEnvy do
|
|
|
150
160
|
end
|
|
151
161
|
EOS
|
|
152
162
|
|
|
153
|
-
expect(src).to reek_only_of(:DuplicateMethodCall)
|
|
163
|
+
expect(src).to reek_only_of(:DuplicateMethodCall, name: 'bravo.echo')
|
|
154
164
|
end
|
|
155
165
|
|
|
156
|
-
it '
|
|
166
|
+
it 'counts local calls' do
|
|
157
167
|
src = <<-EOS
|
|
158
168
|
def alfa(bravo)
|
|
159
|
-
|
|
160
|
-
|
|
169
|
+
charlie.delta(bravo.echo)
|
|
170
|
+
foxtrot.delta(bravo.echo)
|
|
161
171
|
end
|
|
162
172
|
EOS
|
|
163
173
|
|
|
164
|
-
expect(src).to reek_only_of(:DuplicateMethodCall)
|
|
174
|
+
expect(src).to reek_only_of(:DuplicateMethodCall, name: 'bravo.echo')
|
|
165
175
|
end
|
|
166
176
|
|
|
167
177
|
it 'reports many calls to lvar' do
|
|
@@ -59,4 +59,17 @@ RSpec.describe Reek::SmellDetectors::ManualDispatch do
|
|
|
59
59
|
|
|
60
60
|
expect(src).to reek_of(:ManualDispatch)
|
|
61
61
|
end
|
|
62
|
+
|
|
63
|
+
it 'reports occurences in a single method as one smell warning' do
|
|
64
|
+
src = <<-EOS
|
|
65
|
+
class Alfa
|
|
66
|
+
def bravo(charlie, delta)
|
|
67
|
+
return true if charlie.respond_to?(:to_a)
|
|
68
|
+
true if delta.respond_to?(:to_a)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
EOS
|
|
72
|
+
|
|
73
|
+
expect(src).to reek_of(:ManualDispatch, lines: [3, 4], context: 'Alfa#bravo')
|
|
74
|
+
end
|
|
62
75
|
end
|
|
@@ -16,7 +16,17 @@ RSpec.describe Reek::SmellDetectors::ModuleInitialize do
|
|
|
16
16
|
source: 'string')
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
it '
|
|
19
|
+
it 'reports nothing for a method with a different name' do
|
|
20
|
+
src = <<-EOF
|
|
21
|
+
module Alfa
|
|
22
|
+
def bravo; end
|
|
23
|
+
end
|
|
24
|
+
EOF
|
|
25
|
+
|
|
26
|
+
expect(src).not_to reek_of(:ModuleInitialize)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'reports nothing for a method named initialize in a nested class' do
|
|
20
30
|
src = <<-EOF
|
|
21
31
|
module Alfa
|
|
22
32
|
class Bravo
|
|
@@ -28,7 +38,7 @@ RSpec.describe Reek::SmellDetectors::ModuleInitialize do
|
|
|
28
38
|
expect(src).not_to reek_of(:ModuleInitialize)
|
|
29
39
|
end
|
|
30
40
|
|
|
31
|
-
it '
|
|
41
|
+
it 'reports nothing for a method named initialize in a nested struct' do
|
|
32
42
|
src = <<-EOF
|
|
33
43
|
module Alfa
|
|
34
44
|
Bravo = Struct.new(:charlie) do
|
|
@@ -39,4 +49,15 @@ RSpec.describe Reek::SmellDetectors::ModuleInitialize do
|
|
|
39
49
|
|
|
40
50
|
expect(src).not_to reek_of(:ModuleInitialize)
|
|
41
51
|
end
|
|
52
|
+
|
|
53
|
+
it 'can be disabled via comment' do
|
|
54
|
+
src = <<-EOS
|
|
55
|
+
# :reek:ModuleInitialize
|
|
56
|
+
module Alfa
|
|
57
|
+
def initialize; end
|
|
58
|
+
end
|
|
59
|
+
EOS
|
|
60
|
+
|
|
61
|
+
expect(src).not_to reek_of(:ModuleInitialize)
|
|
62
|
+
end
|
|
42
63
|
end
|
|
@@ -155,7 +155,7 @@ RSpec.describe Reek::SmellDetectors::NestedIterators do
|
|
|
155
155
|
it 'handles the case where super receives a block and arguments' do
|
|
156
156
|
src = <<-EOS
|
|
157
157
|
def alfa
|
|
158
|
-
super do |bravo|
|
|
158
|
+
super(delta) do |bravo|
|
|
159
159
|
bravo.each { |charlie| charlie }
|
|
160
160
|
end
|
|
161
161
|
end
|
|
@@ -47,4 +47,16 @@ RSpec.describe Reek::SmellDetectors::PrimaDonnaMethod do
|
|
|
47
47
|
|
|
48
48
|
expect(src).not_to reek_of(:PrimaDonnaMethod)
|
|
49
49
|
end
|
|
50
|
+
|
|
51
|
+
it 'does not report methods we excluded via comment' do
|
|
52
|
+
source = <<-EOF
|
|
53
|
+
# :reek:PrimaDonnaMethod: { exclude: [ bravo! ] }
|
|
54
|
+
class Alfa
|
|
55
|
+
def bravo!
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
EOF
|
|
59
|
+
|
|
60
|
+
expect(source).not_to reek_of(:PrimaDonnaMethod)
|
|
61
|
+
end
|
|
50
62
|
end
|
|
@@ -45,11 +45,6 @@ RSpec.describe Reek::SmellDetectors::SubclassedFromCoreClass do
|
|
|
45
45
|
expect(src).not_to reek_of(:SubclassedFromCoreClass)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
it 'reports if we inherit from a core class using Class#new' do
|
|
49
|
-
src = 'Alfa = Class.new(Array)'
|
|
50
|
-
expect(src).to reek_of(:SubclassedFromCoreClass)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
48
|
it 'reports if inner class inherit from a core class' do
|
|
54
49
|
src = <<-EOS
|
|
55
50
|
class Alfa
|
|
@@ -25,8 +25,8 @@ RSpec.describe Reek::SmellDetectors::UncommunicativeVariableName do
|
|
|
25
25
|
end
|
|
26
26
|
EOS
|
|
27
27
|
|
|
28
|
-
expect(src).to reek_of(:UncommunicativeVariableName, lines: [2], name:
|
|
29
|
-
and reek_of(:UncommunicativeVariableName, lines: [3], name:
|
|
28
|
+
expect(src).to reek_of(:UncommunicativeVariableName, lines: [2], name: 'x').
|
|
29
|
+
and reek_of(:UncommunicativeVariableName, lines: [3], name: 'y')
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
context 'instance variables' do
|
|
@@ -24,7 +24,7 @@ RSpec.describe Reek::SmellDetectors::UnusedParameters do
|
|
|
24
24
|
|
|
25
25
|
expect(src).
|
|
26
26
|
to reek_of(:UnusedParameters, lines: [1], name: 'bravo').
|
|
27
|
-
and reek_of(:UnusedParameters, lines: [1], name:
|
|
27
|
+
and reek_of(:UnusedParameters, lines: [1], name: 'charlie')
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
it 'reports nothing for no parameters' do
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
require_relative '
|
|
2
|
-
require_lib 'reek/
|
|
1
|
+
require_relative '../spec_helper'
|
|
2
|
+
require_lib 'reek/smell_warning'
|
|
3
3
|
|
|
4
|
-
RSpec.describe Reek::
|
|
4
|
+
RSpec.describe Reek::SmellWarning do
|
|
5
5
|
let(:duplication_detector) { build(:smell_detector, smell_type: 'DuplicateMethodCall') }
|
|
6
6
|
let(:feature_envy_detector) { build(:smell_detector, smell_type: 'FeatureEnvy') }
|
|
7
7
|
let(:utility_function_detector) { build(:smell_detector, smell_type: 'UtilityFunction') }
|
|
@@ -30,14 +30,14 @@ RSpec.describe Reek::SmellDetectors::SmellWarning do
|
|
|
30
30
|
let(:first) { build(:smell_warning, smell_detector: duplication_detector) }
|
|
31
31
|
let(:second) { build(:smell_warning, smell_detector: feature_envy_detector) }
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
it_behaves_like 'first sorts ahead of second'
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
context 'smells differing only by lines' do
|
|
37
37
|
let(:first) { build(:smell_warning, smell_detector: feature_envy_detector, lines: [2]) }
|
|
38
38
|
let(:second) { build(:smell_warning, smell_detector: feature_envy_detector, lines: [3]) }
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
it_behaves_like 'first sorts ahead of second'
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
context 'smells differing only by context' do
|
|
@@ -46,7 +46,7 @@ RSpec.describe Reek::SmellDetectors::SmellWarning do
|
|
|
46
46
|
build(:smell_warning, smell_detector: duplication_detector, context: 'second')
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
it_behaves_like 'first sorts ahead of second'
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
context 'smells differing only by message' do
|
|
@@ -59,7 +59,7 @@ RSpec.describe Reek::SmellDetectors::SmellWarning do
|
|
|
59
59
|
context: 'ctx', message: 'second message')
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
it_behaves_like 'first sorts ahead of second'
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
context 'smell name takes precedence over message' do
|
|
@@ -70,7 +70,7 @@ RSpec.describe Reek::SmellDetectors::SmellWarning do
|
|
|
70
70
|
build(:smell_warning, smell_detector: utility_function_detector, message: 'first message')
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
it_behaves_like 'first sorts ahead of second'
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
context 'smells differing everywhere' do
|
|
@@ -86,7 +86,7 @@ RSpec.describe Reek::SmellDetectors::SmellWarning do
|
|
|
86
86
|
message: "has the variable name '@s'")
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
it_behaves_like 'first sorts ahead of second'
|
|
90
90
|
end
|
|
91
91
|
end
|
|
92
92
|
|
|
@@ -26,36 +26,15 @@ RSpec.describe Reek::Source::SourceCode do
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
context 'when the parser fails' do
|
|
29
|
-
let(:catcher) { StringIO.new }
|
|
30
29
|
let(:source_name) { 'Test source' }
|
|
31
30
|
let(:error_message) { 'Error message' }
|
|
32
31
|
let(:parser) { class_double(Parser::Ruby23) }
|
|
33
32
|
let(:src) { described_class.new(code: '', origin: source_name, parser: parser) }
|
|
34
33
|
|
|
35
|
-
before { $stderr = catcher }
|
|
36
|
-
|
|
37
34
|
shared_examples_for 'handling and recording the error' do
|
|
38
|
-
it '
|
|
39
|
-
src.syntax_tree
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
it 'returns an empty syntax tree' do
|
|
43
|
-
expect(src.syntax_tree).to be_nil
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it 'records the syntax error' do
|
|
47
|
-
src.syntax_tree
|
|
48
|
-
expect(catcher.string).to match(error_class.name)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
it 'records the source name' do
|
|
52
|
-
src.syntax_tree
|
|
53
|
-
expect(catcher.string).to match(source_name)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
it 'records the error message' do
|
|
57
|
-
src.syntax_tree
|
|
58
|
-
expect(catcher.string).to match(error_message)
|
|
35
|
+
it 'raises an informative error' do
|
|
36
|
+
expect { src.syntax_tree }.
|
|
37
|
+
to raise_error(/#{source_name}: #{error_class.name}: #{error_message}/)
|
|
59
38
|
end
|
|
60
39
|
end
|
|
61
40
|
|
|
@@ -68,7 +47,7 @@ RSpec.describe Reek::Source::SourceCode do
|
|
|
68
47
|
and_raise error_class.new(diagnostic)
|
|
69
48
|
end
|
|
70
49
|
|
|
71
|
-
|
|
50
|
+
it_behaves_like 'handling and recording the error'
|
|
72
51
|
end
|
|
73
52
|
|
|
74
53
|
context 'with a Racc::ParseError' do
|
|
@@ -79,7 +58,7 @@ RSpec.describe Reek::Source::SourceCode do
|
|
|
79
58
|
and_raise(error_class.new(error_message))
|
|
80
59
|
end
|
|
81
60
|
|
|
82
|
-
|
|
61
|
+
it_behaves_like 'handling and recording the error'
|
|
83
62
|
end
|
|
84
63
|
|
|
85
64
|
context 'with a generic error' do
|
|
@@ -91,10 +70,8 @@ RSpec.describe Reek::Source::SourceCode do
|
|
|
91
70
|
end
|
|
92
71
|
|
|
93
72
|
it 'raises the error' do
|
|
94
|
-
expect { src.syntax_tree }.to raise_error
|
|
73
|
+
expect { src.syntax_tree }.to raise_error error_class
|
|
95
74
|
end
|
|
96
75
|
end
|
|
97
|
-
|
|
98
|
-
after { $stderr = STDERR }
|
|
99
76
|
end
|
|
100
77
|
end
|
|
@@ -29,34 +29,66 @@ RSpec.describe Reek::Source::SourceLocator do
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# rubocop:disable RSpec/NestedGroups
|
|
32
33
|
context 'exclude paths' do
|
|
33
34
|
let(:configuration) do
|
|
34
35
|
test_configuration_for(CONFIG_PATH.join('with_excluded_paths.reek'))
|
|
35
36
|
end
|
|
36
37
|
|
|
37
|
-
let(:
|
|
38
|
+
let(:options) { instance_double('Reek::CLI::Options', force_exclusion?: false) }
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
end
|
|
40
|
+
context 'when the path is a file name in an excluded directory' do
|
|
41
|
+
let(:path) { SAMPLES_PATH.join('source_with_exclude_paths', 'ignore_me', 'uncommunicative_method_name.rb') }
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
]
|
|
48
|
-
end
|
|
43
|
+
context 'when options.force_exclusion? is true' do
|
|
44
|
+
before do
|
|
45
|
+
allow(options).to receive(:force_exclusion?).and_return(true)
|
|
46
|
+
end
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
it 'excludes this file' do
|
|
49
|
+
sources = described_class.new([path], configuration: configuration, options: options).sources
|
|
50
|
+
expect(sources).not_to include(path)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context 'when options.force_exclusion? is false' do
|
|
55
|
+
before do
|
|
56
|
+
allow(options).to receive(:force_exclusion?).and_return(false)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'includes this file' do
|
|
60
|
+
sources = described_class.new([path], configuration: configuration, options: options).sources
|
|
61
|
+
expect(sources).to include(path)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
53
64
|
end
|
|
54
65
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
context 'when path is a directory' do
|
|
67
|
+
let(:path) { SAMPLES_PATH.join('source_with_exclude_paths') }
|
|
68
|
+
|
|
69
|
+
let(:expected_paths) do
|
|
70
|
+
[path.join('nested/uncommunicative_parameter_name.rb')]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
let(:paths_that_are_expected_to_be_ignored) do
|
|
74
|
+
[
|
|
75
|
+
path.join('ignore_me/uncommunicative_method_name.rb'),
|
|
76
|
+
path.join('nested/ignore_me_as_well/irresponsible_module.rb')
|
|
77
|
+
]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'does not use excluded paths' do
|
|
81
|
+
sources = described_class.new([path], configuration: configuration, options: options).sources
|
|
82
|
+
expect(sources).not_to include(*paths_that_are_expected_to_be_ignored)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'scans directories that are not excluded' do
|
|
86
|
+
sources = described_class.new([path], configuration: configuration).sources
|
|
87
|
+
expect(sources).to eq expected_paths
|
|
88
|
+
end
|
|
58
89
|
end
|
|
59
90
|
end
|
|
91
|
+
# rubocop:enable RSpec/NestedGroups
|
|
60
92
|
|
|
61
93
|
context 'non-Ruby paths' do
|
|
62
94
|
let(:path) { SAMPLES_PATH.join('source_with_non_ruby_files') }
|
|
@@ -133,7 +133,7 @@ RSpec.describe Reek::Spec::ShouldReekOf do
|
|
|
133
133
|
context 'for a smell that is disabled by default' do
|
|
134
134
|
before do
|
|
135
135
|
default_config = Reek::SmellDetectors::UnusedPrivateMethod.default_config
|
|
136
|
-
expect(default_config[Reek::
|
|
136
|
+
expect(default_config[Reek::SmellConfiguration::ENABLED_KEY]).to be_falsy
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
it 'enables the smell detector to match automatically' do
|
|
@@ -36,14 +36,14 @@ RSpec.describe Reek::Spec::ShouldReekOnlyOf do
|
|
|
36
36
|
context 'with no smells' do
|
|
37
37
|
let(:smells) { [] }
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
it_behaves_like 'no match'
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
context 'with 1 non-matching smell' do
|
|
43
43
|
let(:control_couple_detector) { build(:smell_detector, smell_type: 'ControlParameter') }
|
|
44
44
|
let(:smells) { [build(:smell_warning, smell_detector: control_couple_detector)] }
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
it_behaves_like 'no match'
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
context 'with 2 non-matching smells' do
|
|
@@ -56,7 +56,7 @@ RSpec.describe Reek::Spec::ShouldReekOnlyOf do
|
|
|
56
56
|
]
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
it_behaves_like 'no match'
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
context 'with 1 non-matching and 1 matching smell' do
|
|
@@ -70,7 +70,7 @@ RSpec.describe Reek::Spec::ShouldReekOnlyOf do
|
|
|
70
70
|
]
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
it_behaves_like 'no match'
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
context 'with 1 matching smell' do
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'pathname'
|
|
2
|
+
require 'timeout'
|
|
2
3
|
require_relative '../lib/reek'
|
|
3
4
|
require_relative '../lib/reek/spec'
|
|
4
5
|
require_relative '../lib/reek/ast/ast_node_class_map'
|
|
@@ -84,9 +85,9 @@ RSpec.configure do |config|
|
|
|
84
85
|
mocks.verify_doubled_constant_names = true
|
|
85
86
|
end
|
|
86
87
|
|
|
87
|
-
# Avoid infinitely running tests. This is mainly useful when running
|
|
88
|
-
# Set the DEBUG environment variable to something truthy
|
|
89
|
-
# this and allow using pry without specs failing.
|
|
88
|
+
# Avoid infinitely running tests. This is mainly useful when running a
|
|
89
|
+
# mutation tester. Set the DEBUG environment variable to something truthy
|
|
90
|
+
# like '1' to disable this and allow using pry without specs failing.
|
|
90
91
|
unless ENV['DEBUG']
|
|
91
92
|
config.around(:each) do |example|
|
|
92
93
|
Timeout.timeout(5, &example)
|
data/tasks/configuration.rake
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
require_relative '../lib/reek/
|
|
1
|
+
require_relative '../lib/reek/detector_repository'
|
|
2
2
|
require 'yaml'
|
|
3
3
|
|
|
4
4
|
namespace :configuration do
|
|
5
5
|
desc 'Updates the default configuration file when smell defaults change'
|
|
6
6
|
task :update_default_configuration do
|
|
7
7
|
DEFAULT_SMELL_CONFIGURATION = 'defaults.reek'.freeze
|
|
8
|
-
content = Reek::
|
|
8
|
+
content = Reek::DetectorRepository.smell_types.each_with_object({}) do |klass, hash|
|
|
9
9
|
hash[klass.smell_type] = klass.default_config
|
|
10
10
|
end
|
|
11
11
|
File.open(DEFAULT_SMELL_CONFIGURATION, 'w') { |file| YAML.dump(content, file) }
|