rubocop-ast 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -5
  3. data/lib/rubocop/ast.rb +2 -1
  4. data/lib/rubocop/ast/builder.rb +3 -1
  5. data/lib/rubocop/ast/ext/range.rb +28 -0
  6. data/lib/rubocop/ast/node.rb +23 -6
  7. data/lib/rubocop/ast/node/array_node.rb +2 -8
  8. data/lib/rubocop/ast/node/break_node.rb +1 -6
  9. data/lib/rubocop/ast/node/case_match_node.rb +3 -9
  10. data/lib/rubocop/ast/node/case_node.rb +13 -9
  11. data/lib/rubocop/ast/node/def_node.rb +4 -23
  12. data/lib/rubocop/ast/node/defined_node.rb +2 -0
  13. data/lib/rubocop/ast/node/float_node.rb +1 -0
  14. data/lib/rubocop/ast/node/hash_node.rb +21 -8
  15. data/lib/rubocop/ast/node/if_node.rb +7 -14
  16. data/lib/rubocop/ast/node/index_node.rb +5 -3
  17. data/lib/rubocop/ast/node/indexasgn_node.rb +5 -3
  18. data/lib/rubocop/ast/node/int_node.rb +1 -0
  19. data/lib/rubocop/ast/node/lambda_node.rb +10 -3
  20. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +0 -7
  21. data/lib/rubocop/ast/node/mixin/parameterized_node.rb +55 -0
  22. data/lib/rubocop/ast/node/next_node.rb +12 -0
  23. data/lib/rubocop/ast/node/pair_node.rb +2 -2
  24. data/lib/rubocop/ast/node/return_node.rb +1 -13
  25. data/lib/rubocop/ast/node/send_node.rb +7 -1
  26. data/lib/rubocop/ast/node/super_node.rb +2 -0
  27. data/lib/rubocop/ast/node/when_node.rb +3 -9
  28. data/lib/rubocop/ast/node/yield_node.rb +2 -0
  29. data/lib/rubocop/ast/node_pattern.rb +99 -86
  30. data/lib/rubocop/ast/processed_source.rb +54 -16
  31. data/lib/rubocop/ast/traversal.rb +1 -1
  32. data/lib/rubocop/ast/version.rb +1 -1
  33. metadata +9 -8
  34. 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: 4108494066548a429e972d3f2afcaa9adfd39072a929308cdb20e4a602fef66d
4
- data.tar.gz: 413b4382539bffed1760d0599bc093ad40ffef64992f821484994150903812da
3
+ metadata.gz: 918c6017183db74497fc68166973904312bac7583f7752c2e55d1829574cb248
4
+ data.tar.gz: 1d04eb24fcbaec96b4bf0f17694018c31034fce4b3d81a9446ca98b3085e05a4
5
5
  SHA512:
6
- metadata.gz: 97af9dd864e8f6867614a79b2aac596e18e147b9a55bcc67b8755e47ef762730ec69612dcc6858ee12017b33beae0b89e008e1267034f1730682015c4efa4255
7
- data.tar.gz: 807305ab6dc90885fff96d1387d787debf8ce8f27a0d150ad4bf86a76d4afb2d288f0771b2399cf3c3cfb1472c72cd750e4df9e97ad07467da4615a97c062f79
6
+ metadata.gz: 54f6882ebf057c76a9c97212a62b295d03baea85ec7c44e606b412e74edce01b6c4bba93dfafa341756009a8bfa2352c4b2b3b22bdbf689dac08ddd9395a9aff
7
+ data.tar.gz: '08e60b802e83dba688bf1a31be417f9880b640194cf3b966849dd2c211de5a1f3797c8a37be3f2d3aa466d6c994b10c31277b0ed3dc708b12fe1c2f7a0f15552'
data/README.md CHANGED
@@ -6,11 +6,12 @@
6
6
  [![Maintainability](https://api.codeclimate.com/v1/badges/a29666e6373bc41bc0a9/maintainability)](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
- * `RuboCop::AST::Node`
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 `parser` gem, which `rubocop-ast` extends.
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
- The main `RuboCop` gem uses [legacy AST output from parser](https://github.com/whitequark/parser/#usage).
36
- This gem is meant to be compatible with all settings. For example, to have `-> { ... }` emitted
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
@@ -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'
@@ -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
@@ -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 (const nil? {:Class :Module}) :new ...))
317
- (casgn $_ $_ (block (send (const nil? {:Class :Module}) :new ...) ...))}
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 (const nil? :Proc) :new) ...)
500
- (send (const nil? :Proc) :new)}
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 (const nil? {:Class :Module}) :new ...)
508
- (block (send (const nil? {:Class :Module}) :new ...) ...)}
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
- def values
18
- each_child_node.to_a
19
- end
17
+ alias values children
20
18
 
21
- # Calls the given block for all values in the `array` literal.
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 MethodDispatchNode
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
- # Calls the given block for each `in_pattern` node in the `in` statement.
19
- # If no block is given, an `Enumerator` is returned.
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 do |condition|
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
- # Calls the given block for each `when` node in the `case` statement.
19
- # If no block is given, an `Enumerator` is returned.
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 do |condition|
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
- node_parts[2]
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
- node_parts[1]
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
- node_parts[0]
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
- node_parts[3]
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
@@ -12,6 +12,8 @@ module RuboCop
12
12
  def node_parts
13
13
  [nil, :defined?, *to_a]
14
14
  end
15
+
16
+ alias arguments children
15
17
  end
16
18
  end
17
19
  end
@@ -6,6 +6,7 @@ module RuboCop
6
6
  # node when the builder constructs the AST, making its methods available to
7
7
  # all `float` nodes within RuboCop.
8
8
  class FloatNode < Node
9
+ include BasicLiteralNode
9
10
  include NumericNode
10
11
  end
11
12
  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 do |key|
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 do |value|
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
- if keyword == 'if'
68
- 'unless'
69
- elsif keyword == 'unless'
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 else_branch
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
- # Calls the given block for each branch node in the conditional statement.
162
- # If no block is given, an `Enumerator` is returned.
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 do |branch|
170
- yield branch
171
- end
164
+ branches.each(&block)
172
165
  end
173
166
  end
174
167
  end