rubocop-ast 0.1.0 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -5
  3. data/lib/rubocop/ast.rb +5 -1
  4. data/lib/rubocop/ast/builder.rb +5 -1
  5. data/lib/rubocop/ast/ext/range.rb +28 -0
  6. data/lib/rubocop/ast/ext/set.rb +12 -0
  7. data/lib/rubocop/ast/node.rb +63 -8
  8. data/lib/rubocop/ast/node/array_node.rb +2 -8
  9. data/lib/rubocop/ast/node/block_node.rb +1 -1
  10. data/lib/rubocop/ast/node/break_node.rb +1 -6
  11. data/lib/rubocop/ast/node/case_match_node.rb +3 -9
  12. data/lib/rubocop/ast/node/case_node.rb +13 -9
  13. data/lib/rubocop/ast/node/const_node.rb +65 -0
  14. data/lib/rubocop/ast/node/def_node.rb +4 -23
  15. data/lib/rubocop/ast/node/defined_node.rb +2 -0
  16. data/lib/rubocop/ast/node/float_node.rb +1 -0
  17. data/lib/rubocop/ast/node/hash_node.rb +21 -8
  18. data/lib/rubocop/ast/node/if_node.rb +7 -14
  19. data/lib/rubocop/ast/node/index_node.rb +5 -3
  20. data/lib/rubocop/ast/node/indexasgn_node.rb +5 -3
  21. data/lib/rubocop/ast/node/int_node.rb +1 -0
  22. data/lib/rubocop/ast/node/lambda_node.rb +10 -3
  23. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +0 -7
  24. data/lib/rubocop/ast/node/mixin/parameterized_node.rb +55 -0
  25. data/lib/rubocop/ast/node/next_node.rb +12 -0
  26. data/lib/rubocop/ast/node/pair_node.rb +2 -2
  27. data/lib/rubocop/ast/node/resbody_node.rb +21 -0
  28. data/lib/rubocop/ast/node/rescue_node.rb +49 -0
  29. data/lib/rubocop/ast/node/return_node.rb +1 -13
  30. data/lib/rubocop/ast/node/send_node.rb +7 -1
  31. data/lib/rubocop/ast/node/super_node.rb +2 -0
  32. data/lib/rubocop/ast/node/when_node.rb +3 -9
  33. data/lib/rubocop/ast/node/yield_node.rb +2 -0
  34. data/lib/rubocop/ast/node_pattern.rb +99 -86
  35. data/lib/rubocop/ast/processed_source.rb +94 -16
  36. data/lib/rubocop/ast/traversal.rb +2 -2
  37. data/lib/rubocop/ast/version.rb +1 -1
  38. metadata +12 -8
  39. data/lib/rubocop/ast/node/retry_node.rb +0 -17
@@ -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
@@ -17,7 +17,7 @@ module RuboCop
17
17
  # The main RuboCop runs in legacy mode; this node is only used
18
18
  # if user `AST::Builder.modernize` or `AST::Builder.emit_index=true`
19
19
  class IndexNode < Node
20
- include ParameterizedNode
20
+ include ParameterizedNode::RestArguments
21
21
  include MethodDispatchNode
22
22
 
23
23
  # For similarity with legacy mode
@@ -35,11 +35,13 @@ module RuboCop
35
35
  :[]
36
36
  end
37
37
 
38
+ private
39
+
38
40
  # An array containing the arguments of the dispatched method.
39
41
  #
40
42
  # @return [Array<Node>] the arguments of the dispatched method
41
- def arguments
42
- node_parts[1..-1]
43
+ def first_argument_index
44
+ 1
43
45
  end
44
46
  end
45
47
  end
@@ -19,7 +19,7 @@ module RuboCop
19
19
  # The main RuboCop runs in legacy mode; this node is only used
20
20
  # if user `AST::Builder.modernize` or `AST::Builder.emit_index=true`
21
21
  class IndexasgnNode < Node
22
- include ParameterizedNode
22
+ include ParameterizedNode::RestArguments
23
23
  include MethodDispatchNode
24
24
 
25
25
  # For similarity with legacy mode
@@ -37,11 +37,13 @@ module RuboCop
37
37
  :[]=
38
38
  end
39
39
 
40
+ private
41
+
40
42
  # An array containing the arguments of the dispatched method.
41
43
  #
42
44
  # @return [Array<Node>] the arguments of the dispatched method
43
- def arguments
44
- node_parts[1..-1]
45
+ def first_argument_index
46
+ 1
45
47
  end
46
48
  end
47
49
  end
@@ -6,6 +6,7 @@ module RuboCop
6
6
  # node when the builder constructs the AST, making its methods available to
7
7
  # all `int` nodes within RuboCop.
8
8
  class IntNode < Node
9
+ include BasicLiteralNode
9
10
  include NumericNode
10
11
  end
11
12
  end
@@ -21,7 +21,7 @@ module RuboCop
21
21
  # The main RuboCop runs in legacy mode; this node is only used
22
22
  # if user `AST::Builder.modernize` or `AST::Builder.emit_lambda=true`
23
23
  class LambdaNode < Node
24
- include ParameterizedNode
24
+ include ParameterizedNode::RestArguments
25
25
  include MethodDispatchNode
26
26
 
27
27
  # For similarity with legacy mode
@@ -44,14 +44,21 @@ module RuboCop
44
44
  false
45
45
  end
46
46
 
47
+ # For similarity with legacy mode
48
+ def receiver
49
+ nil
50
+ end
51
+
47
52
  # For similarity with legacy mode
48
53
  def method_name
49
54
  :lambda
50
55
  end
51
56
 
57
+ private
58
+
52
59
  # For similarity with legacy mode
53
- def arguments
54
- []
60
+ def first_argument_index
61
+ 2
55
62
  end
56
63
  end
57
64
  end
@@ -26,13 +26,6 @@ module RuboCop
26
26
  node_parts[1]
27
27
  end
28
28
 
29
- # An array containing the arguments of the dispatched method.
30
- #
31
- # @return [Array<Node>] the arguments of the dispatched method
32
- def arguments
33
- node_parts[2..-1]
34
- end
35
-
36
29
  # The `block` node associated with this method dispatch, if any.
37
30
  #
38
31
  # @return [BlockNode, nil] the `block` node associated with this method
@@ -2,6 +2,8 @@
2
2
 
3
3
  module RuboCop
4
4
  module AST
5
+ # Requires implementing `arguments`.
6
+ #
5
7
  # Common functionality for nodes that are parameterized:
6
8
  # `send`, `super`, `zsuper`, `def`, `defs`
7
9
  # and (modern only): `index`, `indexasgn`, `lambda`
@@ -57,6 +59,59 @@ module RuboCop
57
59
  arguments? &&
58
60
  (last_argument.block_pass_type? || last_argument.blockarg_type?)
59
61
  end
62
+
63
+ # A specialized `ParameterizedNode` for node that have a single child
64
+ # containing either `nil`, an argument, or a `begin` node with all the
65
+ # arguments
66
+ module WrappedArguments
67
+ include ParameterizedNode
68
+ # @return [Array] The arguments of the node.
69
+ def arguments
70
+ first = children.first
71
+ if first&.begin_type?
72
+ first.children
73
+ else
74
+ children
75
+ end
76
+ end
77
+ end
78
+
79
+ # A specialized `ParameterizedNode`.
80
+ # Requires implementing `first_argument_index`
81
+ # Implements `arguments` as `children[first_argument_index..-1]`
82
+ # and optimizes other calls
83
+ module RestArguments
84
+ include ParameterizedNode
85
+ # @return [Array<Node>] arguments, if any
86
+ def arguments
87
+ children[first_argument_index..-1].freeze
88
+ end
89
+
90
+ # A shorthand for getting the first argument of the node.
91
+ # Equivalent to `arguments.first`.
92
+ #
93
+ # @return [Node, nil] the first argument of the node,
94
+ # or `nil` if there are no arguments
95
+ def first_argument
96
+ children[first_argument_index]
97
+ end
98
+
99
+ # A shorthand for getting the last argument of the node.
100
+ # Equivalent to `arguments.last`.
101
+ #
102
+ # @return [Node, nil] the last argument of the node,
103
+ # or `nil` if there are no arguments
104
+ def last_argument
105
+ children[-1] if arguments?
106
+ end
107
+
108
+ # Checks whether this node has any arguments.
109
+ #
110
+ # @return [Boolean] whether this node has any arguments
111
+ def arguments?
112
+ children.size > first_argument_index
113
+ end
114
+ end
60
115
  end
61
116
  end
62
117
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `next` nodes. This will be used in place of a
6
+ # plain node when the builder constructs the AST, making its methods
7
+ # available to all `next` nodes within RuboCop.
8
+ class NextNode < Node
9
+ include ParameterizedNode::WrappedArguments
10
+ end
11
+ end
12
+ end
@@ -32,7 +32,7 @@ module RuboCop
32
32
  #
33
33
  # @param [Boolean] with_spacing whether to include spacing
34
34
  # @return [String] the delimiter of the `pair`
35
- def delimiter(with_spacing = false)
35
+ def delimiter(*deprecated, with_spacing: deprecated.first)
36
36
  if with_spacing
37
37
  hash_rocket? ? SPACED_HASH_ROCKET : SPACED_COLON
38
38
  else
@@ -44,7 +44,7 @@ module RuboCop
44
44
  #
45
45
  # @param [Boolean] with_spacing whether to include spacing
46
46
  # @return [String] the inverse delimiter of the `pair`
47
- def inverse_delimiter(with_spacing = false)
47
+ def inverse_delimiter(*deprecated, with_spacing: deprecated.first)
48
48
  if with_spacing
49
49
  hash_rocket? ? SPACED_COLON : SPACED_HASH_ROCKET
50
50
  else
@@ -13,12 +13,33 @@ module RuboCop
13
13
  node_parts[2]
14
14
  end
15
15
 
16
+ # Returns an array of all the exceptions in the `rescue` clause.
17
+ #
18
+ # @return [Array<Node>] an array of exception nodes
19
+ def exceptions
20
+ exceptions_node = node_parts[0]
21
+ if exceptions_node.nil?
22
+ []
23
+ elsif exceptions_node.array_type?
24
+ exceptions_node.values
25
+ else
26
+ [exceptions_node]
27
+ end
28
+ end
29
+
16
30
  # Returns the exception variable of the `rescue` clause.
17
31
  #
18
32
  # @return [Node, nil] The exception variable of the `resbody`.
19
33
  def exception_variable
20
34
  node_parts[1]
21
35
  end
36
+
37
+ # Returns the index of the `resbody` branch within the exception handling statement.
38
+ #
39
+ # @return [Integer] the index of the `resbody` branch
40
+ def branch_index
41
+ parent.resbody_branches.index(self)
42
+ end
22
43
  end
23
44
  end
24
45
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `rescue` nodes. This will be used in place of a
6
+ # plain node when the builder constructs the AST, making its methods
7
+ # available to all `rescue` nodes within RuboCop.
8
+ class RescueNode < Node
9
+ # Returns the body of the rescue node.
10
+ #
11
+ # @return [Node, nil] The body of the rescue node.
12
+ def body
13
+ node_parts[0]
14
+ end
15
+
16
+ # Returns an array of all the rescue branches in the exception handling statement.
17
+ #
18
+ # @return [Array<ResbodyNode>] an array of `resbody` nodes
19
+ def resbody_branches
20
+ node_parts[1...-1]
21
+ end
22
+
23
+ # Returns an array of all the rescue branches in the exception handling statement.
24
+ #
25
+ # @return [Array<Node, nil>] an array of the bodies of the rescue branches
26
+ # and the else (if any). Note that these bodies could be nil.
27
+ def branches
28
+ bodies = resbody_branches.map(&:body)
29
+ bodies.push(else_branch) if else?
30
+ bodies
31
+ end
32
+
33
+ # Returns the else branch of the exception handling statement, if any.
34
+ #
35
+ # @return [Node] the else branch node of the exception handling statement
36
+ # @return [nil] if the exception handling statement does not have an else branch.
37
+ def else_branch
38
+ node_parts[-1]
39
+ end
40
+
41
+ # Checks whether this exception handling statement has an `else` branch.
42
+ #
43
+ # @return [Boolean] whether the exception handling statement has an `else` branch
44
+ def else?
45
+ loc.else
46
+ end
47
+ end
48
+ end
49
+ end
@@ -6,19 +6,7 @@ module RuboCop
6
6
  # plain node when the builder constructs the AST, making its methods
7
7
  # available to all `return` nodes within RuboCop.
8
8
  class ReturnNode < Node
9
- include MethodDispatchNode
10
- include ParameterizedNode
11
-
12
- # Returns the arguments of the `return`.
13
- #
14
- # @return [Array] The arguments of the `return`.
15
- def arguments
16
- if node_parts.one? && node_parts.first.begin_type?
17
- node_parts.first.children
18
- else
19
- node_parts
20
- end
21
- end
9
+ include ParameterizedNode::WrappedArguments
22
10
  end
23
11
  end
24
12
  end