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
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