reek 4.0.0.pre1 → 4.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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +11 -2
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +3 -0
- data/README.md +2 -0
- data/docs/Attribute.md +1 -1
- data/docs/Uncommunicative-Method-Name.md +32 -2
- data/docs/Uncommunicative-Module-Name.md +29 -2
- data/docs/Uncommunicative-Parameter-Name.md +30 -2
- data/features/configuration_files/accept_setting.feature +70 -0
- data/features/configuration_files/exclude_directives.feature +34 -0
- data/features/configuration_files/mix_accept_reject_setting.feature +81 -0
- data/features/configuration_files/reject_setting.feature +78 -0
- data/features/configuration_files/unused_private_method.feature +66 -0
- data/lib/reek/configuration/app_configuration.rb +0 -30
- data/lib/reek/context/method_context.rb +15 -1
- data/lib/reek/smells/uncommunicative_method_name.rb +8 -7
- data/lib/reek/smells/uncommunicative_module_name.rb +8 -8
- data/lib/reek/smells/uncommunicative_parameter_name.rb +9 -7
- data/lib/reek/smells/unused_private_method.rb +7 -2
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +3 -4
- data/spec/reek/configuration/app_configuration_spec.rb +6 -27
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +72 -16
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +60 -47
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +55 -9
- data/spec/reek/smells/unused_parameters_spec.rb +9 -0
- data/spec/reek/smells/unused_private_method_spec.rb +38 -0
- data/spec/reek/smells/utility_function_spec.rb +3 -5
- data/spec/spec_helper.rb +28 -1
- metadata +11 -7
@@ -28,12 +28,12 @@ module Reek
|
|
28
28
|
# to be treated as exceptions; these names will not be reported as
|
29
29
|
# uncommunicative.
|
30
30
|
ACCEPT_KEY = 'accept'.freeze
|
31
|
-
|
31
|
+
DEFAULT_ACCEPT_PATTERNS = [].freeze
|
32
32
|
|
33
33
|
def self.default_config
|
34
|
-
super.merge(
|
34
|
+
super().merge(
|
35
35
|
REJECT_KEY => DEFAULT_REJECT_PATTERNS,
|
36
|
-
ACCEPT_KEY =>
|
36
|
+
ACCEPT_KEY => DEFAULT_ACCEPT_PATTERNS
|
37
37
|
)
|
38
38
|
end
|
39
39
|
|
@@ -66,16 +66,16 @@ module Reek
|
|
66
66
|
|
67
67
|
# :reek:ControlParameter
|
68
68
|
def acceptable_name?(context:, module_name:, fully_qualified_name:)
|
69
|
-
|
70
|
-
reject_patterns(context).none? { |
|
69
|
+
accept_patterns(context).any? { |accept_pattern| fully_qualified_name.match accept_pattern } ||
|
70
|
+
reject_patterns(context).none? { |reject_pattern| module_name.match reject_pattern }
|
71
71
|
end
|
72
72
|
|
73
73
|
def reject_patterns(context)
|
74
|
-
value(REJECT_KEY, context, DEFAULT_REJECT_PATTERNS)
|
74
|
+
Array value(REJECT_KEY, context, DEFAULT_REJECT_PATTERNS)
|
75
75
|
end
|
76
76
|
|
77
|
-
def
|
78
|
-
value(ACCEPT_KEY, context,
|
77
|
+
def accept_patterns(context)
|
78
|
+
Array value(ACCEPT_KEY, context, DEFAULT_ACCEPT_PATTERNS)
|
79
79
|
end
|
80
80
|
end
|
81
81
|
end
|
@@ -16,6 +16,8 @@ module Reek
|
|
16
16
|
# Currently +UncommunicativeParameterName+ checks for
|
17
17
|
# * 1-character names
|
18
18
|
# * names ending with a number
|
19
|
+
# * names beginning with an underscore
|
20
|
+
# * names containing a capital letter (assuming camelCase)
|
19
21
|
#
|
20
22
|
# See {file:docs/Uncommunicative-Parameter-Name.md} for details.
|
21
23
|
class UncommunicativeParameterName < SmellDetector
|
@@ -23,12 +25,12 @@ module Reek
|
|
23
25
|
DEFAULT_REJECT_PATTERNS = [/^.$/, /[0-9]$/, /[A-Z]/, /^_/].freeze
|
24
26
|
|
25
27
|
ACCEPT_KEY = 'accept'.freeze
|
26
|
-
|
28
|
+
DEFAULT_ACCEPT_PATTERNS = [].freeze
|
27
29
|
|
28
30
|
def self.default_config
|
29
31
|
super.merge(
|
30
32
|
REJECT_KEY => DEFAULT_REJECT_PATTERNS,
|
31
|
-
ACCEPT_KEY =>
|
33
|
+
ACCEPT_KEY => DEFAULT_ACCEPT_PATTERNS
|
32
34
|
)
|
33
35
|
end
|
34
36
|
|
@@ -58,16 +60,16 @@ module Reek
|
|
58
60
|
end
|
59
61
|
|
60
62
|
def acceptable_name?(name:, context:)
|
61
|
-
|
62
|
-
reject_patterns(context).none? { |
|
63
|
+
accept_patterns(context).any? { |accept_pattern| name.match accept_pattern } ||
|
64
|
+
reject_patterns(context).none? { |reject_pattern| name.match reject_pattern }
|
63
65
|
end
|
64
66
|
|
65
67
|
def reject_patterns(context)
|
66
|
-
value(REJECT_KEY, context, DEFAULT_REJECT_PATTERNS)
|
68
|
+
Array value(REJECT_KEY, context, DEFAULT_REJECT_PATTERNS)
|
67
69
|
end
|
68
70
|
|
69
|
-
def
|
70
|
-
value(ACCEPT_KEY, context,
|
71
|
+
def accept_patterns(context)
|
72
|
+
Array value(ACCEPT_KEY, context, DEFAULT_ACCEPT_PATTERNS)
|
71
73
|
end
|
72
74
|
|
73
75
|
# :reek:UtilityFunction
|
@@ -78,9 +78,14 @@ module Reek
|
|
78
78
|
# @param ctx [Context::ClassContext]
|
79
79
|
# @return [Boolean]
|
80
80
|
#
|
81
|
+
# :reek:FeatureEnvy
|
81
82
|
def ignore_method?(ctx, method)
|
82
|
-
|
83
|
-
|
83
|
+
# ignore_contexts will be e.g. ["Foo::Smelly#my_method", "..."]
|
84
|
+
ignore_contexts = value(EXCLUDE_KEY, ctx, DEFAULT_EXCLUDE_SET)
|
85
|
+
ignore_contexts.any? do |ignore_context|
|
86
|
+
full_name = "#{method.parent.full_name}##{method.name}"
|
87
|
+
full_name[ignore_context]
|
88
|
+
end
|
84
89
|
end
|
85
90
|
end
|
86
91
|
end
|
data/lib/reek/version.rb
CHANGED
data/reek.gemspec
CHANGED
@@ -7,10 +7,9 @@ Gem::Specification.new do |s|
|
|
7
7
|
|
8
8
|
s.authors = ['Kevin Rutherford', 'Timo Roessner', 'Matijs van Zuijlen', 'Piotr Szotkowski']
|
9
9
|
s.default_executable = 'reek'
|
10
|
-
s.description =
|
11
|
-
Reek is a tool that examines Ruby classes, modules and methods and reports
|
12
|
-
any code smells it finds.
|
13
|
-
DESC
|
10
|
+
s.description =
|
11
|
+
'Reek is a tool that examines Ruby classes, modules and methods and reports ' \
|
12
|
+
'any code smells it finds.'
|
14
13
|
|
15
14
|
s.license = 'MIT'
|
16
15
|
s.email = ['timo.roessner@googlemail.com']
|
@@ -57,28 +57,6 @@ RSpec.describe Reek::Configuration::AppConfiguration do
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
describe '#from_map' do
|
61
|
-
it 'properly sets the configuration from simple data structures' do
|
62
|
-
config = described_class.from_map(directory_directives: directory_directives_value,
|
63
|
-
default_directive: default_directive_value,
|
64
|
-
excluded_paths: exclude_paths_value)
|
65
|
-
|
66
|
-
expect(config.send(:excluded_paths)).to eq(expected_excluded_paths)
|
67
|
-
expect(config.send(:default_directive)).to eq(expected_default_directive)
|
68
|
-
expect(config.send(:directory_directives)).to eq(expected_directory_directives)
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'properly sets the configuration from native structures' do
|
72
|
-
config = described_class.from_map(directory_directives: expected_directory_directives,
|
73
|
-
default_directive: expected_default_directive,
|
74
|
-
excluded_paths: expected_excluded_paths)
|
75
|
-
|
76
|
-
expect(config.send(:excluded_paths)).to eq(expected_excluded_paths)
|
77
|
-
expect(config.send(:default_directive)).to eq(expected_default_directive)
|
78
|
-
expect(config.send(:directory_directives)).to eq(expected_directory_directives)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
60
|
describe '#from_hash' do
|
83
61
|
it 'sets the configuration a unified simple data structure' do
|
84
62
|
config = described_class.from_hash(combined_value)
|
@@ -104,7 +82,7 @@ RSpec.describe Reek::Configuration::AppConfiguration do
|
|
104
82
|
end
|
105
83
|
|
106
84
|
it 'returns the corresponding directive' do
|
107
|
-
configuration = described_class.
|
85
|
+
configuration = described_class.from_hash directory_directives
|
108
86
|
expect(configuration.directive_for(source_via)).to eq(bang_config)
|
109
87
|
end
|
110
88
|
end
|
@@ -120,11 +98,12 @@ RSpec.describe Reek::Configuration::AppConfiguration do
|
|
120
98
|
}
|
121
99
|
end
|
122
100
|
let(:source_via) { "#{directory}/dummy.rb" }
|
101
|
+
let(:configuration_as_hash) { directory_directives.merge(default_directive) }
|
123
102
|
|
124
103
|
it 'returns the directory directive with the default directive reverse-merged' do
|
125
|
-
configuration = described_class.
|
126
|
-
default_directive: default_directive
|
104
|
+
configuration = described_class.from_hash configuration_as_hash
|
127
105
|
actual = configuration.directive_for(source_via)
|
106
|
+
|
128
107
|
expect(actual[Reek::Smells::IrresponsibleModule]).to be_truthy
|
129
108
|
expect(actual[Reek::Smells::TooManyStatements]).to be_truthy
|
130
109
|
expect(actual[Reek::Smells::TooManyStatements][:max_statements]).to eq(8)
|
@@ -138,10 +117,10 @@ RSpec.describe Reek::Configuration::AppConfiguration do
|
|
138
117
|
let(:directory_directives) do
|
139
118
|
{ 'spec/samples/two_smelly_files' => attribute_config }
|
140
119
|
end
|
120
|
+
let(:configuration_as_hash) { directory_directives.merge(default_directive) }
|
141
121
|
|
142
122
|
it 'returns the default directive' do
|
143
|
-
configuration = described_class.
|
144
|
-
default_directive: default_directive
|
123
|
+
configuration = described_class.from_hash configuration_as_hash
|
145
124
|
expect(configuration.directive_for(source_via)).to eq(default_directive)
|
146
125
|
end
|
147
126
|
end
|
@@ -4,31 +4,87 @@ require_relative 'smell_detector_shared'
|
|
4
4
|
|
5
5
|
RSpec.describe Reek::Smells::UncommunicativeMethodName do
|
6
6
|
let(:detector) { build(:smell_detector, smell_type: :UncommunicativeMethodName) }
|
7
|
-
|
8
7
|
it_should_behave_like 'SmellDetector'
|
9
8
|
|
10
|
-
|
11
|
-
it
|
12
|
-
|
13
|
-
|
9
|
+
describe 'default configuration' do
|
10
|
+
it 'reports one-word names' do
|
11
|
+
expect('def a; end').to reek_of(:UncommunicativeMethodName)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'reports names ending with a digit' do
|
15
|
+
expect('def xyz1; end').to reek_of(:UncommunicativeMethodName)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'reports camelcased names' do
|
19
|
+
expect('def aBBa; end').to reek_of(:UncommunicativeMethodName)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'does not report one-letter special characters' do
|
23
|
+
['+', '-', '/', '*'].each do |symbol|
|
24
|
+
expect("def #{symbol}; end").not_to reek_of(:UncommunicativeMethodName)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'inspect' do
|
30
|
+
let(:source) { 'def x; end' }
|
31
|
+
let(:context) { code_context(source) }
|
32
|
+
let(:detector) { build(:smell_detector, smell_type: :UncommunicativeMethodName) }
|
33
|
+
|
34
|
+
it 'returns an array of smell warnings' do
|
35
|
+
smells = detector.inspect(context)
|
36
|
+
expect(smells.length).to eq(1)
|
37
|
+
expect(smells[0]).to be_a_kind_of(Reek::Smells::SmellWarning)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'contains proper smell warnings' do
|
41
|
+
smells = detector.inspect(context)
|
42
|
+
warning = smells[0]
|
43
|
+
|
44
|
+
expect(warning.smell_type).to eq(Reek::Smells::UncommunicativeMethodName.smell_type)
|
45
|
+
expect(warning.parameters[:name]).to eq('x')
|
46
|
+
expect(warning.context).to match(/#{warning.parameters[:name]}/)
|
47
|
+
expect(warning.lines).to eq([1])
|
14
48
|
end
|
15
49
|
end
|
16
50
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
51
|
+
describe '`accept` patterns' do
|
52
|
+
let(:source) { 'def x; end' }
|
53
|
+
|
54
|
+
it 'make smelly names pass via regex / strings given by list / literal' do
|
55
|
+
[[/x/], /x/, ['x'], 'x'].each do |pattern|
|
56
|
+
configuration = accept_configuration_for(described_class, pattern: pattern)
|
57
|
+
expect(source).to_not reek_of(described_class, {}, configuration)
|
23
58
|
end
|
59
|
+
end
|
60
|
+
end
|
24
61
|
|
25
|
-
|
62
|
+
describe '`reject` patterns' do
|
63
|
+
let(:source) { 'def helper; end' }
|
26
64
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
expect(
|
65
|
+
it 'reject smelly names via regex / strings given by list / literal' do
|
66
|
+
[[/helper/], /helper/, ['helper'], 'helper'].each do |pattern|
|
67
|
+
configuration = reject_configuration_for(described_class, pattern: pattern)
|
68
|
+
expect(source).to reek_of(described_class, {}, configuration)
|
31
69
|
end
|
32
70
|
end
|
33
71
|
end
|
72
|
+
|
73
|
+
describe '.default_config' do
|
74
|
+
it 'should merge in the default accept and reject patterns' do
|
75
|
+
expected = {
|
76
|
+
'enabled' => true,
|
77
|
+
'exclude' => [],
|
78
|
+
'reject' => [/^[a-z]$/, /[0-9]$/, /[A-Z]/],
|
79
|
+
'accept' => []
|
80
|
+
}
|
81
|
+
expect(described_class.default_config).to eq(expected)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '.contexts' do
|
86
|
+
it 'should be scoped to classes and modules' do
|
87
|
+
expect(described_class.contexts).to eq([:def, :defs])
|
88
|
+
end
|
89
|
+
end
|
34
90
|
end
|
@@ -5,74 +5,87 @@ require_lib 'reek/context/code_context'
|
|
5
5
|
|
6
6
|
RSpec.describe Reek::Smells::UncommunicativeModuleName do
|
7
7
|
let(:detector) { build(:smell_detector, smell_type: :UncommunicativeModuleName) }
|
8
|
-
|
9
8
|
it_should_behave_like 'SmellDetector'
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
describe 'default configuration' do
|
11
|
+
['class', 'module'].each do |type|
|
12
|
+
it 'does not report one-word name' do
|
13
|
+
expect("#{type} Helper; end").not_to reek_of(:UncommunicativeModuleName)
|
14
|
+
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
it 'reports one-letter name' do
|
17
|
+
expect("#{type} X; end").to reek_of(:UncommunicativeModuleName, name: 'X')
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
it 'reports name of the form "x2"' do
|
21
|
+
expect("#{type} X2; end").to reek_of(:UncommunicativeModuleName, name: 'X2')
|
22
|
+
end
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
it 'reports long name ending in a number' do
|
25
|
+
expect("#{type} Printer2; end").to reek_of(:UncommunicativeModuleName, name: 'Printer2')
|
26
|
+
end
|
26
27
|
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'inspect' do
|
31
|
+
let(:source) { 'class Foo::X; end' }
|
32
|
+
let(:context) { code_context(source) }
|
33
|
+
let(:detector) { build(:smell_detector, smell_type: :UncommunicativeModuleName) }
|
27
34
|
|
28
|
-
it '
|
29
|
-
|
30
|
-
ctx = Reek::Context::CodeContext.new(nil, Reek::Source::SourceCode.from(src).syntax_tree)
|
31
|
-
smells = detector.inspect(ctx)
|
35
|
+
it 'returns an array of smell warnings' do
|
36
|
+
smells = detector.inspect(context)
|
32
37
|
expect(smells.length).to eq(1)
|
33
|
-
expect(smells[0]
|
34
|
-
expect(smells[0].parameters[:name]).to eq('X')
|
35
|
-
expect(smells[0].context).to match(/#{smells[0].parameters[:name]}/)
|
38
|
+
expect(smells[0]).to be_a_kind_of(Reek::Smells::SmellWarning)
|
36
39
|
end
|
37
|
-
end
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
}
|
48
|
-
Reek::Configuration::AppConfiguration.from_map(default_directive_for_smell)
|
41
|
+
it 'contains proper smell warnings' do
|
42
|
+
smells = detector.inspect(context)
|
43
|
+
warning = smells[0]
|
44
|
+
|
45
|
+
expect(warning.smell_type).to eq(Reek::Smells::UncommunicativeModuleName.smell_type)
|
46
|
+
expect(warning.parameters[:name]).to eq('X')
|
47
|
+
expect(warning.context).to match(/#{warning.parameters[:name]}/)
|
48
|
+
expect(warning.lines).to eq([1])
|
49
49
|
end
|
50
|
+
end
|
50
51
|
|
51
|
-
|
52
|
-
|
52
|
+
describe '`accept` patterns' do
|
53
|
+
let(:source) { 'class Classy1; end' }
|
53
54
|
|
54
|
-
|
55
|
+
it 'make smelly names pass via regex / strings given by list / literal' do
|
56
|
+
[[/lassy/], /lassy/, ['lassy'], 'lassy'].each do |pattern|
|
57
|
+
configuration = accept_configuration_for(described_class, pattern: pattern)
|
58
|
+
expect(source).to_not reek_of(described_class, {}, configuration)
|
59
|
+
end
|
55
60
|
end
|
61
|
+
end
|
56
62
|
|
57
|
-
|
58
|
-
|
63
|
+
describe '`reject` patterns' do
|
64
|
+
let(:source) { 'class BaseHelper; end' }
|
59
65
|
|
60
|
-
|
66
|
+
it 'reject smelly names via regex / strings given by list / literal' do
|
67
|
+
[[/Helper/], /Helper/, ['Helper'], 'Helper'].each do |pattern|
|
68
|
+
configuration = reject_configuration_for(described_class, pattern: pattern)
|
69
|
+
expect(source).to reek_of(described_class, {}, configuration)
|
70
|
+
end
|
61
71
|
end
|
62
72
|
end
|
63
73
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
74
|
+
describe '.default_config' do
|
75
|
+
it 'should merge in the default accept and reject patterns' do
|
76
|
+
expected = {
|
77
|
+
'enabled' => true,
|
78
|
+
'exclude' => [],
|
79
|
+
'reject' => [/^.$/, /[0-9]$/],
|
80
|
+
'accept' => []
|
81
|
+
}
|
82
|
+
expect(described_class.default_config).to eq(expected)
|
69
83
|
end
|
84
|
+
end
|
70
85
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
expect(warning.parameters[:name]).to eq('Printer2')
|
75
|
-
expect(warning.lines).to eq([1])
|
86
|
+
describe '.contexts' do
|
87
|
+
it 'should be scoped to classes and modules' do
|
88
|
+
expect(described_class.contexts).to eq([:module, :class])
|
76
89
|
end
|
77
90
|
end
|
78
91
|
end
|
@@ -5,7 +5,6 @@ require_lib 'reek/context/method_context'
|
|
5
5
|
|
6
6
|
RSpec.describe Reek::Smells::UncommunicativeParameterName do
|
7
7
|
let(:detector) { build(:smell_detector, smell_type: :UncommunicativeParameterName) }
|
8
|
-
|
9
8
|
it_should_behave_like 'SmellDetector'
|
10
9
|
|
11
10
|
{ 'obj.' => 'with a receiver',
|
@@ -73,18 +72,65 @@ RSpec.describe Reek::Smells::UncommunicativeParameterName do
|
|
73
72
|
end
|
74
73
|
end
|
75
74
|
|
76
|
-
|
77
|
-
let(:
|
78
|
-
|
79
|
-
|
80
|
-
|
75
|
+
describe 'inspect' do
|
76
|
+
let(:source) { 'def foo(bar2); baz(bar2); end' }
|
77
|
+
let(:context) { method_context(source) }
|
78
|
+
let(:detector) { build(:smell_detector, smell_type: :UncommunicativeParameterName) }
|
79
|
+
|
80
|
+
it 'returns an array of smell warnings' do
|
81
|
+
smells = detector.inspect(context)
|
82
|
+
expect(smells.length).to eq(1)
|
83
|
+
expect(smells[0]).to be_a_kind_of(Reek::Smells::SmellWarning)
|
81
84
|
end
|
82
85
|
|
83
|
-
|
86
|
+
it 'contains proper smell warnings' do
|
87
|
+
smells = detector.inspect(context)
|
88
|
+
warning = smells[0]
|
84
89
|
|
85
|
-
|
86
|
-
expect(warning.parameters[:name]).to eq('
|
90
|
+
expect(warning.smell_type).to eq(Reek::Smells::UncommunicativeParameterName.smell_type)
|
91
|
+
expect(warning.parameters[:name]).to eq('bar2')
|
92
|
+
expect(warning.context).to match('foo')
|
87
93
|
expect(warning.lines).to eq([1])
|
88
94
|
end
|
89
95
|
end
|
96
|
+
|
97
|
+
describe '`accept` patterns' do
|
98
|
+
let(:source) { 'def foo(bar2); baz(bar2); end' }
|
99
|
+
|
100
|
+
it 'make smelly names pass via regex / strings given by list / literal' do
|
101
|
+
[[/bar2/], /bar2/, ['bar2'], 'bar2'].each do |pattern|
|
102
|
+
configuration = accept_configuration_for(described_class, pattern: pattern)
|
103
|
+
expect(source).to_not reek_of(described_class, {}, configuration)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '`reject` patterns' do
|
109
|
+
let(:source) { 'def foo(bar); baz(bar); end' }
|
110
|
+
|
111
|
+
it 'reject smelly names via regex / strings given by list / literal' do
|
112
|
+
[[/bar/], /bar/, ['bar'], 'bar'].each do |pattern|
|
113
|
+
configuration = reject_configuration_for(described_class, pattern: pattern)
|
114
|
+
expect(source).to reek_of(described_class, {}, configuration)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '.default_config' do
|
120
|
+
it 'should merge in the default accept and reject patterns' do
|
121
|
+
expected = {
|
122
|
+
'enabled' => true,
|
123
|
+
'exclude' => [],
|
124
|
+
'reject' => [/^.$/, /[0-9]$/, /[A-Z]/, /^_/],
|
125
|
+
'accept' => []
|
126
|
+
}
|
127
|
+
expect(described_class.default_config).to eq(expected)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '.contexts' do
|
132
|
+
it 'should be scoped to classes and modules' do
|
133
|
+
expect(described_class.contexts).to eq([:def, :defs])
|
134
|
+
end
|
135
|
+
end
|
90
136
|
end
|
@@ -66,5 +66,14 @@ RSpec.describe Reek::Smells::UnusedParameters do
|
|
66
66
|
expect('def simple(var, kw: :val, **args); @var, @kw, @args = var, kw, args; end').
|
67
67
|
not_to reek_of(:UnusedParameters)
|
68
68
|
end
|
69
|
+
|
70
|
+
it 'reports nothing when using a parameter via self assignment' do
|
71
|
+
expect('def simple(counter); counter += 1; end').not_to reek_of(:UnusedParameters)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'reports nothing when using a parameter on a rescue' do
|
75
|
+
expect('def simple(tries = 3); puts "nothing"; rescue; retry if tries -= 1 > 0; raise; end').
|
76
|
+
not_to reek_of(:UnusedParameters)
|
77
|
+
end
|
69
78
|
end
|
70
79
|
end
|
@@ -115,4 +115,42 @@ RSpec.describe Reek::Smells::UnusedPrivateMethod do
|
|
115
115
|
expect(source).not_to reek_of(:UnusedPrivateMethod)
|
116
116
|
end
|
117
117
|
end
|
118
|
+
|
119
|
+
describe 'prevent methods from being reported' do
|
120
|
+
let(:source) do
|
121
|
+
<<-EOF
|
122
|
+
class Car
|
123
|
+
private
|
124
|
+
def start; end
|
125
|
+
def drive; end
|
126
|
+
end
|
127
|
+
EOF
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'excludes them via direct match in the app configuration' do
|
131
|
+
configuration = test_configuration_for(
|
132
|
+
described_class =>
|
133
|
+
{
|
134
|
+
Reek::Smells::SmellConfiguration::ENABLED_KEY => true,
|
135
|
+
Reek::Smells::SmellDetector::EXCLUDE_KEY => ['Car#drive']
|
136
|
+
}
|
137
|
+
)
|
138
|
+
|
139
|
+
expect(source).to reek_of(:UnusedPrivateMethod, { name: :start }, configuration)
|
140
|
+
expect(source).not_to reek_of(:UnusedPrivateMethod, { name: :drive }, configuration)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'excludes them via regex in the app configuration' do
|
144
|
+
configuration = test_configuration_for(
|
145
|
+
described_class =>
|
146
|
+
{
|
147
|
+
Reek::Smells::SmellConfiguration::ENABLED_KEY => true,
|
148
|
+
Reek::Smells::SmellDetector::EXCLUDE_KEY => [/drive/]
|
149
|
+
}
|
150
|
+
)
|
151
|
+
|
152
|
+
expect(source).to reek_of(:UnusedPrivateMethod, { name: :start }, configuration)
|
153
|
+
expect(source).not_to reek_of(:UnusedPrivateMethod, { name: :drive }, configuration)
|
154
|
+
end
|
155
|
+
end
|
118
156
|
end
|
@@ -220,13 +220,11 @@ RSpec.describe Reek::Smells::UtilityFunction do
|
|
220
220
|
describe 'disabling UtilityFunction via configuration for non-public methods' do
|
221
221
|
let(:configuration) do
|
222
222
|
default_directive = {
|
223
|
-
|
224
|
-
Reek::Smells::UtilityFunction =>
|
225
|
-
Reek::Smells::UtilityFunction::PUBLIC_METHODS_ONLY_KEY => true
|
226
|
-
}
|
223
|
+
Reek::Smells::UtilityFunction => {
|
224
|
+
Reek::Smells::UtilityFunction::PUBLIC_METHODS_ONLY_KEY => true
|
227
225
|
}
|
228
226
|
}
|
229
|
-
Reek::Configuration::AppConfiguration.
|
227
|
+
Reek::Configuration::AppConfiguration.from_hash(default_directive)
|
230
228
|
end
|
231
229
|
|
232
230
|
context 'public methods' do
|
data/spec/spec_helper.rb
CHANGED
@@ -27,7 +27,7 @@ module Helpers
|
|
27
27
|
when Pathname
|
28
28
|
configuration = Reek::Configuration::AppConfiguration.from_path(config)
|
29
29
|
when Hash
|
30
|
-
configuration = Reek::Configuration::AppConfiguration.
|
30
|
+
configuration = Reek::Configuration::AppConfiguration.from_hash config
|
31
31
|
else
|
32
32
|
raise "Unknown config given in `test_configuration_for`: #{config.inspect}"
|
33
33
|
end
|
@@ -41,6 +41,33 @@ module Helpers
|
|
41
41
|
Reek::Source::SourceCode.from(code).syntax_tree
|
42
42
|
end
|
43
43
|
|
44
|
+
# @param code [String] The given code.
|
45
|
+
#
|
46
|
+
# @return syntax_tree [Reek::Context::CodeContext]
|
47
|
+
def code_context(code)
|
48
|
+
Reek::Context::CodeContext.new(nil, syntax_tree(code))
|
49
|
+
end
|
50
|
+
|
51
|
+
# @param code [String] The given code.
|
52
|
+
#
|
53
|
+
# @return syntax_tree [Reek::Context::MethodContext]
|
54
|
+
def method_context(code)
|
55
|
+
Reek::Context::MethodContext.new(nil, syntax_tree(code))
|
56
|
+
end
|
57
|
+
|
58
|
+
# Helper methods to generate a configuration for smell types that support
|
59
|
+
# `accept` and `reject` settings.
|
60
|
+
%w(accept reject).each do |switch|
|
61
|
+
define_method("#{switch}_configuration_for") do |smell_type, pattern:|
|
62
|
+
hash = {
|
63
|
+
smell_type => {
|
64
|
+
switch => pattern
|
65
|
+
}
|
66
|
+
}
|
67
|
+
Reek::Configuration::AppConfiguration.from_hash(hash)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
44
71
|
# :reek:UncommunicativeMethodName
|
45
72
|
def sexp(type, *children)
|
46
73
|
@klass_map ||= Reek::AST::ASTNodeClassMap.new
|