rubocop-ast 1.24.1 → 1.46.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/rubocop/ast/builder.rb +104 -85
  4. data/lib/rubocop/ast/builder_prism.rb +11 -0
  5. data/lib/rubocop/ast/ext/range.rb +2 -2
  6. data/lib/rubocop/ast/node/args_node.rb +1 -1
  7. data/lib/rubocop/ast/node/array_node.rb +9 -5
  8. data/lib/rubocop/ast/node/asgn_node.rb +2 -0
  9. data/lib/rubocop/ast/node/block_node.rb +27 -8
  10. data/lib/rubocop/ast/node/casgn_node.rb +4 -12
  11. data/lib/rubocop/ast/node/complex_node.rb +13 -0
  12. data/lib/rubocop/ast/node/const_node.rb +1 -52
  13. data/lib/rubocop/ast/node/csend_node.rb +2 -2
  14. data/lib/rubocop/ast/node/def_node.rb +1 -1
  15. data/lib/rubocop/ast/node/ensure_node.rb +36 -0
  16. data/lib/rubocop/ast/node/for_node.rb +1 -1
  17. data/lib/rubocop/ast/node/hash_node.rb +1 -1
  18. data/lib/rubocop/ast/node/if_node.rb +11 -4
  19. data/lib/rubocop/ast/node/in_pattern_node.rb +1 -1
  20. data/lib/rubocop/ast/node/keyword_begin_node.rb +44 -0
  21. data/lib/rubocop/ast/node/keyword_splat_node.rb +10 -3
  22. data/lib/rubocop/ast/node/masgn_node.rb +63 -0
  23. data/lib/rubocop/ast/node/mixin/basic_literal_node.rb +1 -1
  24. data/lib/rubocop/ast/node/mixin/collection_node.rb +1 -1
  25. data/lib/rubocop/ast/node/mixin/constant_node.rb +62 -0
  26. data/lib/rubocop/ast/node/mixin/descendence.rb +3 -3
  27. data/lib/rubocop/ast/node/mixin/hash_element_node.rb +2 -0
  28. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +29 -19
  29. data/lib/rubocop/ast/node/mixin/numeric_node.rb +2 -2
  30. data/lib/rubocop/ast/node/mixin/parameterized_node.rb +2 -2
  31. data/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +7 -2
  32. data/lib/rubocop/ast/node/mlhs_node.rb +29 -0
  33. data/lib/rubocop/ast/node/op_asgn_node.rb +3 -1
  34. data/lib/rubocop/ast/node/rational_node.rb +13 -0
  35. data/lib/rubocop/ast/node/str_node.rb +37 -1
  36. data/lib/rubocop/ast/node/until_node.rb +1 -1
  37. data/lib/rubocop/ast/node/var_node.rb +15 -0
  38. data/lib/rubocop/ast/node/when_node.rb +1 -1
  39. data/lib/rubocop/ast/node/while_node.rb +1 -1
  40. data/lib/rubocop/ast/node.rb +131 -46
  41. data/lib/rubocop/ast/node_pattern/compiler/atom_subcompiler.rb +1 -1
  42. data/lib/rubocop/ast/node_pattern/compiler/binding.rb +3 -3
  43. data/lib/rubocop/ast/node_pattern/compiler/debug.rb +4 -9
  44. data/lib/rubocop/ast/node_pattern/compiler/sequence_subcompiler.rb +3 -4
  45. data/lib/rubocop/ast/node_pattern/compiler.rb +1 -1
  46. data/lib/rubocop/ast/node_pattern/lexer.rex.rb +1 -2
  47. data/lib/rubocop/ast/node_pattern/node.rb +15 -6
  48. data/lib/rubocop/ast/node_pattern/parser.racc.rb +4 -2
  49. data/lib/rubocop/ast/node_pattern/parser.rb +1 -1
  50. data/lib/rubocop/ast/node_pattern/with_meta.rb +3 -4
  51. data/lib/rubocop/ast/node_pattern.rb +1 -1
  52. data/lib/rubocop/ast/processed_source.rb +159 -58
  53. data/lib/rubocop/ast/token.rb +2 -1
  54. data/lib/rubocop/ast/traversal.rb +35 -25
  55. data/lib/rubocop/ast/utilities/simple_forwardable.rb +27 -0
  56. data/lib/rubocop/ast/version.rb +1 -1
  57. data/lib/rubocop/ast.rb +10 -1
  58. metadata +21 -19
  59. data/lib/rubocop/ast/ext/range_min_max.rb +0 -18
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `kwbegin` nodes. This will be used in place of a plain
6
+ # node when the builder constructs the AST, making its methods available
7
+ # to all `kwbegin` nodes within RuboCop.
8
+ class KeywordBeginNode < Node
9
+ # Returns the body of the `kwbegin` block. Returns `self` if the `kwbegin` contains
10
+ # multiple nodes.
11
+ #
12
+ # @return [Node, nil] The body of the `kwbegin`.
13
+ def body
14
+ return unless node_parts.any?
15
+
16
+ if rescue_node
17
+ rescue_node.body
18
+ elsif ensure_node
19
+ ensure_node.node_parts[0]
20
+ elsif node_parts.one?
21
+ node_parts[0]
22
+ else
23
+ self
24
+ end
25
+ end
26
+
27
+ # Returns the `rescue` node of the `kwbegin` block, if one is present.
28
+ #
29
+ # @return [Node, nil] The `rescue` node within `kwbegin`.
30
+ def ensure_node
31
+ node_parts[0] if node_parts[0]&.ensure_type?
32
+ end
33
+
34
+ # Returns the `rescue` node of the `kwbegin` block, if one is present.
35
+ #
36
+ # @return [Node, nil] The `rescue` node within `kwbegin`.
37
+ def rescue_node
38
+ return ensure_node&.rescue_node if ensure_node&.rescue_node
39
+
40
+ node_parts[0] if node_parts[0]&.rescue_type?
41
+ end
42
+ end
43
+ end
44
+ end
@@ -2,9 +2,9 @@
2
2
 
3
3
  module RuboCop
4
4
  module AST
5
- # A node extension for `kwsplat` 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 `kwsplat` nodes within RuboCop.
5
+ # A node extension for `kwsplat` and `forwarded_kwrestarg` nodes. This will be used in
6
+ # place of a plain node when the builder constructs the AST, making its methods available to
7
+ # all `kwsplat` and `forwarded_kwrestarg` nodes within RuboCop.
8
8
  class KeywordSplatNode < Node
9
9
  include HashElementNode
10
10
 
@@ -41,6 +41,13 @@ module RuboCop
41
41
  def node_parts
42
42
  [self, self]
43
43
  end
44
+
45
+ # This provides `forwarded_kwrestarg` node to return true to be compatible with `kwsplat` node.
46
+ #
47
+ # @return [true]
48
+ def kwsplat_type?
49
+ true
50
+ end
44
51
  end
45
52
  end
46
53
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `masgn` nodes.
6
+ # This will be used in place of a plain node when the builder constructs
7
+ # the AST, making its methods available to all assignment nodes within RuboCop.
8
+ class MasgnNode < Node
9
+ # @return [MlhsNode] the `mlhs` node
10
+ def lhs
11
+ # The first child is a `mlhs` node
12
+ node_parts[0]
13
+ end
14
+
15
+ # @return [Array<Node>] the assignment nodes of the multiple assignment
16
+ def assignments
17
+ lhs.assignments
18
+ end
19
+
20
+ # @return [Array<Symbol>] names of all the variables being assigned
21
+ def names
22
+ assignments.map do |assignment|
23
+ if assignment.type?(:send, :indexasgn)
24
+ assignment.method_name
25
+ else
26
+ assignment.name
27
+ end
28
+ end
29
+ end
30
+
31
+ # The RHS (right hand side) of the multiple assignment. This returns
32
+ # the nodes as parsed: either a single node if the RHS has a single value,
33
+ # or an `array` node containing multiple nodes.
34
+ #
35
+ # NOTE: Due to how parsing works, `expression` will return the same for
36
+ # `a, b = x, y` and `a, b = [x, y]`.
37
+ #
38
+ # @return [Node] the right hand side of a multiple assignment.
39
+ def expression
40
+ node_parts[1]
41
+ end
42
+ alias rhs expression
43
+
44
+ # In contrast to `expression`, `values` always returns a Ruby array
45
+ # containing all the nodes being assigned on the RHS.
46
+ #
47
+ # Literal arrays are considered a singular value; but unlike `expression`,
48
+ # implied `array` nodes from assigning multiple values on the RHS are treated
49
+ # as separate.
50
+ #
51
+ # @return [Array<Node>] individual values being assigned on the RHS of the multiple assignment
52
+ def values
53
+ multiple_rhs? ? expression.children : [expression]
54
+ end
55
+
56
+ private
57
+
58
+ def multiple_rhs?
59
+ expression.array_type? && !expression.bracketed?
60
+ end
61
+ end
62
+ end
63
+ end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module AST
5
5
  # Common functionality for primitive literal nodes: `sym`, `str`,
6
- # `int`, `float`, ...
6
+ # `int`, `float`, `rational`, `complex`...
7
7
  module BasicLiteralNode
8
8
  # Returns the value of the literal.
9
9
  #
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module AST
5
5
  # A mixin that helps give collection nodes array polymorphism.
6
6
  module CollectionNode
7
- extend Forwardable
7
+ extend SimpleForwardable
8
8
 
9
9
  ARRAY_METHODS =
10
10
  (Array.instance_methods - Object.instance_methods - [:to_a]).freeze
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # Common functionality for nodes that deal with constants:
6
+ # `const`, `casgn`.
7
+ module ConstantNode
8
+ # @return [Node, nil] the node associated with the scope (e.g. cbase, const, ...)
9
+ def namespace
10
+ children[0]
11
+ end
12
+
13
+ # @return [Symbol] the demodulized name of the constant: "::Foo::Bar" => :Bar
14
+ def short_name
15
+ children[1]
16
+ end
17
+
18
+ # @return [Boolean] if the constant is a Module / Class, according to the standard convention.
19
+ # Note: some classes might have uppercase in which case this method
20
+ # returns false
21
+ def module_name?
22
+ short_name.match?(/[[:lower:]]/)
23
+ end
24
+ alias class_name? module_name?
25
+
26
+ # @return [Boolean] if the constant starts with `::` (aka s(:cbase))
27
+ def absolute?
28
+ return false unless namespace
29
+
30
+ each_path.first.cbase_type?
31
+ end
32
+
33
+ # @return [Boolean] if the constant does not start with `::` (aka s(:cbase))
34
+ def relative?
35
+ !absolute?
36
+ end
37
+
38
+ # Yield nodes for the namespace
39
+ #
40
+ # For `::Foo::Bar::BAZ` => yields:
41
+ # s(:cbase), then
42
+ # s(:const, :Foo), then
43
+ # s(:const, s(:const, :Foo), :Bar)
44
+ def each_path(&block)
45
+ return to_enum(__method__) unless block
46
+
47
+ descendants = []
48
+ last = self
49
+ loop do
50
+ last = last.children.first
51
+ break if last.nil?
52
+
53
+ descendants << last
54
+ break unless last.const_type?
55
+ end
56
+ descendants.reverse_each(&block)
57
+
58
+ self
59
+ end
60
+ end
61
+ end
62
+ end
@@ -25,7 +25,7 @@ module RuboCop
25
25
  children.each do |child|
26
26
  next unless child.is_a?(::AST::Node)
27
27
 
28
- yield child if types.empty? || types.include?(child.type)
28
+ yield child if types.empty? || child.type?(*types)
29
29
  end
30
30
 
31
31
  self
@@ -95,7 +95,7 @@ module RuboCop
95
95
  def each_node(*types, &block)
96
96
  return to_enum(__method__, *types) unless block
97
97
 
98
- yield self if types.empty? || types.include?(type)
98
+ yield self if types.empty? || type?(*types)
99
99
 
100
100
  visit_descendants(types, &block)
101
101
 
@@ -108,7 +108,7 @@ module RuboCop
108
108
  children.each do |child|
109
109
  next unless child.is_a?(::AST::Node)
110
110
 
111
- yield child if types.empty? || types.include?(child.type)
111
+ yield child if types.empty? || child.type?(*types)
112
112
  child.visit_descendants(types, &block)
113
113
  end
114
114
  end
@@ -99,7 +99,9 @@ module RuboCop
99
99
 
100
100
  def valid_argument_types?
101
101
  [first, second].all? do |argument|
102
+ # rubocop:disable InternalAffairs/NodeTypeMultiplePredicates
102
103
  argument.pair_type? || argument.kwsplat_type?
104
+ # rubocop:enable InternalAffairs/NodeTypeMultiplePredicates
103
105
  end
104
106
  end
105
107
 
@@ -5,7 +5,7 @@ module RuboCop
5
5
  # Common functionality for nodes that are a kind of method dispatch:
6
6
  # `send`, `csend`, `super`, `zsuper`, `yield`, `defined?`,
7
7
  # and (modern only): `index`, `indexasgn`, `lambda`
8
- module MethodDispatchNode
8
+ module MethodDispatchNode # rubocop:disable Metrics/ModuleLength
9
9
  extend NodePattern::Macros
10
10
  include MethodIdentifierPredicates
11
11
 
@@ -28,10 +28,21 @@ module RuboCop
28
28
  node_parts[1]
29
29
  end
30
30
 
31
- # The `block` or `numblock` node associated with this method dispatch, if any.
31
+ # The source range for the method name or keyword that dispatches this call.
32
32
  #
33
- # @return [BlockNode, nil] the `block` or `numblock` node associated with this method
34
- # call or `nil`
33
+ # @return [Parser::Source::Range] the source range for the method name or keyword
34
+ def selector
35
+ if loc.respond_to? :keyword
36
+ loc.keyword
37
+ else
38
+ loc.selector
39
+ end
40
+ end
41
+
42
+ # The `block`, `numblock`, or `itblock` node associated with this method dispatch, if any.
43
+ #
44
+ # @return [BlockNode, nil] the `block`, `numblock`, or `itblock` node associated with this
45
+ # method call or `nil`
35
46
  def block_node
36
47
  parent if block_literal?
37
48
  end
@@ -94,7 +105,7 @@ module RuboCop
94
105
  #
95
106
  # @return [Boolean] whether the dispatched method is a setter
96
107
  def setter_method?
97
- loc.respond_to?(:operator) && loc.operator
108
+ loc?(:operator)
98
109
  end
99
110
  alias assignment? setter_method?
100
111
 
@@ -106,7 +117,7 @@ module RuboCop
106
117
  #
107
118
  # @return [Boolean] whether the method was called with a connecting dot
108
119
  def dot?
109
- loc.respond_to?(:dot) && loc.dot && loc.dot.is?('.')
120
+ loc_is?(:dot, '.')
110
121
  end
111
122
 
112
123
  # Checks whether the dispatched method uses a double colon to connect the
@@ -114,7 +125,7 @@ module RuboCop
114
125
  #
115
126
  # @return [Boolean] whether the method was called with a connecting dot
116
127
  def double_colon?
117
- loc.respond_to?(:dot) && loc.dot && loc.dot.is?('::')
128
+ loc_is?(:dot, '::')
118
129
  end
119
130
 
120
131
  # Checks whether the dispatched method uses a safe navigation operator to
@@ -122,7 +133,7 @@ module RuboCop
122
133
  #
123
134
  # @return [Boolean] whether the method was called with a connecting dot
124
135
  def safe_navigation?
125
- loc.respond_to?(:dot) && loc.dot && loc.dot.is?('&.')
136
+ loc_is?(:dot, '&.')
126
137
  end
127
138
 
128
139
  # Checks whether the *explicit* receiver of this method dispatch is
@@ -147,14 +158,14 @@ module RuboCop
147
158
  #
148
159
  # @return [Boolean] whether the method is the implicit form of `#call`
149
160
  def implicit_call?
150
- method?(:call) && !loc.selector
161
+ method?(:call) && !selector
151
162
  end
152
163
 
153
164
  # Whether this method dispatch has an explicit block.
154
165
  #
155
166
  # @return [Boolean] whether the dispatched method has a block
156
167
  def block_literal?
157
- (parent&.block_type? || parent&.numblock_type?) && eql?(parent.send_node)
168
+ parent&.any_block_type? && eql?(parent.send_node)
158
169
  end
159
170
 
160
171
  # Checks whether this node is an arithmetic operation
@@ -189,8 +200,7 @@ module RuboCop
189
200
  arg = node.children[2]
190
201
 
191
202
  return unless node.send_type? && node.receiver.nil? && arg.is_a?(::AST::Node)
192
-
193
- return arg if arg.def_type? || arg.defs_type?
203
+ return arg if arg.any_def_type?
194
204
 
195
205
  def_modifier(arg)
196
206
  end
@@ -222,9 +232,9 @@ module RuboCop
222
232
  #
223
233
  # @return [Boolean] whether this method is a unary operation
224
234
  def unary_operation?
225
- return false unless loc.selector
235
+ return false unless selector
226
236
 
227
- operator_method? && loc.expression.begin_pos == loc.selector.begin_pos
237
+ operator_method? && loc.expression.begin_pos == selector.begin_pos
228
238
  end
229
239
 
230
240
  # Checks whether this is a binary operation.
@@ -235,9 +245,9 @@ module RuboCop
235
245
  #
236
246
  # @return [Boolean] whether this method is a binary operation
237
247
  def binary_operation?
238
- return false unless loc.selector
248
+ return false unless selector
239
249
 
240
- operator_method? && loc.expression.begin_pos != loc.selector.begin_pos
250
+ operator_method? && loc.expression.begin_pos != selector.begin_pos
241
251
  end
242
252
 
243
253
  private
@@ -249,7 +259,7 @@ module RuboCop
249
259
  ^{ # or the parent is...
250
260
  sclass class module class_constructor? # a class-like node
251
261
  [ { # or some "wrapper"
252
- kwbegin begin block numblock
262
+ kwbegin begin any_block
253
263
  (if _condition <%0 _>) # note: we're excluding the condition of `if` nodes
254
264
  }
255
265
  #in_macro_scope? # that is itself in a macro scope
@@ -260,7 +270,7 @@ module RuboCop
260
270
 
261
271
  # @!method adjacent_def_modifier?(node = self)
262
272
  def_node_matcher :adjacent_def_modifier?, <<~PATTERN
263
- (send nil? _ ({def defs} ...))
273
+ (send nil? _ (any_def ...))
264
274
  PATTERN
265
275
 
266
276
  # @!method bare_access_modifier_declaration?(node = self)
@@ -270,7 +280,7 @@ module RuboCop
270
280
 
271
281
  # @!method non_bare_access_modifier_declaration?(node = self)
272
282
  def_node_matcher :non_bare_access_modifier_declaration?, <<~PATTERN
273
- (send nil? {:public :protected :private :module_function} _)
283
+ (send nil? {:public :protected :private :module_function} _+)
274
284
  PATTERN
275
285
  end
276
286
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RuboCop
4
4
  module AST
5
- # Common functionality for primitive numeric nodes: `int`, `float`, ...
5
+ # Common functionality for primitive numeric nodes: `int`, `float`, `rational`, `complex`...
6
6
  module NumericNode
7
7
  SIGN_REGEX = /\A[+-]/.freeze
8
8
  private_constant :SIGN_REGEX
@@ -15,7 +15,7 @@ module RuboCop
15
15
  #
16
16
  # @return [Boolean] whether this literal has a sign.
17
17
  def sign?
18
- source.match(SIGN_REGEX)
18
+ source.match?(SIGN_REGEX)
19
19
  end
20
20
  end
21
21
  end
@@ -13,7 +13,7 @@ module RuboCop
13
13
  # @return [Boolean] whether this node's arguments are
14
14
  # wrapped in parentheses
15
15
  def parenthesized?
16
- loc.end&.is?(')')
16
+ loc_is?(:end, ')')
17
17
  end
18
18
 
19
19
  # A shorthand for getting the first argument of the node.
@@ -57,7 +57,7 @@ module RuboCop
57
57
  # @return [Boolean] whether the last argument of the node is a block pass
58
58
  def block_argument?
59
59
  arguments? &&
60
- (last_argument.block_pass_type? || last_argument.blockarg_type?)
60
+ last_argument.type?(:block_pass, :blockarg)
61
61
  end
62
62
 
63
63
  # A specialized `ParameterizedNode` for node that have a single child
@@ -14,6 +14,11 @@ module RuboCop
14
14
  SEMANTIC_OR = 'or'
15
15
  private_constant :SEMANTIC_OR
16
16
 
17
+ LOGICAL_OPERATORS = [LOGICAL_AND, LOGICAL_OR].freeze
18
+ private_constant :LOGICAL_OPERATORS
19
+ SEMANTIC_OPERATORS = [SEMANTIC_AND, SEMANTIC_OR].freeze
20
+ private_constant :SEMANTIC_OPERATORS
21
+
17
22
  # Returns the operator as a string.
18
23
  #
19
24
  # @return [String] the operator
@@ -25,14 +30,14 @@ module RuboCop
25
30
  #
26
31
  # @return [Boolean] whether this is a logical operator
27
32
  def logical_operator?
28
- operator == LOGICAL_AND || operator == LOGICAL_OR
33
+ LOGICAL_OPERATORS.include?(operator)
29
34
  end
30
35
 
31
36
  # Checks whether this is a semantic operator.
32
37
  #
33
38
  # @return [Boolean] whether this is a semantic operator
34
39
  def semantic_operator?
35
- operator == SEMANTIC_AND || operator == SEMANTIC_OR
40
+ SEMANTIC_OPERATORS.include?(operator)
36
41
  end
37
42
  end
38
43
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `mlhs` nodes.
6
+ # This will be used in place of a plain node when the builder constructs
7
+ # the AST, making its methods available to all assignment nodes within RuboCop.
8
+ class MlhsNode < Node
9
+ # Returns all the assignment nodes on the left hand side (LHS) of a multiple assignment.
10
+ # These are generally assignment nodes (`lvasgn`, `ivasgn`, `cvasgn`, `gvasgn`, `casgn`)
11
+ # but can also be `send` nodes in case of `foo.bar, ... =` or `foo[:bar], ... =`,
12
+ # or a `splat` node for `*, ... =`.
13
+ #
14
+ # @return [Array<Node>] the assignment nodes of the multiple assignment LHS
15
+ def assignments
16
+ child_nodes.flat_map do |node|
17
+ if node.splat_type?
18
+ # Anonymous splats have no children
19
+ node.child_nodes.first || node
20
+ elsif node.mlhs_type?
21
+ node.assignments
22
+ else
23
+ node
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -10,12 +10,13 @@ module RuboCop
10
10
  def assignment_node
11
11
  node_parts[0]
12
12
  end
13
+ alias lhs assignment_node
13
14
 
14
15
  # The name of the variable being assigned as a symbol.
15
16
  #
16
17
  # @return [Symbol] the name of the variable being assigned
17
18
  def name
18
- assignment_node.name
19
+ assignment_node.call_type? ? assignment_node.method_name : assignment_node.name
19
20
  end
20
21
 
21
22
  # The operator being used for assignment as a symbol.
@@ -31,6 +32,7 @@ module RuboCop
31
32
  def expression
32
33
  node_parts.last
33
34
  end
35
+ alias rhs expression
34
36
  end
35
37
  end
36
38
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `rational` nodes. This will be used in place of a plain
6
+ # node when the builder constructs the AST, making its methods available to
7
+ # all `rational` nodes within RuboCop.
8
+ class RationalNode < Node
9
+ include BasicLiteralNode
10
+ include NumericNode
11
+ end
12
+ end
13
+ end
@@ -8,13 +8,49 @@ module RuboCop
8
8
  class StrNode < Node
9
9
  include BasicLiteralNode
10
10
 
11
+ PERCENT_LITERAL_TYPES = {
12
+ :% => /\A%(?=[^a-zA-Z])/,
13
+ :q => /\A%q/,
14
+ :Q => /\A%Q/
15
+ }.freeze
16
+ private_constant :PERCENT_LITERAL_TYPES
17
+
18
+ def single_quoted?
19
+ loc_is?(:begin, "'")
20
+ end
21
+
22
+ def double_quoted?
23
+ loc_is?(:begin, '"')
24
+ end
25
+
11
26
  def character_literal?
12
- loc.respond_to?(:begin) && loc.begin && loc.begin.is?('?')
27
+ loc_is?(:begin, '?')
13
28
  end
14
29
 
15
30
  def heredoc?
16
31
  loc.is_a?(Parser::Source::Map::Heredoc)
17
32
  end
33
+
34
+ # Checks whether the string literal is delimited by percent brackets.
35
+ #
36
+ # @overload percent_literal?
37
+ # Check for any string percent literal.
38
+ #
39
+ # @overload percent_literal?(type)
40
+ # Check for a string percent literal of type `type`.
41
+ #
42
+ # @param type [Symbol] an optional percent literal type
43
+ #
44
+ # @return [Boolean] whether the string is enclosed in percent brackets
45
+ def percent_literal?(type = nil)
46
+ return false unless loc?(:begin)
47
+
48
+ if type
49
+ loc.begin.source.match?(PERCENT_LITERAL_TYPES.fetch(type))
50
+ else
51
+ loc.begin.source.start_with?('%')
52
+ end
53
+ end
18
54
  end
19
55
  end
20
56
  end
@@ -28,7 +28,7 @@ module RuboCop
28
28
  #
29
29
  # @return [Boolean] whether the `until` node has a `do` keyword
30
30
  def do?
31
- loc.begin&.is?('do')
31
+ loc_is?(:begin, 'do')
32
32
  end
33
33
  end
34
34
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `lvar`, `ivar`, `cvar` and `gvar` nodes.
6
+ # This will be used in place of a plain node when the builder constructs
7
+ # the AST, making its methods available to all assignment nodes within RuboCop.
8
+ class VarNode < Node
9
+ # @return [Symbol] The name of the variable.
10
+ def name
11
+ node_parts[0]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -33,7 +33,7 @@ module RuboCop
33
33
  #
34
34
  # @return [Boolean] whether the `when` node has a `then` keyword
35
35
  def then?
36
- loc.begin&.is?('then')
36
+ loc_is?(:begin, 'then')
37
37
  end
38
38
 
39
39
  # Returns the body of the `when` node.
@@ -28,7 +28,7 @@ module RuboCop
28
28
  #
29
29
  # @return [Boolean] whether the `until` node has a `do` keyword
30
30
  def do?
31
- loc.begin&.is?('do')
31
+ loc_is?(:begin, 'do')
32
32
  end
33
33
  end
34
34
  end