rubocop-ast 0.1.0 → 0.3.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/README.md +9 -5
- data/lib/rubocop/ast.rb +2 -1
- data/lib/rubocop/ast/builder.rb +3 -1
- data/lib/rubocop/ast/ext/range.rb +28 -0
- data/lib/rubocop/ast/node.rb +23 -6
- data/lib/rubocop/ast/node/array_node.rb +2 -8
- data/lib/rubocop/ast/node/break_node.rb +1 -6
- data/lib/rubocop/ast/node/case_match_node.rb +3 -9
- data/lib/rubocop/ast/node/case_node.rb +13 -9
- data/lib/rubocop/ast/node/def_node.rb +4 -23
- data/lib/rubocop/ast/node/defined_node.rb +2 -0
- data/lib/rubocop/ast/node/float_node.rb +1 -0
- data/lib/rubocop/ast/node/hash_node.rb +21 -8
- data/lib/rubocop/ast/node/if_node.rb +7 -14
- data/lib/rubocop/ast/node/index_node.rb +5 -3
- data/lib/rubocop/ast/node/indexasgn_node.rb +5 -3
- data/lib/rubocop/ast/node/int_node.rb +1 -0
- data/lib/rubocop/ast/node/lambda_node.rb +10 -3
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +0 -7
- data/lib/rubocop/ast/node/mixin/parameterized_node.rb +55 -0
- data/lib/rubocop/ast/node/next_node.rb +12 -0
- data/lib/rubocop/ast/node/pair_node.rb +2 -2
- data/lib/rubocop/ast/node/return_node.rb +1 -13
- data/lib/rubocop/ast/node/send_node.rb +7 -1
- data/lib/rubocop/ast/node/super_node.rb +2 -0
- data/lib/rubocop/ast/node/when_node.rb +3 -9
- data/lib/rubocop/ast/node/yield_node.rb +2 -0
- data/lib/rubocop/ast/node_pattern.rb +99 -86
- data/lib/rubocop/ast/processed_source.rb +54 -16
- data/lib/rubocop/ast/traversal.rb +1 -1
- data/lib/rubocop/ast/version.rb +1 -1
- metadata +9 -8
- data/lib/rubocop/ast/node/retry_node.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 918c6017183db74497fc68166973904312bac7583f7752c2e55d1829574cb248
|
4
|
+
data.tar.gz: 1d04eb24fcbaec96b4bf0f17694018c31034fce4b3d81a9446ca98b3085e05a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54f6882ebf057c76a9c97212a62b295d03baea85ec7c44e606b412e74edce01b6c4bba93dfafa341756009a8bfa2352c4b2b3b22bdbf689dac08ddd9395a9aff
|
7
|
+
data.tar.gz: '08e60b802e83dba688bf1a31be417f9880b640194cf3b966849dd2c211de5a1f3797c8a37be3f2d3aa466d6c994b10c31277b0ed3dc708b12fe1c2f7a0f15552'
|
data/README.md
CHANGED
@@ -6,11 +6,12 @@
|
|
6
6
|
[](https://codeclimate.com/github/rubocop-hq/rubocop-ast/maintainability)
|
7
7
|
|
8
8
|
Contains the classes needed by [RuboCop](https://github.com/rubocop-hq/rubocop) to deal with Ruby's AST, in particular:
|
9
|
-
|
9
|
+
|
10
|
+
* `RuboCop::AST::Node` ([doc](docs/modules/ROOT/pages/node_types.adoc))
|
10
11
|
* `RuboCop::AST::NodePattern` ([doc](docs/modules/ROOT/pages/node_pattern.adoc))
|
11
12
|
|
12
13
|
This gem may be used independently from the main RuboCop gem. It was extracted from RuboCop in version 0.84 and its only
|
13
|
-
dependency is the
|
14
|
+
dependency is the [parser](https://github.com/whitequark/parser) gem, which `rubocop-ast` extends.
|
14
15
|
|
15
16
|
## Installation
|
16
17
|
|
@@ -28,12 +29,15 @@ gem 'rubocop-ast'
|
|
28
29
|
|
29
30
|
## Usage
|
30
31
|
|
31
|
-
Refer to the documentation of `RuboCop::AST::Node` and [`RuboCop::AST::NodePattern`](docs/modules/ROOT/pages/node_pattern.adoc)
|
32
|
+
Refer to the documentation of [`RuboCop::AST::Node`](docs/modules/ROOT/pages/node_types.adoc) and [`RuboCop::AST::NodePattern`](docs/modules/ROOT/pages/node_pattern.adoc)
|
33
|
+
|
34
|
+
See the [docs site](https://docs.rubocop.org/rubocop-ast) for more details.
|
32
35
|
|
33
36
|
### Parser compatibility switches
|
34
37
|
|
35
|
-
|
36
|
-
|
38
|
+
This gem, by default, uses most [legacy AST output from parser](https://github.com/whitequark/parser/#usage), except for `emit_forward_arg` which is set to `true`.
|
39
|
+
|
40
|
+
The main `RuboCop` gem uses these defaults (and is currently only compatible with these), but this gem can be used separately from `RuboCop` and is meant to be compatible with all settings. For example, to have `-> { ... }` emitted
|
37
41
|
as `LambdaNode` instead of `SendNode`:
|
38
42
|
|
39
43
|
```ruby
|
data/lib/rubocop/ast.rb
CHANGED
@@ -4,6 +4,7 @@ require 'parser'
|
|
4
4
|
require 'forwardable'
|
5
5
|
require 'set'
|
6
6
|
|
7
|
+
require_relative 'ast/ext/range'
|
7
8
|
require_relative 'ast/node_pattern'
|
8
9
|
require_relative 'ast/sexp'
|
9
10
|
require_relative 'ast/node'
|
@@ -41,12 +42,12 @@ require_relative 'ast/node/int_node'
|
|
41
42
|
require_relative 'ast/node/keyword_splat_node'
|
42
43
|
require_relative 'ast/node/lambda_node'
|
43
44
|
require_relative 'ast/node/module_node'
|
45
|
+
require_relative 'ast/node/next_node'
|
44
46
|
require_relative 'ast/node/or_node'
|
45
47
|
require_relative 'ast/node/pair_node'
|
46
48
|
require_relative 'ast/node/range_node'
|
47
49
|
require_relative 'ast/node/regexp_node'
|
48
50
|
require_relative 'ast/node/resbody_node'
|
49
|
-
require_relative 'ast/node/retry_node'
|
50
51
|
require_relative 'ast/node/return_node'
|
51
52
|
require_relative 'ast/node/self_class_node'
|
52
53
|
require_relative 'ast/node/send_node'
|
data/lib/rubocop/ast/builder.rb
CHANGED
@@ -14,6 +14,8 @@ module RuboCop
|
|
14
14
|
# parser = Parser::Ruby25.new(builder)
|
15
15
|
# root_node = parser.parse(buffer)
|
16
16
|
class Builder < Parser::Builders::Default
|
17
|
+
self.emit_forward_arg = true
|
18
|
+
|
17
19
|
NODE_MAP = {
|
18
20
|
and: AndNode,
|
19
21
|
alias: AliasNode,
|
@@ -42,11 +44,11 @@ module RuboCop
|
|
42
44
|
kwsplat: KeywordSplatNode,
|
43
45
|
lambda: LambdaNode,
|
44
46
|
module: ModuleNode,
|
47
|
+
next: NextNode,
|
45
48
|
or: OrNode,
|
46
49
|
pair: PairNode,
|
47
50
|
regexp: RegexpNode,
|
48
51
|
resbody: ResbodyNode,
|
49
|
-
retry: RetryNode,
|
50
52
|
return: ReturnNode,
|
51
53
|
csend: SendNode,
|
52
54
|
send: SendNode,
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
module Ext
|
6
|
+
# Extensions to Parser::AST::Range
|
7
|
+
module Range
|
8
|
+
# @return [Range] the range of line numbers for the node
|
9
|
+
# If `exclude_end` is `true`, then the range will be exclusive.
|
10
|
+
#
|
11
|
+
# Assume that `node` corresponds to the following array literal:
|
12
|
+
#
|
13
|
+
# [
|
14
|
+
# :foo,
|
15
|
+
# :bar
|
16
|
+
# ]
|
17
|
+
#
|
18
|
+
# node.loc.begin.line_span # => 1..1
|
19
|
+
# node.loc.expression.line_span(exclude_end: true) # => 1...4
|
20
|
+
def line_span(exclude_end: false)
|
21
|
+
::Range.new(first_line, last_line, exclude_end)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
::Parser::Source::Range.include ::RuboCop::AST::Ext::Range
|
data/lib/rubocop/ast/node.rb
CHANGED
@@ -313,8 +313,8 @@ module RuboCop
|
|
313
313
|
def_node_matcher :defined_module0, <<~PATTERN
|
314
314
|
{(class (const $_ $_) ...)
|
315
315
|
(module (const $_ $_) ...)
|
316
|
-
(casgn $_ $_ (send (
|
317
|
-
(casgn $_ $_ (block (send (
|
316
|
+
(casgn $_ $_ (send #global_const?({:Class :Module}) :new ...))
|
317
|
+
(casgn $_ $_ (block (send #global_const?({:Class :Module}) :new ...) ...))}
|
318
318
|
PATTERN
|
319
319
|
|
320
320
|
private :defined_module0
|
@@ -496,16 +496,33 @@ module RuboCop
|
|
496
496
|
|
497
497
|
def_node_matcher :proc?, <<~PATTERN
|
498
498
|
{(block (send nil? :proc) ...)
|
499
|
-
(block (send (
|
500
|
-
(send (
|
499
|
+
(block (send #global_const?(:Proc) :new) ...)
|
500
|
+
(send #global_const?(:Proc) :new)}
|
501
501
|
PATTERN
|
502
502
|
|
503
503
|
def_node_matcher :lambda?, '({block numblock} (send nil? :lambda) ...)'
|
504
504
|
def_node_matcher :lambda_or_proc?, '{lambda? proc?}'
|
505
505
|
|
506
|
+
def_node_matcher :global_const?, '(const {nil? cbase} %1)'
|
507
|
+
|
506
508
|
def_node_matcher :class_constructor?, <<~PATTERN
|
507
|
-
{ (send (
|
508
|
-
(block (send (
|
509
|
+
{ (send #global_const?({:Class :Module}) :new ...)
|
510
|
+
(block (send #global_const?({:Class :Module}) :new ...) ...)}
|
511
|
+
PATTERN
|
512
|
+
|
513
|
+
def_node_matcher :struct_constructor?, <<~PATTERN
|
514
|
+
(block (send #global_const?(:Struct) :new ...) _ $_)
|
515
|
+
PATTERN
|
516
|
+
|
517
|
+
def_node_matcher :class_definition?, <<~PATTERN
|
518
|
+
{(class _ _ $_)
|
519
|
+
(sclass _ $_)
|
520
|
+
(block (send #global_const?({:Struct :Class}) :new ...) _ $_)}
|
521
|
+
PATTERN
|
522
|
+
|
523
|
+
def_node_matcher :module_definition?, <<~PATTERN
|
524
|
+
{(module _ $_)
|
525
|
+
(block (send #global_const?(:Module) :new ...) _ $_)}
|
509
526
|
PATTERN
|
510
527
|
|
511
528
|
# Some expressions are evaluated for their value, some for their side
|
@@ -14,15 +14,9 @@ module RuboCop
|
|
14
14
|
# Returns an array of all value nodes in the `array` literal.
|
15
15
|
#
|
16
16
|
# @return [Array<Node>] an array of value nodes
|
17
|
-
|
18
|
-
each_child_node.to_a
|
19
|
-
end
|
17
|
+
alias values children
|
20
18
|
|
21
|
-
#
|
22
|
-
#
|
23
|
-
# @yieldparam [Node] node each node
|
24
|
-
# @return [self] if a block is given
|
25
|
-
# @return [Enumerator] if no block is given
|
19
|
+
# @deprecated Use `values.each` (a.k.a. `children.each`)
|
26
20
|
def each_value(&block)
|
27
21
|
return to_enum(__method__) unless block_given?
|
28
22
|
|
@@ -6,12 +6,7 @@ module RuboCop
|
|
6
6
|
# plain node when the builder constructs the AST, making its methods
|
7
7
|
# available to all `break` nodes within RuboCop.
|
8
8
|
class BreakNode < Node
|
9
|
-
include
|
10
|
-
include ParameterizedNode
|
11
|
-
|
12
|
-
def arguments
|
13
|
-
[]
|
14
|
-
end
|
9
|
+
include ParameterizedNode::WrappedArguments
|
15
10
|
end
|
16
11
|
end
|
17
12
|
end
|
@@ -15,17 +15,11 @@ module RuboCop
|
|
15
15
|
'case'
|
16
16
|
end
|
17
17
|
|
18
|
-
#
|
19
|
-
|
20
|
-
#
|
21
|
-
# @return [self] if a block is given
|
22
|
-
# @return [Enumerator] if no block is given
|
23
|
-
def each_in_pattern
|
18
|
+
# @deprecated Use `in_pattern_branches.each`
|
19
|
+
def each_in_pattern(&block)
|
24
20
|
return in_pattern_branches.to_enum(__method__) unless block_given?
|
25
21
|
|
26
|
-
in_pattern_branches.each
|
27
|
-
yield condition
|
28
|
-
end
|
22
|
+
in_pattern_branches.each(&block)
|
29
23
|
|
30
24
|
self
|
31
25
|
end
|
@@ -15,17 +15,11 @@ module RuboCop
|
|
15
15
|
'case'
|
16
16
|
end
|
17
17
|
|
18
|
-
#
|
19
|
-
|
20
|
-
#
|
21
|
-
# @return [self] if a block is given
|
22
|
-
# @return [Enumerator] if no block is given
|
23
|
-
def each_when
|
18
|
+
# @deprecated Use `when_branches.each`
|
19
|
+
def each_when(&block)
|
24
20
|
return when_branches.to_enum(__method__) unless block_given?
|
25
21
|
|
26
|
-
when_branches.each
|
27
|
-
yield condition
|
28
|
-
end
|
22
|
+
when_branches.each(&block)
|
29
23
|
|
30
24
|
self
|
31
25
|
end
|
@@ -37,6 +31,16 @@ module RuboCop
|
|
37
31
|
node_parts[1...-1]
|
38
32
|
end
|
39
33
|
|
34
|
+
# Returns an array of all the when branches in the `case` statement.
|
35
|
+
#
|
36
|
+
# @return [Array<Node, nil>] an array of the bodies of the when branches
|
37
|
+
# and the else (if any). Note that these bodies could be nil.
|
38
|
+
def branches
|
39
|
+
bodies = when_branches.map(&:body)
|
40
|
+
bodies.push(else_branch) if else?
|
41
|
+
bodies
|
42
|
+
end
|
43
|
+
|
40
44
|
# Returns the else branch of the `case` statement, if any.
|
41
45
|
#
|
42
46
|
# @return [Node] the else branch node of the `case` statement
|
@@ -31,14 +31,14 @@ module RuboCop
|
|
31
31
|
#
|
32
32
|
# @return [Symbol] the name of the defined method
|
33
33
|
def method_name
|
34
|
-
|
34
|
+
children[-3]
|
35
35
|
end
|
36
36
|
|
37
37
|
# An array containing the arguments of the method definition.
|
38
38
|
#
|
39
39
|
# @return [Array<Node>] the arguments of the method definition
|
40
40
|
def arguments
|
41
|
-
|
41
|
+
children[-2]
|
42
42
|
end
|
43
43
|
|
44
44
|
# The body of the method definition.
|
@@ -49,33 +49,14 @@ module RuboCop
|
|
49
49
|
#
|
50
50
|
# @return [Node] the body of the method definition
|
51
51
|
def body
|
52
|
-
|
52
|
+
children[-1]
|
53
53
|
end
|
54
54
|
|
55
55
|
# The receiver of the method definition, if any.
|
56
56
|
#
|
57
57
|
# @return [Node, nil] the receiver of the method definition, or `nil`.
|
58
58
|
def receiver
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
# Custom destructuring method. This can be used to normalize
|
63
|
-
# destructuring for different variations of the node.
|
64
|
-
#
|
65
|
-
# In this case, the `def` node destructures into:
|
66
|
-
#
|
67
|
-
# `method_name, arguments, body`
|
68
|
-
#
|
69
|
-
# while the `defs` node destructures into:
|
70
|
-
#
|
71
|
-
# `receiver, method_name, arguments, body`
|
72
|
-
#
|
73
|
-
# so we reverse the destructured array to get the optional receiver
|
74
|
-
# at the end, where it can be discarded.
|
75
|
-
#
|
76
|
-
# @return [Array] the different parts of the `def` or `defs` node
|
77
|
-
def node_parts
|
78
|
-
to_a.reverse
|
59
|
+
children[-4]
|
79
60
|
end
|
80
61
|
end
|
81
62
|
end
|
@@ -8,6 +8,9 @@ module RuboCop
|
|
8
8
|
class HashNode < Node
|
9
9
|
# Returns an array of all the key value pairs in the `hash` literal.
|
10
10
|
#
|
11
|
+
# @note this may be different from children as `kwsplat` nodes are
|
12
|
+
# ignored.
|
13
|
+
#
|
11
14
|
# @return [Array<PairNode>] an array of `pair` nodes
|
12
15
|
def pairs
|
13
16
|
each_pair.to_a
|
@@ -23,6 +26,8 @@ module RuboCop
|
|
23
26
|
# Calls the given block for each `pair` node in the `hash` literal.
|
24
27
|
# If no block is given, an `Enumerator` is returned.
|
25
28
|
#
|
29
|
+
# @note `kwsplat` nodes are ignored.
|
30
|
+
#
|
26
31
|
# @return [self] if a block is given
|
27
32
|
# @return [Enumerator] if no block is given
|
28
33
|
def each_pair
|
@@ -37,6 +42,8 @@ module RuboCop
|
|
37
42
|
|
38
43
|
# Returns an array of all the keys in the `hash` literal.
|
39
44
|
#
|
45
|
+
# @note `kwsplat` nodes are ignored.
|
46
|
+
#
|
40
47
|
# @return [Array<Node>] an array of keys in the `hash` literal
|
41
48
|
def keys
|
42
49
|
each_key.to_a
|
@@ -45,20 +52,22 @@ module RuboCop
|
|
45
52
|
# Calls the given block for each `key` node in the `hash` literal.
|
46
53
|
# If no block is given, an `Enumerator` is returned.
|
47
54
|
#
|
55
|
+
# @note `kwsplat` nodes are ignored.
|
56
|
+
#
|
48
57
|
# @return [self] if a block is given
|
49
58
|
# @return [Enumerator] if no block is given
|
50
|
-
def each_key
|
59
|
+
def each_key(&block)
|
51
60
|
return pairs.map(&:key).to_enum unless block_given?
|
52
61
|
|
53
|
-
pairs.map(&:key).each
|
54
|
-
yield key
|
55
|
-
end
|
62
|
+
pairs.map(&:key).each(&block)
|
56
63
|
|
57
64
|
self
|
58
65
|
end
|
59
66
|
|
60
67
|
# Returns an array of all the values in the `hash` literal.
|
61
68
|
#
|
69
|
+
# @note `kwsplat` nodes are ignored.
|
70
|
+
#
|
62
71
|
# @return [Array<Node>] an array of values in the `hash` literal
|
63
72
|
def values
|
64
73
|
each_pair.map(&:value)
|
@@ -67,14 +76,14 @@ module RuboCop
|
|
67
76
|
# Calls the given block for each `value` node in the `hash` literal.
|
68
77
|
# If no block is given, an `Enumerator` is returned.
|
69
78
|
#
|
79
|
+
# @note `kwsplat` nodes are ignored.
|
80
|
+
#
|
70
81
|
# @return [self] if a block is given
|
71
82
|
# @return [Enumerator] if no block is given
|
72
|
-
def each_value
|
83
|
+
def each_value(&block)
|
73
84
|
return pairs.map(&:value).to_enum unless block_given?
|
74
85
|
|
75
|
-
pairs.map(&:value).each
|
76
|
-
yield value
|
77
|
-
end
|
86
|
+
pairs.map(&:value).each(&block)
|
78
87
|
|
79
88
|
self
|
80
89
|
end
|
@@ -85,6 +94,8 @@ module RuboCop
|
|
85
94
|
# @note A multiline `pair` is considered to be on the same line if it
|
86
95
|
# shares any of its lines with another `pair`
|
87
96
|
#
|
97
|
+
# @note `kwsplat` nodes are ignored.
|
98
|
+
#
|
88
99
|
# @return [Boolean] whether any `pair` nodes are on the same line
|
89
100
|
def pairs_on_same_line?
|
90
101
|
pairs.each_cons(2).any? { |first, second| first.same_line?(second) }
|
@@ -93,6 +104,8 @@ module RuboCop
|
|
93
104
|
# Checks whether this `hash` uses a mix of hash rocket and colon
|
94
105
|
# delimiters for its pairs.
|
95
106
|
#
|
107
|
+
# @note `kwsplat` nodes are ignored.
|
108
|
+
#
|
96
109
|
# @return [Boolean] whether the `hash` uses mixed delimiters
|
97
110
|
def mixed_delimiters?
|
98
111
|
pairs.map(&:delimiter).uniq.size > 1
|
@@ -64,10 +64,9 @@ module RuboCop
|
|
64
64
|
#
|
65
65
|
# @return [String] the inverse keyword of the `if` statement
|
66
66
|
def inverse_keyword
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
'if'
|
67
|
+
case keyword
|
68
|
+
when 'if' then 'unless'
|
69
|
+
when 'unless' then 'if'
|
71
70
|
else
|
72
71
|
''
|
73
72
|
end
|
@@ -148,7 +147,7 @@ module RuboCop
|
|
148
147
|
def branches
|
149
148
|
branches = [if_branch]
|
150
149
|
|
151
|
-
return branches unless
|
150
|
+
return branches unless else?
|
152
151
|
|
153
152
|
other_branches = if elsif_conditional?
|
154
153
|
else_branch.branches
|
@@ -158,17 +157,11 @@ module RuboCop
|
|
158
157
|
branches.concat(other_branches)
|
159
158
|
end
|
160
159
|
|
161
|
-
#
|
162
|
-
|
163
|
-
#
|
164
|
-
# @return [self] if a block is given
|
165
|
-
# @return [Enumerator] if no block is given
|
166
|
-
def each_branch
|
160
|
+
# @deprecated Use `branches.each`
|
161
|
+
def each_branch(&block)
|
167
162
|
return branches.to_enum(__method__) unless block_given?
|
168
163
|
|
169
|
-
branches.each
|
170
|
-
yield branch
|
171
|
-
end
|
164
|
+
branches.each(&block)
|
172
165
|
end
|
173
166
|
end
|
174
167
|
end
|