reek 4.6.2 → 4.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +24 -24
- data/CHANGELOG.md +4 -0
- data/Gemfile +1 -1
- data/defaults.reek +3 -0
- data/docs/Prima-Donna-Method.md +1 -1
- data/features/command_line_interface/stdin.feature +7 -3
- data/lib/reek/examiner.rb +9 -6
- data/lib/reek/rake/task.rb +0 -1
- data/lib/reek/report/code_climate/code_climate_configuration.yml +4 -0
- data/lib/reek/smell_detectors.rb +1 -0
- data/lib/reek/smell_detectors/syntax.rb +33 -0
- data/lib/reek/source/source_code.rb +36 -30
- data/lib/reek/version.rb +1 -1
- data/spec/reek/source/source_code_spec.rb +14 -33
- data/spec/reek/spec/should_reek_of_spec.rb +0 -1
- data/spec/spec_helper.rb +1 -0
- metadata +3 -3
- data/lib/reek/errors/parse_error.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ec8e3f40eb231654c58d4025080c703268e7322
|
4
|
+
data.tar.gz: a018b00cdba03a5da356e1c05e32bd0bc04ba569
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78c20b5e99a3c4f804c530da98b020d634b289ea575f15339e3978088f207112a022345695b7ba45fcaa5edfbac74bcba38409e99ffc6e42d0e46f2add060fdf
|
7
|
+
data.tar.gz: 1bd64f7d805994fb356887cb638e900669c2308d2bc86fed37ad36709df4314dbe4dcfc616240c8790bf1d61ce5e3c1b58fd7b07e5bed385d0ced79cfad19cdf
|
data/.rubocop.yml
CHANGED
@@ -8,6 +8,30 @@ AllCops:
|
|
8
8
|
- 'vendor/**/*'
|
9
9
|
TargetRubyVersion: 2.1
|
10
10
|
|
11
|
+
# Place . on the previous line
|
12
|
+
Layout/DotPosition:
|
13
|
+
EnforcedStyle: trailing
|
14
|
+
|
15
|
+
# Require empty lines between defs, except for one-line defs
|
16
|
+
Layout/EmptyLineBetweenDefs:
|
17
|
+
AllowAdjacentOneLineDefs: true
|
18
|
+
|
19
|
+
# Use active_support's strip_heredoc to indent heredocs
|
20
|
+
Layout/IndentHeredoc:
|
21
|
+
EnforcedStyle: active_support
|
22
|
+
|
23
|
+
# Always put the closing brace on the last line
|
24
|
+
Layout/MultilineMethodCallBraceLayout:
|
25
|
+
EnforcedStyle: same_line
|
26
|
+
|
27
|
+
# Indent one level for follow-up lines
|
28
|
+
Layout/MultilineMethodCallIndentation:
|
29
|
+
EnforcedStyle: indented
|
30
|
+
|
31
|
+
# Indent one level for follow-up lines
|
32
|
+
Layout/MultilineOperationIndentation:
|
33
|
+
EnforcedStyle: indented
|
34
|
+
|
11
35
|
# Assume the programmer knows how bracketed block syntax works
|
12
36
|
Lint/AmbiguousBlockAssociation:
|
13
37
|
Enabled: false
|
@@ -95,14 +119,6 @@ Style/Documentation:
|
|
95
119
|
- 'lib/reek/ast/sexp_extensions/super.rb'
|
96
120
|
- 'lib/reek/ast/sexp_extensions/variables.rb'
|
97
121
|
|
98
|
-
# Place . on the previous line
|
99
|
-
Style/DotPosition:
|
100
|
-
EnforcedStyle: trailing
|
101
|
-
|
102
|
-
# Require empty lines between defs, except for one-line defs
|
103
|
-
Style/EmptyLineBetweenDefs:
|
104
|
-
AllowAdjacentOneLineDefs: true
|
105
|
-
|
106
122
|
# Require comment for files in lib and bin
|
107
123
|
Style/FrozenStringLiteralComment:
|
108
124
|
Include:
|
@@ -110,26 +126,10 @@ Style/FrozenStringLiteralComment:
|
|
110
126
|
- 'lib/**/*'
|
111
127
|
EnforcedStyle: always
|
112
128
|
|
113
|
-
# Use active_support's strip_heredoc to indent heredocs
|
114
|
-
Style/IndentHeredoc:
|
115
|
-
EnforcedStyle: active_support
|
116
|
-
|
117
129
|
# Allow multiline block chains
|
118
130
|
Style/MultilineBlockChain:
|
119
131
|
Enabled: false
|
120
132
|
|
121
|
-
# Always put the closing brace on the last line
|
122
|
-
Style/MultilineMethodCallBraceLayout:
|
123
|
-
EnforcedStyle: same_line
|
124
|
-
|
125
|
-
# Indent one level for follow-up lines
|
126
|
-
Style/MultilineMethodCallIndentation:
|
127
|
-
EnforcedStyle: indented
|
128
|
-
|
129
|
-
# Indent one level for follow-up lines
|
130
|
-
Style/MultilineOperationIndentation:
|
131
|
-
EnforcedStyle: indented
|
132
|
-
|
133
133
|
# There's nothing wrong with parallel assignment
|
134
134
|
Style/ParallelAssignment:
|
135
135
|
Enabled: false
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/defaults.reek
CHANGED
data/docs/Prima-Donna-Method.md
CHANGED
@@ -82,7 +82,7 @@ ruby.rb -- 1 warning:
|
|
82
82
|
If you want to suppress this warning you can do this via source comment like this:
|
83
83
|
|
84
84
|
```Ruby
|
85
|
-
# :reek:PrimaDonnaMethod
|
85
|
+
# :reek:PrimaDonnaMethod { exclude: [ bravo! ] }
|
86
86
|
class Alfa
|
87
87
|
def bravo!
|
88
88
|
end
|
@@ -34,6 +34,10 @@ Feature: Reek reads from $stdin when no files are given
|
|
34
34
|
|
35
35
|
Scenario: syntax error causes the source to be ignored
|
36
36
|
When I pass "= invalid syntax =" to reek
|
37
|
-
Then
|
38
|
-
And
|
39
|
-
|
37
|
+
Then the exit status indicates smells
|
38
|
+
And it reports:
|
39
|
+
"""
|
40
|
+
STDIN -- 2 warnings:
|
41
|
+
[2]:Syntax: This file has unexpected token $end [https://github.com/troessner/reek/blob/master/docs/Syntax.md]
|
42
|
+
[1]:Syntax: This file has unexpected token tEQL [https://github.com/troessner/reek/blob/master/docs/Syntax.md]
|
43
|
+
"""
|
data/lib/reek/examiner.rb
CHANGED
@@ -97,12 +97,15 @@ module Reek
|
|
97
97
|
#
|
98
98
|
# :reek:TooManyStatements { max_statements: 8 }
|
99
99
|
def run
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
100
|
+
if source.valid_syntax? && syntax_tree
|
101
|
+
begin
|
102
|
+
examine_tree
|
103
|
+
rescue Errors::BaseError => exception
|
104
|
+
raise unless @error_handler.handle exception
|
105
|
+
[]
|
106
|
+
end
|
107
|
+
else
|
108
|
+
SmellDetectors::Syntax.smells_from_source(source)
|
106
109
|
end
|
107
110
|
end
|
108
111
|
|
data/lib/reek/rake/task.rb
CHANGED
data/lib/reek/smell_detectors.rb
CHANGED
@@ -18,6 +18,7 @@ require_relative 'smell_detectors/nil_check'
|
|
18
18
|
require_relative 'smell_detectors/prima_donna_method'
|
19
19
|
require_relative 'smell_detectors/repeated_conditional'
|
20
20
|
require_relative 'smell_detectors/subclassed_from_core_class'
|
21
|
+
require_relative 'smell_detectors/syntax'
|
21
22
|
require_relative 'smell_detectors/too_many_instance_variables'
|
22
23
|
require_relative 'smell_detectors/too_many_constants'
|
23
24
|
require_relative 'smell_detectors/too_many_methods'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base_detector'
|
4
|
+
|
5
|
+
module Reek
|
6
|
+
module SmellDetectors
|
7
|
+
# Check syntax errors.
|
8
|
+
# Note: this detector is called by examiner directly unlike other detectors.
|
9
|
+
class Syntax < BaseDetector
|
10
|
+
DummyContext = Struct.new(:exp, :full_name).new(
|
11
|
+
Struct.new('Exp', :source).new(nil),
|
12
|
+
'This file')
|
13
|
+
|
14
|
+
def self.contexts
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.smells_from_source(source)
|
19
|
+
new.smells_from_source(source)
|
20
|
+
end
|
21
|
+
|
22
|
+
# :reek:FeatureEnvy
|
23
|
+
def smells_from_source(source)
|
24
|
+
source.diagnostics.map do |diagnostic|
|
25
|
+
smell_warning(
|
26
|
+
context: DummyContext,
|
27
|
+
lines: [diagnostic.location.line],
|
28
|
+
message: "has #{diagnostic.message}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -7,7 +7,6 @@ end
|
|
7
7
|
require_relative '../tree_dresser'
|
8
8
|
require_relative '../ast/node'
|
9
9
|
require_relative '../ast/builder'
|
10
|
-
require_relative '../errors/parse_error'
|
11
10
|
|
12
11
|
# Opt in to new way of representing lambdas
|
13
12
|
Parser::Builders::Default.emit_lambda = true
|
@@ -21,7 +20,7 @@ module Reek
|
|
21
20
|
IO_IDENTIFIER = 'STDIN'.freeze
|
22
21
|
STRING_IDENTIFIER = 'string'.freeze
|
23
22
|
|
24
|
-
attr_reader :origin
|
23
|
+
attr_reader :origin, :diagnostics, :syntax_tree
|
25
24
|
|
26
25
|
# Initializer.
|
27
26
|
#
|
@@ -29,9 +28,9 @@ module Reek
|
|
29
28
|
# origin - 'STDIN', 'string' or a filepath as String
|
30
29
|
# parser - the parser to use for generating AST's out of the given source
|
31
30
|
def initialize(code:, origin:, parser: default_parser)
|
32
|
-
@source = code
|
33
31
|
@origin = origin
|
34
|
-
@
|
32
|
+
@diagnostics = []
|
33
|
+
@syntax_tree = parse(parser, code)
|
35
34
|
end
|
36
35
|
|
37
36
|
# Initializes an instance of SourceCode given a source.
|
@@ -53,13 +52,22 @@ module Reek
|
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
55
|
+
# @return [true|false] Returns true if parsed file does not have any syntax errors.
|
56
|
+
def valid_syntax?
|
57
|
+
@diagnostics.none? { |diagnostic| [:error, :fatal].include?(diagnostic.level) }
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
attr_reader :source
|
63
|
+
|
56
64
|
# Parses the given source into an AST and associates the source code comments with it.
|
57
65
|
# This AST is then traversed by a TreeDresser which adorns the nodes in the AST
|
58
66
|
# with our SexpExtensions.
|
59
67
|
# Finally this AST is returned where each node is an anonymous subclass of Reek::AST::Node
|
60
68
|
#
|
61
|
-
# Important to note is that Reek will not fail on unparseable files but rather
|
62
|
-
#
|
69
|
+
# Important to note is that Reek will not fail on unparseable files but rather register a
|
70
|
+
# parse error to @diagnostics and then just continue.
|
63
71
|
#
|
64
72
|
# Given this @source:
|
65
73
|
#
|
@@ -82,36 +90,34 @@ module Reek
|
|
82
90
|
# where each node is possibly adorned with our SexpExtensions (see ast/ast_node_class_map
|
83
91
|
# and ast/sexp_extensions for details).
|
84
92
|
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
93
|
+
# @param parser [Parser::Ruby24]
|
94
|
+
# @param source [String] - Ruby code
|
95
|
+
# @return [Anonymous subclass of Reek::AST::Node] the AST presentation
|
96
|
+
# for the given source
|
97
|
+
def parse(parser, source)
|
98
|
+
buffer = Parser::Source::Buffer.new(origin, 1)
|
99
|
+
buffer.source = source
|
100
|
+
begin
|
101
|
+
ast, comments = parser.parse_with_comments(buffer)
|
102
|
+
rescue Parser::SyntaxError # rubocop:disable Lint/HandleExceptions
|
103
|
+
# All errors are in diagnostics. No need to handle exception.
|
104
|
+
end
|
98
105
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
106
|
+
# See https://whitequark.github.io/parser/Parser/Source/Comment/Associator.html
|
107
|
+
comment_map = Parser::Source::Comment.associate(ast, comments) if ast
|
108
|
+
TreeDresser.new.dress(ast, comment_map)
|
103
109
|
end
|
104
110
|
|
105
|
-
|
106
|
-
|
107
|
-
attr_reader :parser, :source
|
108
|
-
|
109
|
-
# :reek:UtilityFunction
|
111
|
+
# :reek:TooManyStatements: { max_statements: 6 }
|
112
|
+
# :reek:FeatureEnvy
|
110
113
|
def default_parser
|
111
114
|
Parser::Ruby24.new(AST::Builder.new).tap do |parser|
|
112
115
|
diagnostics = parser.diagnostics
|
113
|
-
diagnostics.all_errors_are_fatal =
|
114
|
-
diagnostics.ignore_warnings =
|
116
|
+
diagnostics.all_errors_are_fatal = false
|
117
|
+
diagnostics.ignore_warnings = false
|
118
|
+
diagnostics.consumer = lambda do |diagnostic|
|
119
|
+
@diagnostics << diagnostic
|
120
|
+
end
|
115
121
|
end
|
116
122
|
end
|
117
123
|
end
|
data/lib/reek/version.rb
CHANGED
@@ -34,50 +34,31 @@ RSpec.describe Reek::Source::SourceCode do
|
|
34
34
|
|
35
35
|
context 'when the parser fails' do
|
36
36
|
let(:source_name) { 'Test source' }
|
37
|
-
let(:
|
38
|
-
let(:parser) { instance_double('Parser::Ruby24') }
|
39
|
-
let(:src) { described_class.new(code: '', origin: source_name, parser: parser) }
|
40
|
-
|
41
|
-
shared_examples_for 'handling and recording the error' do
|
42
|
-
it 'raises an informative error' do
|
43
|
-
expect { src.syntax_tree }.
|
44
|
-
to raise_error(/#{source_name}: #{error_class.name}: #{error_message}/)
|
45
|
-
end
|
46
|
-
end
|
37
|
+
let(:src) { described_class.new(code: code, origin: source_name, **parser) }
|
47
38
|
|
48
39
|
context 'with a Parser::SyntaxError' do
|
49
|
-
let(:
|
50
|
-
let(:
|
51
|
-
|
52
|
-
before do
|
53
|
-
allow(parser).to receive(:parse_with_comments).
|
54
|
-
and_raise error_class.new(diagnostic)
|
55
|
-
end
|
40
|
+
let(:code) { '== Invalid Syntax ==' }
|
41
|
+
let(:parser) { {} }
|
56
42
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
context 'with a Racc::ParseError' do
|
61
|
-
let(:error_class) { Racc::ParseError }
|
62
|
-
|
63
|
-
before do
|
64
|
-
allow(parser).to receive(:parse_with_comments).
|
65
|
-
and_raise(error_class.new(error_message))
|
43
|
+
it 'adds a diagnostic' do
|
44
|
+
expect(src.diagnostics.size).to eq 2
|
66
45
|
end
|
67
|
-
|
68
|
-
it_behaves_like 'handling and recording the error'
|
69
46
|
end
|
70
47
|
|
71
48
|
context 'with a generic error' do
|
49
|
+
let(:code) { '' }
|
72
50
|
let(:error_class) { RuntimeError }
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
51
|
+
let(:error_message) { 'An error' }
|
52
|
+
let(:parser) do
|
53
|
+
parser = instance_double('Parser::Ruby24')
|
54
|
+
allow(parser).to receive(:parse_with_comments).and_raise(error_class, error_message)
|
55
|
+
{
|
56
|
+
parser: parser
|
57
|
+
}
|
77
58
|
end
|
78
59
|
|
79
60
|
it 'raises the error' do
|
80
|
-
expect { src
|
61
|
+
expect { src }.to raise_error error_class, error_message
|
81
62
|
end
|
82
63
|
end
|
83
64
|
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.
|
4
|
+
version: 4.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Rutherford
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2017-
|
14
|
+
date: 2017-05-31 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: codeclimate-engine-rb
|
@@ -230,7 +230,6 @@ files:
|
|
230
230
|
- lib/reek/errors/base_error.rb
|
231
231
|
- lib/reek/errors/garbage_detector_configuration_in_comment_error.rb
|
232
232
|
- lib/reek/errors/incomprehensible_source_error.rb
|
233
|
-
- lib/reek/errors/parse_error.rb
|
234
233
|
- lib/reek/examiner.rb
|
235
234
|
- lib/reek/logging_error_handler.rb
|
236
235
|
- lib/reek/rake/task.rb
|
@@ -275,6 +274,7 @@ files:
|
|
275
274
|
- lib/reek/smell_detectors/prima_donna_method.rb
|
276
275
|
- lib/reek/smell_detectors/repeated_conditional.rb
|
277
276
|
- lib/reek/smell_detectors/subclassed_from_core_class.rb
|
277
|
+
- lib/reek/smell_detectors/syntax.rb
|
278
278
|
- lib/reek/smell_detectors/too_many_constants.rb
|
279
279
|
- lib/reek/smell_detectors/too_many_instance_variables.rb
|
280
280
|
- lib/reek/smell_detectors/too_many_methods.rb
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'base_error'
|
4
|
-
|
5
|
-
module Reek
|
6
|
-
module Errors
|
7
|
-
# Gets raised when Reek is unable to process the source
|
8
|
-
class ParseError < BaseError
|
9
|
-
MESSAGE_TEMPLATE = '%s: %s: %s'.freeze
|
10
|
-
|
11
|
-
def initialize(origin:, original_exception:)
|
12
|
-
message = format(MESSAGE_TEMPLATE,
|
13
|
-
origin,
|
14
|
-
original_exception.class.name,
|
15
|
-
original_exception.message)
|
16
|
-
super message
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|