rubocop-ast 0.1.0 → 0.4.2

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 (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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4108494066548a429e972d3f2afcaa9adfd39072a929308cdb20e4a602fef66d
4
- data.tar.gz: 413b4382539bffed1760d0599bc093ad40ffef64992f821484994150903812da
3
+ metadata.gz: 40c38e6b0706f9e32534f937c63364ea14265677769db826355eb0b7e54e23fb
4
+ data.tar.gz: 1ea90e49f444e46fdbb998c5689fb711fda71ab6762462358210d8ee1e0494af
5
5
  SHA512:
6
- metadata.gz: 97af9dd864e8f6867614a79b2aac596e18e147b9a55bcc67b8755e47ef762730ec69612dcc6858ee12017b33beae0b89e008e1267034f1730682015c4efa4255
7
- data.tar.gz: 807305ab6dc90885fff96d1387d787debf8ce8f27a0d150ad4bf86a76d4afb2d288f0771b2399cf3c3cfb1472c72cd750e4df9e97ad07467da4615a97c062f79
6
+ metadata.gz: cea177a8e7e1a8ee9435fd00788f7ffec664e8b0de29c8fc390ccbbcb211aab5fc834ffdb84d6b05a94075f9d2e6c31aadeb8e43a91e0e5c7f1a8726da186c64
7
+ data.tar.gz: 8b7e38a8f92d84b22bfeac82efb5352d318a8663aecd97c1b9519fb065f6327136a19ce504ba7a75b9b3839ec1ac846c45ec52d414fdd292eebcf615db3ae79d
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,8 @@ require 'parser'
4
4
  require 'forwardable'
5
5
  require 'set'
6
6
 
7
+ require_relative 'ast/ext/range'
8
+ require_relative 'ast/ext/set'
7
9
  require_relative 'ast/node_pattern'
8
10
  require_relative 'ast/sexp'
9
11
  require_relative 'ast/node'
@@ -27,6 +29,7 @@ require_relative 'ast/node/break_node'
27
29
  require_relative 'ast/node/case_match_node'
28
30
  require_relative 'ast/node/case_node'
29
31
  require_relative 'ast/node/class_node'
32
+ require_relative 'ast/node/const_node'
30
33
  require_relative 'ast/node/def_node'
31
34
  require_relative 'ast/node/defined_node'
32
35
  require_relative 'ast/node/ensure_node'
@@ -41,12 +44,13 @@ require_relative 'ast/node/int_node'
41
44
  require_relative 'ast/node/keyword_splat_node'
42
45
  require_relative 'ast/node/lambda_node'
43
46
  require_relative 'ast/node/module_node'
47
+ require_relative 'ast/node/next_node'
44
48
  require_relative 'ast/node/or_node'
45
49
  require_relative 'ast/node/pair_node'
46
50
  require_relative 'ast/node/range_node'
47
51
  require_relative 'ast/node/regexp_node'
52
+ require_relative 'ast/node/rescue_node'
48
53
  require_relative 'ast/node/resbody_node'
49
- require_relative 'ast/node/retry_node'
50
54
  require_relative 'ast/node/return_node'
51
55
  require_relative 'ast/node/self_class_node'
52
56
  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,
@@ -25,6 +27,7 @@ module RuboCop
25
27
  case_match: CaseMatchNode,
26
28
  case: CaseNode,
27
29
  class: ClassNode,
30
+ const: ConstNode,
28
31
  def: DefNode,
29
32
  defined?: DefinedNode,
30
33
  defs: DefNode,
@@ -42,11 +45,12 @@ module RuboCop
42
45
  kwsplat: KeywordSplatNode,
43
46
  lambda: LambdaNode,
44
47
  module: ModuleNode,
48
+ next: NextNode,
45
49
  or: OrNode,
46
50
  pair: PairNode,
47
51
  regexp: RegexpNode,
52
+ rescue: RescueNode,
48
53
  resbody: ResbodyNode,
49
- retry: RetryNode,
50
54
  return: ReturnNode,
51
55
  csend: SendNode,
52
56
  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
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ test = :foo
4
+ case test
5
+ when Set[:foo]
6
+ # ok, RUBY_VERSION > 2.4
7
+ else
8
+ # Harmonize `Set#===`
9
+ class Set
10
+ alias === include?
11
+ end
12
+ end
@@ -38,7 +38,7 @@ module RuboCop
38
38
  IMMUTABLE_LITERALS = (LITERALS - MUTABLE_LITERALS).freeze
39
39
 
40
40
  EQUALS_ASSIGNMENTS = %i[lvasgn ivasgn cvasgn gvasgn
41
- casgn masgn].freeze
41
+ casgn masgn rasgn mrasgn].freeze
42
42
  SHORTHAND_ASSIGNMENTS = %i[op_asgn or_asgn and_asgn].freeze
43
43
  ASSIGNMENTS = (EQUALS_ASSIGNMENTS + SHORTHAND_ASSIGNMENTS).freeze
44
44
 
@@ -116,12 +116,50 @@ module RuboCop
116
116
 
117
117
  # Returns the index of the receiver node in its siblings. (Sibling index
118
118
  # uses zero based numbering.)
119
+ # Use is discouraged, this is a potentially slow method.
119
120
  #
120
- # @return [Integer] the index of the receiver node in its siblings
121
+ # @return [Integer, nil] the index of the receiver node in its siblings
121
122
  def sibling_index
122
123
  parent&.children&.index { |sibling| sibling.equal?(self) }
123
124
  end
124
125
 
126
+ # Use is discouraged, this is a potentially slow method and can lead
127
+ # to even slower algorithms
128
+ # @return [Node, nil] the right (aka next) sibling
129
+ def right_sibling
130
+ return unless parent
131
+
132
+ parent.children[sibling_index + 1].freeze
133
+ end
134
+
135
+ # Use is discouraged, this is a potentially slow method and can lead
136
+ # to even slower algorithms
137
+ # @return [Node, nil] the left (aka previous) sibling
138
+ def left_sibling
139
+ i = sibling_index
140
+ return if i.nil? || i.zero?
141
+
142
+ parent.children[i - 1].freeze
143
+ end
144
+
145
+ # Use is discouraged, this is a potentially slow method and can lead
146
+ # to even slower algorithms
147
+ # @return [Array<Node>] the left (aka previous) siblings
148
+ def left_siblings
149
+ return [].freeze unless parent
150
+
151
+ parent.children[0...sibling_index].freeze
152
+ end
153
+
154
+ # Use is discouraged, this is a potentially slow method and can lead
155
+ # to even slower algorithms
156
+ # @return [Array<Node>] the right (aka next) siblings
157
+ def right_siblings
158
+ return [].freeze unless parent
159
+
160
+ parent.children[sibling_index + 1..-1].freeze
161
+ end
162
+
125
163
  # Common destructuring method. This can be used to normalize
126
164
  # destructuring for different variations of the node.
127
165
  # Some node types override this with their own custom
@@ -313,8 +351,8 @@ module RuboCop
313
351
  def_node_matcher :defined_module0, <<~PATTERN
314
352
  {(class (const $_ $_) ...)
315
353
  (module (const $_ $_) ...)
316
- (casgn $_ $_ (send (const nil? {:Class :Module}) :new ...))
317
- (casgn $_ $_ (block (send (const nil? {:Class :Module}) :new ...) ...))}
354
+ (casgn $_ $_ (send #global_const?({:Class :Module}) :new ...))
355
+ (casgn $_ $_ (block (send #global_const?({:Class :Module}) :new ...) ...))}
318
356
  PATTERN
319
357
 
320
358
  private :defined_module0
@@ -496,16 +534,33 @@ module RuboCop
496
534
 
497
535
  def_node_matcher :proc?, <<~PATTERN
498
536
  {(block (send nil? :proc) ...)
499
- (block (send (const nil? :Proc) :new) ...)
500
- (send (const nil? :Proc) :new)}
537
+ (block (send #global_const?(:Proc) :new) ...)
538
+ (send #global_const?(:Proc) :new)}
501
539
  PATTERN
502
540
 
503
541
  def_node_matcher :lambda?, '({block numblock} (send nil? :lambda) ...)'
504
542
  def_node_matcher :lambda_or_proc?, '{lambda? proc?}'
505
543
 
544
+ def_node_matcher :global_const?, '(const {nil? cbase} %1)'
545
+
506
546
  def_node_matcher :class_constructor?, <<~PATTERN
507
- { (send (const nil? {:Class :Module}) :new ...)
508
- (block (send (const nil? {:Class :Module}) :new ...) ...)}
547
+ { (send #global_const?({:Class :Module}) :new ...)
548
+ (block (send #global_const?({:Class :Module}) :new ...) ...)}
549
+ PATTERN
550
+
551
+ def_node_matcher :struct_constructor?, <<~PATTERN
552
+ (block (send #global_const?(:Struct) :new ...) _ $_)
553
+ PATTERN
554
+
555
+ def_node_matcher :class_definition?, <<~PATTERN
556
+ {(class _ _ $_)
557
+ (sclass _ $_)
558
+ (block (send #global_const?({:Struct :Class}) :new ...) _ $_)}
559
+ PATTERN
560
+
561
+ def_node_matcher :module_definition?, <<~PATTERN
562
+ {(module _ $_)
563
+ (block (send #global_const?(:Module) :new ...) _ $_)}
509
564
  PATTERN
510
565
 
511
566
  # 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
 
@@ -25,7 +25,7 @@ module RuboCop
25
25
  # @return [Array<Node>]
26
26
  def arguments
27
27
  if numblock_type?
28
- [] # Numbered parameters have no block arguments.
28
+ [].freeze # Numbered parameters have no block arguments.
29
29
  else
30
30
  node_parts[1]
31
31
  end
@@ -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
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A node extension for `const` nodes.
6
+ class ConstNode < Node
7
+ # The `send` node associated with this block.
8
+ #
9
+ # @return [Node, nil] the node associated with the scope (e.g. cbase, const, ...)
10
+ def namespace
11
+ children[0]
12
+ end
13
+
14
+ # @return [Symbol] the demodulized name of the constant: "::Foo::Bar" => :Bar
15
+ def short_name
16
+ children[1]
17
+ end
18
+
19
+ # The body of this block.
20
+ #
21
+ # @return [Boolean] if the constant is a Module / Class, according to the standard convention.
22
+ # Note: some classes might have uppercase in which case this method
23
+ # returns false
24
+ def module_name?
25
+ short_name.match?(/[[:lower:]]/)
26
+ end
27
+ alias class_name? module_name?
28
+
29
+ # @return [Boolean] if the constant starts with `::` (aka s(:cbase))
30
+ def absolute?
31
+ return false unless namespace
32
+
33
+ each_path.first.cbase_type?
34
+ end
35
+
36
+ # @return [Boolean] if the constant does not start with `::` (aka s(:cbase))
37
+ def relative?
38
+ !absolute?
39
+ end
40
+
41
+ # Yield nodes for the namespace
42
+ #
43
+ # For `::Foo::Bar::BAZ` => yields:
44
+ # s(:cbase), then
45
+ # s(:const, :Foo), then
46
+ # s(:const, s(:const, :Foo), :Bar)
47
+ def each_path(&block)
48
+ return to_enum(__method__) unless block_given?
49
+
50
+ descendants = []
51
+ last = self
52
+ loop do
53
+ last = last.children.first
54
+ break if last.nil?
55
+
56
+ descendants << last
57
+ break unless last.const_type?
58
+ end
59
+ descendants.reverse_each(&block)
60
+
61
+ self
62
+ end
63
+ end
64
+ end
65
+ end
@@ -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