reek 6.0.0 → 6.0.3
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/.github/dependabot.yml +9 -0
- data/.github/workflows/ruby.yml +52 -0
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +27 -20
- data/CHANGELOG.md +16 -0
- data/Gemfile +5 -6
- data/README.md +10 -4
- data/docs/Boolean-Parameter.md +2 -2
- data/docs/templates/default/docstring/setup.rb +1 -3
- data/features/command_line_interface/options.feature +2 -2
- data/features/configuration_files/schema_validation.feature +1 -1
- data/features/reports/json.feature +3 -3
- data/features/reports/reports.feature +4 -4
- data/features/reports/yaml.feature +3 -3
- data/features/step_definitions/reek_steps.rb +1 -1
- data/features/step_definitions/sample_file_steps.rb +2 -2
- data/features/support/env.rb +0 -1
- data/lib/reek/ast/node.rb +1 -1
- data/lib/reek/cli/options.rb +1 -1
- data/lib/reek/configuration/app_configuration.rb +4 -3
- data/lib/reek/configuration/configuration_converter.rb +2 -2
- data/lib/reek/configuration/directory_directives.rb +9 -3
- data/lib/reek/configuration/excluded_paths.rb +2 -1
- data/lib/reek/context/code_context.rb +1 -1
- data/lib/reek/context/module_context.rb +3 -1
- data/lib/reek/context/refinement_context.rb +16 -0
- data/lib/reek/context_builder.rb +16 -2
- data/lib/reek/report/code_climate/code_climate_configuration.yml +1 -1
- data/lib/reek/smell_detectors/base_detector.rb +1 -0
- data/lib/reek/smell_detectors/boolean_parameter.rb +3 -1
- data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +1 -1
- data/lib/reek/smell_warning.rb +1 -2
- data/lib/reek/source/source_locator.rb +13 -10
- data/lib/reek/spec/smell_matcher.rb +2 -1
- data/lib/reek/version.rb +1 -1
- data/lib/reek.rb +1 -0
- data/reek.gemspec +10 -2
- data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +2 -4
- data/spec/quality/documentation_spec.rb +2 -1
- data/spec/reek/code_comment_spec.rb +20 -23
- data/spec/reek/configuration/directory_directives_spec.rb +6 -0
- data/spec/reek/configuration/excluded_paths_spec.rb +12 -3
- data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +1 -3
- data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +26 -26
- data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
- data/spec/reek/report/location_formatter_spec.rb +3 -3
- data/spec/reek/smell_detectors/base_detector_spec.rb +3 -3
- data/spec/reek/smell_detectors/utility_function_spec.rb +16 -0
- data/spec/reek/smell_warning_spec.rb +12 -12
- data/spec/reek/spec/should_reek_of_spec.rb +0 -1
- data/spec/reek/spec/should_reek_only_of_spec.rb +6 -6
- data/spec/reek/spec/smell_matcher_spec.rb +1 -1
- data/spec/spec_helper.rb +18 -5
- data/tasks/configuration.rake +1 -2
- metadata +21 -27
- data/.travis.yml +0 -36
- data/spec/factories/factories.rb +0 -37
|
@@ -14,6 +14,8 @@ module Reek
|
|
|
14
14
|
#
|
|
15
15
|
# See {file:docs/Boolean-Parameter.md} for details.
|
|
16
16
|
class BooleanParameter < BaseDetector
|
|
17
|
+
BOOLEAN_VALUES = [:true, :false].freeze
|
|
18
|
+
|
|
17
19
|
#
|
|
18
20
|
# Checks whether the given method has any Boolean parameters.
|
|
19
21
|
#
|
|
@@ -21,7 +23,7 @@ module Reek
|
|
|
21
23
|
#
|
|
22
24
|
def sniff
|
|
23
25
|
context.default_assignments.select do |_parameter, value|
|
|
24
|
-
|
|
26
|
+
BOOLEAN_VALUES.include?(value.type)
|
|
25
27
|
end.map do |parameter, _value|
|
|
26
28
|
smell_warning(
|
|
27
29
|
lines: [source_line],
|
data/lib/reek/smell_warning.rb
CHANGED
|
@@ -31,8 +31,7 @@ module Reek
|
|
|
31
31
|
# public API.
|
|
32
32
|
#
|
|
33
33
|
# @quality :reek:LongParameterList { max_params: 6 }
|
|
34
|
-
def initialize(smell_type, context: '',
|
|
35
|
-
source:, parameters: {})
|
|
34
|
+
def initialize(smell_type, lines:, message:, source:, context: '', parameters: {})
|
|
36
35
|
@smell_type = smell_type
|
|
37
36
|
@source = source
|
|
38
37
|
@context = context.to_s
|
|
@@ -33,23 +33,26 @@ module Reek
|
|
|
33
33
|
|
|
34
34
|
attr_reader :configuration, :paths, :options
|
|
35
35
|
|
|
36
|
-
# @quality :reek:TooManyStatements { max_statements: 7 }
|
|
37
|
-
# @quality :reek:NestedIterators { max_allowed_nesting: 2 }
|
|
38
36
|
def source_paths
|
|
39
37
|
paths.each_with_object([]) do |given_path, relevant_paths|
|
|
40
|
-
|
|
38
|
+
if given_path.exist?
|
|
39
|
+
relevant_paths.concat source_files_from_path(given_path)
|
|
40
|
+
else
|
|
41
41
|
print_no_such_file_error(given_path)
|
|
42
|
-
next
|
|
43
42
|
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
def source_files_from_path(given_path)
|
|
47
|
+
relevant_paths = []
|
|
48
|
+
given_path.find do |path|
|
|
49
|
+
if path.directory?
|
|
50
|
+
Find.prune if ignore_path?(path)
|
|
51
|
+
elsif ruby_file?(path)
|
|
52
|
+
relevant_paths << path unless ignore_file?(path)
|
|
51
53
|
end
|
|
52
54
|
end
|
|
55
|
+
relevant_paths
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
def ignore_file?(path)
|
|
@@ -43,8 +43,9 @@ module Reek
|
|
|
43
43
|
raise ArgumentError, "The attribute '#{extra_keys.first}' is not available for comparison"
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
# :reek:FeatureEnvy
|
|
46
47
|
def common_parameters_equal?(other_parameters)
|
|
47
|
-
smell_warning.parameters.
|
|
48
|
+
smell_warning.parameters.values_at(*other_parameters.keys) == other_parameters.values
|
|
48
49
|
end
|
|
49
50
|
|
|
50
51
|
def common_attributes_equal?(attributes)
|
data/lib/reek/version.rb
CHANGED
data/lib/reek.rb
CHANGED
|
@@ -8,6 +8,7 @@ require_relative 'reek/examiner'
|
|
|
8
8
|
require_relative 'reek/report'
|
|
9
9
|
|
|
10
10
|
module Reek
|
|
11
|
+
DEFAULT_SMELL_CONFIGURATION = File.join(__dir__, '../docs/defaults.reek.yml').freeze
|
|
11
12
|
DEFAULT_CONFIGURATION_FILE_NAME = '.reek.yml'
|
|
12
13
|
DETECTORS_KEY = 'detectors'
|
|
13
14
|
EXCLUDE_PATHS_KEY = 'exclude_paths'
|
data/reek.gemspec
CHANGED
|
@@ -19,8 +19,16 @@ Gem::Specification.new do |s|
|
|
|
19
19
|
s.required_ruby_version = '>= 2.4.0'
|
|
20
20
|
s.summary = 'Code smell detector for Ruby'
|
|
21
21
|
|
|
22
|
+
s.metadata = {
|
|
23
|
+
'homepage_uri' => 'https://github.com/troessner/reek',
|
|
24
|
+
'source_code_uri' => 'https://github.com/troessner/reek',
|
|
25
|
+
'bug_tracker_uri' => 'https://github.com/troessner/reek/issues',
|
|
26
|
+
'changelog_uri' => 'https://github.com/troessner/reek/CHANGELOG.md',
|
|
27
|
+
'documentation_uri' => 'https://www.rubydoc.info/gems/reek'
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
s.add_runtime_dependency 'kwalify', '~> 0.7.0'
|
|
23
|
-
s.add_runtime_dependency 'parser', '
|
|
24
|
-
s.add_runtime_dependency 'psych', '~> 3.1
|
|
31
|
+
s.add_runtime_dependency 'parser', '~> 3.0.0'
|
|
32
|
+
s.add_runtime_dependency 'psych', '~> 3.1'
|
|
25
33
|
s.add_runtime_dependency 'rainbow', '>= 2.0', '< 4.0'
|
|
26
34
|
end
|
|
@@ -6,10 +6,8 @@ RSpec.describe 'Runtime speed' do
|
|
|
6
6
|
|
|
7
7
|
it 'runs on our smelly sources in less than 5 seconds' do
|
|
8
8
|
expect do
|
|
9
|
-
source_directory.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
examiner = Reek::Examiner.new entry.to_path
|
|
9
|
+
Dir[source_directory.join('**/*.rb')].each do |entry|
|
|
10
|
+
examiner = Reek::Examiner.new Pathname.new(entry)
|
|
13
11
|
examiner.smells.size
|
|
14
12
|
end
|
|
15
13
|
end.to perform_under(5).sec
|
|
@@ -4,6 +4,7 @@ require 'kramdown'
|
|
|
4
4
|
RSpec.describe 'Documentation' do
|
|
5
5
|
root = File.expand_path('../..', __dir__)
|
|
6
6
|
files = Dir.glob(File.join(root, '*.md')) + Dir.glob(File.join(root, 'docs', '*.md'))
|
|
7
|
+
code_types = [:codeblock, :codespan]
|
|
7
8
|
|
|
8
9
|
files.each do |file|
|
|
9
10
|
describe "from #{file}" do
|
|
@@ -13,7 +14,7 @@ RSpec.describe 'Documentation' do
|
|
|
13
14
|
|
|
14
15
|
blocks.each do |block|
|
|
15
16
|
# Only consider code blocks with language 'ruby'.
|
|
16
|
-
next unless
|
|
17
|
+
next unless code_types.include?(block.type)
|
|
17
18
|
next unless block.attr['class'] == 'language-ruby'
|
|
18
19
|
|
|
19
20
|
it "has a valid sample at #{block.options[:location] + 1}" do
|
|
@@ -3,7 +3,7 @@ require_lib 'reek/code_comment'
|
|
|
3
3
|
|
|
4
4
|
RSpec.describe Reek::CodeComment do
|
|
5
5
|
context 'with an empty comment' do
|
|
6
|
-
let(:comment) {
|
|
6
|
+
let(:comment) { build_code_comment(comment: '') }
|
|
7
7
|
|
|
8
8
|
it 'is not descriptive' do
|
|
9
9
|
expect(comment).not_to be_descriptive
|
|
@@ -16,22 +16,22 @@ RSpec.describe Reek::CodeComment do
|
|
|
16
16
|
|
|
17
17
|
describe '#descriptive' do
|
|
18
18
|
it 'rejects an empty comment' do
|
|
19
|
-
comment =
|
|
19
|
+
comment = build_code_comment(comment: '#')
|
|
20
20
|
expect(comment).not_to be_descriptive
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
it 'rejects a 1-word comment' do
|
|
24
|
-
comment =
|
|
24
|
+
comment = build_code_comment(comment: "# alpha\n# ")
|
|
25
25
|
expect(comment).not_to be_descriptive
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
it 'accepts a 2-word comment' do
|
|
29
|
-
comment =
|
|
29
|
+
comment = build_code_comment(comment: '# alpha bravo ')
|
|
30
30
|
expect(comment).to be_descriptive
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
it 'accepts a multi-word comment' do
|
|
34
|
-
comment =
|
|
34
|
+
comment = build_code_comment(comment: "# alpha bravo \n# charlie \n # delta ")
|
|
35
35
|
expect(comment).to be_descriptive
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -39,8 +39,7 @@ RSpec.describe Reek::CodeComment do
|
|
|
39
39
|
describe 'good comment config' do
|
|
40
40
|
it 'parses hashed options' do
|
|
41
41
|
comment = '# :reek:DuplicateMethodCall { max_calls: 3 }'
|
|
42
|
-
config =
|
|
43
|
-
comment: comment).config
|
|
42
|
+
config = build_code_comment(comment: comment).config
|
|
44
43
|
|
|
45
44
|
expect(config).to include('DuplicateMethodCall')
|
|
46
45
|
expect(config['DuplicateMethodCall']).to have_key 'max_calls'
|
|
@@ -52,7 +51,7 @@ RSpec.describe Reek::CodeComment do
|
|
|
52
51
|
# :reek:DuplicateMethodCall { max_calls: 3 }
|
|
53
52
|
# :reek:NestedIterators { enabled: true }
|
|
54
53
|
RUBY
|
|
55
|
-
config =
|
|
54
|
+
config = build_code_comment(comment: comment).config
|
|
56
55
|
|
|
57
56
|
expect(config).to include('DuplicateMethodCall', 'NestedIterators')
|
|
58
57
|
expect(config['DuplicateMethodCall']['max_calls']).to eq 3
|
|
@@ -63,7 +62,7 @@ RSpec.describe Reek::CodeComment do
|
|
|
63
62
|
comment = <<-RUBY
|
|
64
63
|
#:reek:DuplicateMethodCall { max_calls: 3 } and :reek:NestedIterators { enabled: true }
|
|
65
64
|
RUBY
|
|
66
|
-
config =
|
|
65
|
+
config = build_code_comment(comment: comment).config
|
|
67
66
|
|
|
68
67
|
expect(config).to include('DuplicateMethodCall', 'NestedIterators')
|
|
69
68
|
expect(config['DuplicateMethodCall']['max_calls']).to eq 3
|
|
@@ -73,7 +72,7 @@ RSpec.describe Reek::CodeComment do
|
|
|
73
72
|
|
|
74
73
|
it 'parses multiple unhashed options on the same line' do
|
|
75
74
|
comment = '# :reek:DuplicateMethodCall and :reek:NestedIterators'
|
|
76
|
-
config =
|
|
75
|
+
config = build_code_comment(comment: comment).config
|
|
77
76
|
|
|
78
77
|
expect(config).to include('DuplicateMethodCall', 'NestedIterators')
|
|
79
78
|
expect(config['DuplicateMethodCall']).to include('enabled')
|
|
@@ -84,7 +83,7 @@ RSpec.describe Reek::CodeComment do
|
|
|
84
83
|
|
|
85
84
|
it 'disables the smell if no options are specifed' do
|
|
86
85
|
comment = '# :reek:DuplicateMethodCall'
|
|
87
|
-
config =
|
|
86
|
+
config = build_code_comment(comment: comment).config
|
|
88
87
|
|
|
89
88
|
expect(config).to include('DuplicateMethodCall')
|
|
90
89
|
expect(config['DuplicateMethodCall']).to include('enabled')
|
|
@@ -93,14 +92,13 @@ RSpec.describe Reek::CodeComment do
|
|
|
93
92
|
|
|
94
93
|
it 'does not disable the smell if options are specifed' do
|
|
95
94
|
comment = '# :reek:DuplicateMethodCall { max_calls: 3 }'
|
|
96
|
-
config =
|
|
95
|
+
config = build_code_comment(comment: comment).config
|
|
97
96
|
|
|
98
97
|
expect(config['DuplicateMethodCall']).not_to include('enabled')
|
|
99
98
|
end
|
|
100
99
|
|
|
101
100
|
it 'ignores smells after a space' do
|
|
102
|
-
config =
|
|
103
|
-
comment: '# :reek: DuplicateMethodCall').config
|
|
101
|
+
config = build_code_comment(comment: '# :reek: DuplicateMethodCall').config
|
|
104
102
|
expect(config).not_to include('DuplicateMethodCall')
|
|
105
103
|
end
|
|
106
104
|
|
|
@@ -111,7 +109,7 @@ RSpec.describe Reek::CodeComment do
|
|
|
111
109
|
# :reek:NestedIterators { enabled: true }
|
|
112
110
|
# comment
|
|
113
111
|
RUBY
|
|
114
|
-
comment =
|
|
112
|
+
comment = build_code_comment(comment: original_comment)
|
|
115
113
|
|
|
116
114
|
expect(comment.send(:sanitized_comment)).to eq('Actual comment')
|
|
117
115
|
end
|
|
@@ -122,8 +120,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
|
|
|
122
120
|
context 'when the comment contains an unknown detector name' do
|
|
123
121
|
it 'raises BadDetectorInCommentError' do
|
|
124
122
|
expect do
|
|
125
|
-
|
|
126
|
-
comment: '# :reek:DoesNotExist')
|
|
123
|
+
build_code_comment(comment: '# :reek:DoesNotExist')
|
|
127
124
|
end.to raise_error(Reek::Errors::BadDetectorInCommentError)
|
|
128
125
|
end
|
|
129
126
|
end
|
|
@@ -132,7 +129,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
|
|
|
132
129
|
it 'raises GarbageDetectorConfigurationInCommentError' do
|
|
133
130
|
expect do
|
|
134
131
|
comment = '# :reek:UncommunicativeMethodName { thats: a: bad: config }'
|
|
135
|
-
|
|
132
|
+
build_code_comment(comment: comment)
|
|
136
133
|
end.to raise_error(Reek::Errors::GarbageDetectorConfigurationInCommentError)
|
|
137
134
|
end
|
|
138
135
|
end
|
|
@@ -140,7 +137,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
|
|
|
140
137
|
context 'when the legacy comment format was used' do
|
|
141
138
|
it 'raises LegacyCommentSeparatorError' do
|
|
142
139
|
comment = '# :reek:DuplicateMethodCall:'
|
|
143
|
-
expect {
|
|
140
|
+
expect { build_code_comment(comment: comment) }.
|
|
144
141
|
to raise_error Reek::Errors::LegacyCommentSeparatorError
|
|
145
142
|
end
|
|
146
143
|
end
|
|
@@ -151,7 +148,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
|
|
|
151
148
|
expect do
|
|
152
149
|
# exclude -> exlude and enabled -> nabled
|
|
153
150
|
comment = '# :reek:UncommunicativeMethodName { exlude: alfa, nabled: true }'
|
|
154
|
-
|
|
151
|
+
build_code_comment(comment: comment)
|
|
155
152
|
end.to raise_error(Reek::Errors::BadDetectorConfigurationKeyInCommentError)
|
|
156
153
|
end
|
|
157
154
|
end
|
|
@@ -160,7 +157,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
|
|
|
160
157
|
it 'does not raise' do
|
|
161
158
|
expect do
|
|
162
159
|
comment = '# :reek:UncommunicativeMethodName { exclude: alfa, enabled: true }'
|
|
163
|
-
|
|
160
|
+
build_code_comment(comment: comment)
|
|
164
161
|
end.not_to raise_error
|
|
165
162
|
end
|
|
166
163
|
end
|
|
@@ -170,7 +167,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
|
|
|
170
167
|
expect do
|
|
171
168
|
# max_copies -> mx_copies and min_clump_size -> mn_clump_size
|
|
172
169
|
comment = '# :reek:DataClump { mx_copies: 4, mn_clump_size: 3 }'
|
|
173
|
-
|
|
170
|
+
build_code_comment(comment: comment)
|
|
174
171
|
end.to raise_error(Reek::Errors::BadDetectorConfigurationKeyInCommentError)
|
|
175
172
|
end
|
|
176
173
|
end
|
|
@@ -179,7 +176,7 @@ RSpec.describe Reek::CodeComment::CodeCommentValidator do
|
|
|
179
176
|
it 'does not raise' do
|
|
180
177
|
expect do
|
|
181
178
|
comment = '# :reek:DataClump { max_copies: 4, min_clump_size: 3 }'
|
|
182
|
-
|
|
179
|
+
build_code_comment(comment: comment)
|
|
183
180
|
end.not_to raise_error
|
|
184
181
|
end
|
|
185
182
|
end
|
|
@@ -89,6 +89,12 @@ RSpec.describe Reek::Configuration::DirectoryDirectives do
|
|
|
89
89
|
expect(hit.to_s).to eq('bar/**/.spec/*')
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
+
it 'returns the corresponding directory when source_base_dir is an absolute_path' do
|
|
93
|
+
source_base_dir = Pathname.new('foo/bar').expand_path
|
|
94
|
+
hit = directives.send :best_match_for, source_base_dir
|
|
95
|
+
expect(hit.to_s).to eq('foo/bar')
|
|
96
|
+
end
|
|
97
|
+
|
|
92
98
|
it 'does not match an arbitrary directory when source_base_dir contains a character that could match the .' do
|
|
93
99
|
source_base_dir = 'bar/something/aspec/direct'
|
|
94
100
|
hit = directives.send :best_match_for, source_base_dir
|
|
@@ -5,12 +5,21 @@ require_lib 'reek/configuration/excluded_paths'
|
|
|
5
5
|
RSpec.describe Reek::Configuration::ExcludedPaths do
|
|
6
6
|
describe '#add' do
|
|
7
7
|
let(:exclusions) { [].extend(described_class) }
|
|
8
|
-
let(:paths)
|
|
9
|
-
|
|
8
|
+
let(:paths) do
|
|
9
|
+
%w(samples/directory_does_not_exist/
|
|
10
|
+
samples/source_with_non_ruby_files/
|
|
11
|
+
samples/**/ignore_me*)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
let(:expected_exclude_paths) do
|
|
15
|
+
[Pathname('samples/source_with_non_ruby_files/'),
|
|
16
|
+
Pathname('samples/source_with_exclude_paths/ignore_me'),
|
|
17
|
+
Pathname('samples/source_with_exclude_paths/nested/ignore_me_as_well')]
|
|
18
|
+
end
|
|
10
19
|
|
|
11
20
|
it 'adds the given paths as Pathname' do
|
|
12
21
|
exclusions.add(paths)
|
|
13
|
-
expect(exclusions).to
|
|
22
|
+
expect(exclusions).to match_array expected_exclude_paths
|
|
14
23
|
end
|
|
15
24
|
end
|
|
16
25
|
end
|
|
@@ -3,9 +3,7 @@ require_lib 'reek/report/code_climate/code_climate_configuration'
|
|
|
3
3
|
|
|
4
4
|
RSpec.describe Reek::Report::CodeClimateConfiguration do
|
|
5
5
|
yml = described_class.load
|
|
6
|
-
smell_types = Reek::SmellDetectors::BaseDetector.descendants.map
|
|
7
|
-
descendant.name.demodulize
|
|
8
|
-
end
|
|
6
|
+
smell_types = Reek::SmellDetectors::BaseDetector.descendants.map(&:smell_type)
|
|
9
7
|
|
|
10
8
|
smell_types.each do |name|
|
|
11
9
|
config = yml.fetch(name)
|
|
@@ -8,12 +8,12 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
|
|
|
8
8
|
context 'when fingerprinting a warning with no parameters' do
|
|
9
9
|
let(:expected_fingerprint) { 'e68badd29db51c92363a7c6a2438d722' }
|
|
10
10
|
let(:warning) do
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
Reek::SmellWarning.new(
|
|
12
|
+
'UtilityFunction',
|
|
13
|
+
context: 'alfa',
|
|
14
|
+
message: "doesn't depend on instance state (maybe move it to another class?)",
|
|
15
|
+
lines: lines,
|
|
16
|
+
source: 'a/ruby/source/file.rb')
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
context 'with code at a specific location' do
|
|
@@ -35,12 +35,12 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
|
|
|
35
35
|
|
|
36
36
|
context 'when the fingerprint should not be computed' do
|
|
37
37
|
let(:warning) do
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
Reek::SmellWarning.new(
|
|
39
|
+
'ManualDispatch',
|
|
40
|
+
context: 'Alfa#bravo',
|
|
41
|
+
message: 'manually dispatches method call',
|
|
42
|
+
lines: [4],
|
|
43
|
+
source: 'a/ruby/source/file.rb')
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
it 'returns nil' do
|
|
@@ -50,13 +50,13 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
|
|
|
50
50
|
|
|
51
51
|
context 'when the smell warning has only identifying parameters' do
|
|
52
52
|
let(:warning) do
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
Reek::SmellWarning.new(
|
|
54
|
+
'ClassVariable',
|
|
55
|
+
context: 'Alfa',
|
|
56
|
+
message: "declares the class variable '@@#{name}'",
|
|
57
|
+
lines: [4],
|
|
58
|
+
parameters: { name: "@@#{name}" },
|
|
59
|
+
source: 'a/ruby/source/file.rb')
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
context 'when the name is one thing' do
|
|
@@ -80,13 +80,13 @@ RSpec.describe Reek::Report::CodeClimateFingerprint do
|
|
|
80
80
|
|
|
81
81
|
context 'when the smell warning has identifying and non-identifying parameters' do
|
|
82
82
|
let(:warning) do
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
Reek::SmellWarning.new(
|
|
84
|
+
'DuplicateMethodCall',
|
|
85
|
+
context: "Alfa##{name}",
|
|
86
|
+
message: "calls '#{name}' #{count} times",
|
|
87
|
+
lines: lines,
|
|
88
|
+
parameters: { name: "@@#{name}", count: count },
|
|
89
|
+
source: 'a/ruby/source/file.rb')
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
context 'when the parameters are provided' do
|
|
@@ -4,12 +4,12 @@ require_lib 'reek/report/code_climate/code_climate_formatter'
|
|
|
4
4
|
RSpec.describe Reek::Report::CodeClimateFormatter do
|
|
5
5
|
describe '#render' do
|
|
6
6
|
let(:warning) do
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
Reek::SmellWarning.new(
|
|
8
|
+
'UtilityFunction',
|
|
9
|
+
context: 'context foo',
|
|
10
|
+
message: 'message bar',
|
|
11
|
+
lines: [1, 2],
|
|
12
|
+
source: 'a/ruby/source/file.rb')
|
|
13
13
|
end
|
|
14
14
|
let(:rendered) { described_class.new(warning).render }
|
|
15
15
|
let(:json) { JSON.parse rendered.chop }
|
|
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
|
|
|
2
2
|
require_lib 'reek/report/location_formatter'
|
|
3
3
|
|
|
4
4
|
RSpec.describe Reek::Report::BlankLocationFormatter do
|
|
5
|
-
let(:warning) {
|
|
5
|
+
let(:warning) { build_smell_warning(lines: [11, 9, 250, 100]) }
|
|
6
6
|
|
|
7
7
|
describe '.format' do
|
|
8
8
|
it 'returns a blank String regardless of the warning' do
|
|
@@ -12,7 +12,7 @@ RSpec.describe Reek::Report::BlankLocationFormatter do
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
RSpec.describe Reek::Report::DefaultLocationFormatter do
|
|
15
|
-
let(:warning) {
|
|
15
|
+
let(:warning) { build_smell_warning(lines: [11, 9, 250, 100]) }
|
|
16
16
|
|
|
17
17
|
describe '.format' do
|
|
18
18
|
it 'returns a prefix with sorted line numbers' do
|
|
@@ -22,7 +22,7 @@ RSpec.describe Reek::Report::DefaultLocationFormatter do
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
RSpec.describe Reek::Report::SingleLineLocationFormatter do
|
|
25
|
-
let(:warning) {
|
|
25
|
+
let(:warning) { build_smell_warning(lines: [11, 9, 250, 100]) }
|
|
26
26
|
|
|
27
27
|
describe '.format' do
|
|
28
28
|
it 'returns the first line where the smell was found' do
|
|
@@ -5,13 +5,13 @@ require_lib 'reek/smell_detectors/duplicate_method_call'
|
|
|
5
5
|
RSpec.describe Reek::SmellDetectors::BaseDetector do
|
|
6
6
|
describe '.todo_configuration_for' do
|
|
7
7
|
it 'returns exclusion configuration for the given smells' do
|
|
8
|
-
smell =
|
|
8
|
+
smell = build_smell_warning(smell_type: 'Foo', context: 'Foo#bar')
|
|
9
9
|
result = described_class.todo_configuration_for([smell])
|
|
10
10
|
expect(result).to eq('BaseDetector' => { 'exclude' => ['Foo#bar'] })
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
it 'merges identical contexts' do
|
|
14
|
-
smell =
|
|
14
|
+
smell = build_smell_warning(smell_type: 'Foo', context: 'Foo#bar')
|
|
15
15
|
result = described_class.todo_configuration_for([smell, smell])
|
|
16
16
|
expect(result).to eq('BaseDetector' => { 'exclude' => ['Foo#bar'] })
|
|
17
17
|
end
|
|
@@ -20,7 +20,7 @@ RSpec.describe Reek::SmellDetectors::BaseDetector do
|
|
|
20
20
|
let(:subclass) { Reek::SmellDetectors::TooManyStatements }
|
|
21
21
|
|
|
22
22
|
it 'includes default exclusions' do
|
|
23
|
-
smell =
|
|
23
|
+
smell = build_smell_warning(smell_type: 'TooManyStatements', context: 'Foo#bar')
|
|
24
24
|
result = subclass.todo_configuration_for([smell])
|
|
25
25
|
|
|
26
26
|
aggregate_failures do
|
|
@@ -161,6 +161,22 @@ RSpec.describe Reek::SmellDetectors::UtilityFunction do
|
|
|
161
161
|
end
|
|
162
162
|
end
|
|
163
163
|
|
|
164
|
+
context 'when examining refinements' do
|
|
165
|
+
it 'reports on the refined class' do
|
|
166
|
+
src = <<-RUBY
|
|
167
|
+
module Alfa
|
|
168
|
+
refine Bravo do
|
|
169
|
+
def bravo(charlie)
|
|
170
|
+
charlie.delta.echo
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
RUBY
|
|
175
|
+
|
|
176
|
+
expect(src).to reek_of(:UtilityFunction, context: 'Bravo#bravo')
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
164
180
|
describe 'method visibility' do
|
|
165
181
|
it 'reports private methods' do
|
|
166
182
|
src = <<-RUBY
|
|
@@ -24,23 +24,23 @@ RSpec.describe Reek::SmellWarning do
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
context 'when smells differ only by detector' do
|
|
27
|
-
let(:first) {
|
|
28
|
-
let(:second) {
|
|
27
|
+
let(:first) { build_smell_warning(smell_type: 'DuplicateMethodCall') }
|
|
28
|
+
let(:second) { build_smell_warning(smell_type: 'FeatureEnvy') }
|
|
29
29
|
|
|
30
30
|
it_behaves_like 'first sorts ahead of second'
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
context 'when smells differ only by lines' do
|
|
34
|
-
let(:first) {
|
|
35
|
-
let(:second) {
|
|
34
|
+
let(:first) { build_smell_warning(smell_type: 'FeatureEnvy', lines: [2]) }
|
|
35
|
+
let(:second) { build_smell_warning(smell_type: 'FeatureEnvy', lines: [3]) }
|
|
36
36
|
|
|
37
37
|
it_behaves_like 'first sorts ahead of second'
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
context 'when smells differ only by context' do
|
|
41
|
-
let(:first) {
|
|
41
|
+
let(:first) { build_smell_warning(smell_type: 'DuplicateMethodCall', context: 'first') }
|
|
42
42
|
let(:second) do
|
|
43
|
-
|
|
43
|
+
build_smell_warning(smell_type: 'DuplicateMethodCall', context: 'second')
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
it_behaves_like 'first sorts ahead of second'
|
|
@@ -48,11 +48,11 @@ RSpec.describe Reek::SmellWarning do
|
|
|
48
48
|
|
|
49
49
|
context 'when smells differ only by message' do
|
|
50
50
|
let(:first) do
|
|
51
|
-
|
|
51
|
+
build_smell_warning(smell_type: 'DuplicateMethodCall',
|
|
52
52
|
context: 'ctx', message: 'first message')
|
|
53
53
|
end
|
|
54
54
|
let(:second) do
|
|
55
|
-
|
|
55
|
+
build_smell_warning(smell_type: 'DuplicateMethodCall',
|
|
56
56
|
context: 'ctx', message: 'second message')
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -61,10 +61,10 @@ RSpec.describe Reek::SmellWarning do
|
|
|
61
61
|
|
|
62
62
|
context 'when smells differ by name and message' do
|
|
63
63
|
let(:first) do
|
|
64
|
-
|
|
64
|
+
build_smell_warning(smell_type: 'FeatureEnvy', message: 'second message')
|
|
65
65
|
end
|
|
66
66
|
let(:second) do
|
|
67
|
-
|
|
67
|
+
build_smell_warning(smell_type: 'UtilityFunction', message: 'first message')
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
it_behaves_like 'first sorts ahead of second'
|
|
@@ -72,13 +72,13 @@ RSpec.describe Reek::SmellWarning do
|
|
|
72
72
|
|
|
73
73
|
context 'when smells differ everywhere' do
|
|
74
74
|
let(:first) do
|
|
75
|
-
|
|
75
|
+
build_smell_warning(smell_type: 'DuplicateMethodCall',
|
|
76
76
|
context: 'Dirty#a',
|
|
77
77
|
message: 'calls @s.title twice')
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
let(:second) do
|
|
81
|
-
|
|
81
|
+
build_smell_warning(smell_type: 'UncommunicativeVariableName',
|
|
82
82
|
context: 'Dirty',
|
|
83
83
|
message: "has the variable name '@s'")
|
|
84
84
|
end
|