reek 4.6.2 → 4.7.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 +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
|