reek 5.6.0 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -1
- data/.simplecov +1 -0
- data/.travis.yml +12 -11
- data/CHANGELOG.md +8 -0
- data/Dockerfile +1 -0
- data/Gemfile +15 -17
- data/README.md +1 -7
- data/bin/code_climate_reek +12 -2
- data/docs/Attribute.md +1 -1
- data/docs/Control-Couple.md +1 -1
- data/docs/Nil-Check.md +4 -1
- data/features/command_line_interface/options.feature +2 -3
- data/features/reports/codeclimate.feature +2 -2
- 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 +4 -0
- data/lib/reek/ast/sexp_extensions/arguments.rb +11 -0
- data/lib/reek/cli/options.rb +2 -2
- data/lib/reek/code_comment.rb +36 -29
- data/lib/reek/errors/legacy_comment_separator_error.rb +36 -0
- data/lib/reek/report.rb +5 -7
- data/lib/reek/report/code_climate/code_climate_report.rb +2 -1
- data/lib/reek/report/simple_warning_formatter.rb +0 -7
- data/lib/reek/smell_detectors/base_detector.rb +0 -9
- data/lib/reek/smell_detectors/data_clump.rb +23 -56
- data/lib/reek/smell_detectors/nil_check.rb +1 -12
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +5 -6
- data/spec/reek/ast/sexp_extensions_spec.rb +15 -33
- data/spec/reek/code_comment_spec.rb +23 -21
- data/spec/reek/context_builder_spec.rb +110 -113
- data/spec/reek/smell_detectors/base_detector_spec.rb +0 -10
- data/spec/reek/smell_detectors/data_clump_spec.rb +14 -0
- data/spec/reek/smell_detectors/missing_safe_method_spec.rb +8 -2
- data/spec/reek/smell_detectors/nil_check_spec.rb +3 -3
- data/spec/reek/source/source_code_spec.rb +13 -0
- data/spec/spec_helper.rb +1 -0
- metadata +6 -18
@@ -3,42 +3,126 @@ require_lib 'reek/context_builder'
|
|
3
3
|
|
4
4
|
RSpec.describe Reek::ContextBuilder do
|
5
5
|
describe '#context_tree' do
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
context 'with some simple example code' do
|
7
|
+
let(:walker) do
|
8
|
+
code = 'class Car; def drive; end; end'
|
9
|
+
described_class.new(syntax_tree(code))
|
10
|
+
end
|
11
|
+
let(:context_tree) { walker.context_tree }
|
12
|
+
let(:module_context) { context_tree.children.first }
|
13
|
+
let(:method_context) { module_context.children.first }
|
14
|
+
|
15
|
+
describe 'the starting node' do
|
16
|
+
it 'is a root node' do
|
17
|
+
expect(context_tree.type).to eq(:root)
|
18
|
+
expect(context_tree).to be_a(Reek::Context::RootContext)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'has one module_context child' do
|
22
|
+
aggregate_failures do
|
23
|
+
expect(context_tree.children.count).to eq 1
|
24
|
+
expect(module_context).to be_a(Reek::Context::ModuleContext)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'the module node' do
|
30
|
+
it 'has one method_context child' do
|
31
|
+
aggregate_failures do
|
32
|
+
expect(method_context).to be_a(Reek::Context::MethodContext)
|
33
|
+
expect(module_context.children.size).to eq(1)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'holds a reference to the parent context' do
|
38
|
+
expect(method_context.parent).to eq(module_context)
|
39
|
+
end
|
40
|
+
end
|
9
41
|
end
|
10
|
-
let(:context_tree) { walker.context_tree }
|
11
|
-
let(:module_context) { context_tree.children.first }
|
12
|
-
let(:method_context) { module_context.children.first }
|
13
42
|
|
14
|
-
it '
|
15
|
-
|
16
|
-
|
43
|
+
it 'creates the proper context for all kinds of singleton methods' do
|
44
|
+
src = <<-RUBY
|
45
|
+
class Car
|
46
|
+
def self.start; end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
def drive; end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
RUBY
|
53
|
+
|
54
|
+
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
55
|
+
context_tree = described_class.new(syntax_tree).context_tree
|
56
|
+
|
57
|
+
class_node = context_tree.children.first
|
58
|
+
start_method = class_node.children.first
|
59
|
+
drive_method = class_node.children.last
|
60
|
+
|
61
|
+
expect(start_method).to be_instance_of Reek::Context::SingletonMethodContext
|
62
|
+
expect(drive_method).to be_instance_of Reek::Context::SingletonMethodContext
|
17
63
|
end
|
18
64
|
|
19
|
-
it '
|
20
|
-
|
65
|
+
it 'returns something sensible for nested metaclasses' do
|
66
|
+
src = <<-RUBY
|
67
|
+
class Foo
|
68
|
+
class << self
|
69
|
+
class << self
|
70
|
+
def bar; end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
RUBY
|
75
|
+
|
76
|
+
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
77
|
+
context_tree = described_class.new(syntax_tree).context_tree
|
78
|
+
|
79
|
+
class_context = context_tree.children.first
|
80
|
+
method_context = class_context.children.first
|
81
|
+
|
82
|
+
expect(method_context).to be_instance_of Reek::Context::SingletonMethodContext
|
83
|
+
expect(method_context.parent).to eq class_context
|
21
84
|
end
|
22
85
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
86
|
+
it 'returns something sensible for nested method definitions' do
|
87
|
+
src = <<-RUBY
|
88
|
+
class Foo
|
89
|
+
def foo
|
90
|
+
def bar
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
RUBY
|
27
95
|
|
28
|
-
|
29
|
-
|
30
|
-
|
96
|
+
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
97
|
+
context_tree = described_class.new(syntax_tree).context_tree
|
98
|
+
|
99
|
+
class_context = context_tree.children.first
|
100
|
+
foo_context = class_context.children.first
|
101
|
+
|
102
|
+
bar_context = foo_context.children.first
|
103
|
+
expect(bar_context).to be_instance_of Reek::Context::MethodContext
|
104
|
+
expect(bar_context.parent).to eq foo_context
|
31
105
|
end
|
32
106
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
107
|
+
it 'returns something sensible for method definitions nested in singleton methods' do
|
108
|
+
src = <<-RUBY
|
109
|
+
class Foo
|
110
|
+
def self.foo
|
111
|
+
def bar
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
RUBY
|
38
116
|
|
39
|
-
|
40
|
-
|
41
|
-
|
117
|
+
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
118
|
+
context_tree = described_class.new(syntax_tree).context_tree
|
119
|
+
|
120
|
+
class_context = context_tree.children.first
|
121
|
+
foo_context = class_context.children.first
|
122
|
+
|
123
|
+
bar_context = foo_context.children.first
|
124
|
+
expect(bar_context).to be_instance_of Reek::Context::SingletonMethodContext
|
125
|
+
expect(bar_context.parent).to eq foo_context
|
42
126
|
end
|
43
127
|
end
|
44
128
|
|
@@ -370,91 +454,4 @@ RSpec.describe Reek::ContextBuilder do
|
|
370
454
|
expect(nested_baz_context.visibility).to eq :public
|
371
455
|
end
|
372
456
|
end
|
373
|
-
|
374
|
-
describe '#context_tree' do
|
375
|
-
it 'creates the proper context for all kinds of singleton methods' do
|
376
|
-
src = <<-RUBY
|
377
|
-
class Car
|
378
|
-
def self.start; end
|
379
|
-
|
380
|
-
class << self
|
381
|
-
def drive; end
|
382
|
-
end
|
383
|
-
end
|
384
|
-
RUBY
|
385
|
-
|
386
|
-
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
387
|
-
context_tree = described_class.new(syntax_tree).context_tree
|
388
|
-
|
389
|
-
class_node = context_tree.children.first
|
390
|
-
start_method = class_node.children.first
|
391
|
-
drive_method = class_node.children.last
|
392
|
-
|
393
|
-
expect(start_method).to be_instance_of Reek::Context::SingletonMethodContext
|
394
|
-
expect(drive_method).to be_instance_of Reek::Context::SingletonMethodContext
|
395
|
-
end
|
396
|
-
|
397
|
-
it 'returns something sensible for nested metaclasses' do
|
398
|
-
src = <<-RUBY
|
399
|
-
class Foo
|
400
|
-
class << self
|
401
|
-
class << self
|
402
|
-
def bar; end
|
403
|
-
end
|
404
|
-
end
|
405
|
-
end
|
406
|
-
RUBY
|
407
|
-
|
408
|
-
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
409
|
-
context_tree = described_class.new(syntax_tree).context_tree
|
410
|
-
|
411
|
-
class_context = context_tree.children.first
|
412
|
-
method_context = class_context.children.first
|
413
|
-
|
414
|
-
expect(method_context).to be_instance_of Reek::Context::SingletonMethodContext
|
415
|
-
expect(method_context.parent).to eq class_context
|
416
|
-
end
|
417
|
-
|
418
|
-
it 'returns something sensible for nested method definitions' do
|
419
|
-
src = <<-RUBY
|
420
|
-
class Foo
|
421
|
-
def foo
|
422
|
-
def bar
|
423
|
-
end
|
424
|
-
end
|
425
|
-
end
|
426
|
-
RUBY
|
427
|
-
|
428
|
-
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
429
|
-
context_tree = described_class.new(syntax_tree).context_tree
|
430
|
-
|
431
|
-
class_context = context_tree.children.first
|
432
|
-
foo_context = class_context.children.first
|
433
|
-
|
434
|
-
bar_context = foo_context.children.first
|
435
|
-
expect(bar_context).to be_instance_of Reek::Context::MethodContext
|
436
|
-
expect(bar_context.parent).to eq foo_context
|
437
|
-
end
|
438
|
-
|
439
|
-
it 'returns something sensible for method definitions nested in singleton methods' do
|
440
|
-
src = <<-RUBY
|
441
|
-
class Foo
|
442
|
-
def self.foo
|
443
|
-
def bar
|
444
|
-
end
|
445
|
-
end
|
446
|
-
end
|
447
|
-
RUBY
|
448
|
-
|
449
|
-
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
450
|
-
context_tree = described_class.new(syntax_tree).context_tree
|
451
|
-
|
452
|
-
class_context = context_tree.children.first
|
453
|
-
foo_context = class_context.children.first
|
454
|
-
|
455
|
-
bar_context = foo_context.children.first
|
456
|
-
expect(bar_context).to be_instance_of Reek::Context::SingletonMethodContext
|
457
|
-
expect(bar_context.parent).to eq foo_context
|
458
|
-
end
|
459
|
-
end
|
460
457
|
end
|
@@ -31,16 +31,6 @@ RSpec.describe Reek::SmellDetectors::BaseDetector do
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
describe '.valid_detector?' do
|
35
|
-
it 'returns true for a valid detector' do
|
36
|
-
expect(described_class.valid_detector?('DuplicateMethodCall')).to be true
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'returns false for an invalid detector' do
|
40
|
-
expect(described_class.valid_detector?('Unknown')).to be false
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
34
|
describe '.to_detector' do
|
45
35
|
it 'returns the right detector' do
|
46
36
|
expect(described_class.to_detector('DuplicateMethodCall')).to eq(Reek::SmellDetectors::DuplicateMethodCall)
|
@@ -76,6 +76,20 @@ RSpec.describe Reek::SmellDetectors::DataClump do
|
|
76
76
|
parameters: ['echo', 'foxtrot'])
|
77
77
|
end
|
78
78
|
|
79
|
+
it 'reports arguments in alphabetical order even if they are never used that way' do
|
80
|
+
src = <<-RUBY
|
81
|
+
#{scope} Alfa
|
82
|
+
def bravo (foxtrot, echo); end
|
83
|
+
def charlie(foxtrot, echo); end
|
84
|
+
def delta (foxtrot, echo); end
|
85
|
+
end
|
86
|
+
RUBY
|
87
|
+
|
88
|
+
expect(src).to reek_of(:DataClump,
|
89
|
+
count: 3,
|
90
|
+
parameters: ['echo', 'foxtrot'])
|
91
|
+
end
|
92
|
+
|
79
93
|
it 'reports parameter sets that are > 2' do
|
80
94
|
src = <<-RUBY
|
81
95
|
#{scope} Alfa
|
@@ -50,13 +50,19 @@ RSpec.describe Reek::SmellDetectors::MissingSafeMethod do
|
|
50
50
|
|
51
51
|
it 'does not report methods we excluded via comment' do
|
52
52
|
source = <<-RUBY
|
53
|
-
# :reek:MissingSafeMethod
|
53
|
+
# :reek:MissingSafeMethod { exclude: [ bravo! ] }
|
54
54
|
class Alfa
|
55
55
|
def bravo!
|
56
56
|
end
|
57
|
+
|
58
|
+
def charlie!
|
59
|
+
end
|
57
60
|
end
|
58
61
|
RUBY
|
59
62
|
|
60
|
-
|
63
|
+
aggregate_failures do
|
64
|
+
expect(source).not_to reek_of(:MissingSafeMethod, name: 'bravo!')
|
65
|
+
expect(source).to reek_of(:MissingSafeMethod, name: 'charlie!')
|
66
|
+
end
|
61
67
|
end
|
62
68
|
end
|
@@ -76,14 +76,14 @@ RSpec.describe Reek::SmellDetectors::NilCheck do
|
|
76
76
|
expect(src).to reek_of(:NilCheck)
|
77
77
|
end
|
78
78
|
|
79
|
-
it '
|
79
|
+
it 'does not report when scope uses &.' do
|
80
80
|
src = <<-RUBY
|
81
81
|
def alfa(bravo)
|
82
82
|
bravo&.charlie
|
83
83
|
end
|
84
84
|
RUBY
|
85
85
|
|
86
|
-
expect(src).
|
86
|
+
expect(src).not_to reek_of(:NilCheck)
|
87
87
|
end
|
88
88
|
|
89
89
|
it 'reports all lines when scope uses multiple nilchecks' do
|
@@ -95,6 +95,6 @@ RSpec.describe Reek::SmellDetectors::NilCheck do
|
|
95
95
|
end
|
96
96
|
RUBY
|
97
97
|
|
98
|
-
expect(src).to reek_of(:NilCheck, lines: [2, 3
|
98
|
+
expect(src).to reek_of(:NilCheck, lines: [2, 3])
|
99
99
|
end
|
100
100
|
end
|
@@ -62,5 +62,18 @@ RSpec.describe Reek::Source::SourceCode do
|
|
62
62
|
expect { src.syntax_tree }.to raise_error error_class, error_message
|
63
63
|
end
|
64
64
|
end
|
65
|
+
|
66
|
+
if RUBY_VERSION >= '2.7'
|
67
|
+
context 'with ruby 2.7 syntax' do
|
68
|
+
context 'with forward_args (`...`)' do
|
69
|
+
let(:source_code) { described_class.new(source: 'def alpha(...) bravo(...); end') }
|
70
|
+
|
71
|
+
it 'returns a :forward_args node' do
|
72
|
+
result = source_code.syntax_tree
|
73
|
+
expect(result.children[1].type).to eq(:forward_args)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
65
78
|
end
|
66
79
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reek
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 6.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Rutherford
|
@@ -11,22 +11,8 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2020-
|
14
|
+
date: 2020-03-30 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
17
|
-
name: codeclimate-engine-rb
|
18
|
-
requirement: !ruby/object:Gem::Requirement
|
19
|
-
requirements:
|
20
|
-
- - "~>"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 0.4.0
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 0.4.0
|
30
16
|
- !ruby/object:Gem::Dependency
|
31
17
|
name: kwalify
|
32
18
|
requirement: !ruby/object:Gem::Requirement
|
@@ -281,6 +267,7 @@ files:
|
|
281
267
|
- lib/reek/errors/encoding_error.rb
|
282
268
|
- lib/reek/errors/garbage_detector_configuration_in_comment_error.rb
|
283
269
|
- lib/reek/errors/incomprehensible_source_error.rb
|
270
|
+
- lib/reek/errors/legacy_comment_separator_error.rb
|
284
271
|
- lib/reek/errors/syntax_error.rb
|
285
272
|
- lib/reek/examiner.rb
|
286
273
|
- lib/reek/logging_error_handler.rb
|
@@ -492,14 +479,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
492
479
|
requirements:
|
493
480
|
- - ">="
|
494
481
|
- !ruby/object:Gem::Version
|
495
|
-
version: 2.
|
482
|
+
version: 2.4.0
|
496
483
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
497
484
|
requirements:
|
498
485
|
- - ">="
|
499
486
|
- !ruby/object:Gem::Version
|
500
487
|
version: '0'
|
501
488
|
requirements: []
|
502
|
-
|
489
|
+
rubyforge_project:
|
490
|
+
rubygems_version: 2.7.7
|
503
491
|
signing_key:
|
504
492
|
specification_version: 4
|
505
493
|
summary: Code smell detector for Ruby
|