rubocop-ast 0.3.0 → 0.8.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.
- checksums.yaml +4 -4
- data/lib/rubocop/ast.rb +21 -0
- data/lib/rubocop/ast/builder.rb +3 -0
- data/lib/rubocop/ast/ext/set.rb +12 -0
- data/lib/rubocop/ast/node.rb +96 -127
- data/lib/rubocop/ast/node/array_node.rb +1 -0
- data/lib/rubocop/ast/node/block_node.rb +2 -1
- data/lib/rubocop/ast/node/const_node.rb +65 -0
- data/lib/rubocop/ast/node/def_node.rb +5 -0
- data/lib/rubocop/ast/node/keyword_splat_node.rb +1 -0
- data/lib/rubocop/ast/node/mixin/collection_node.rb +1 -0
- data/lib/rubocop/ast/node/mixin/descendence.rb +116 -0
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +16 -24
- data/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +9 -0
- data/lib/rubocop/ast/node/mixin/numeric_node.rb +1 -0
- data/lib/rubocop/ast/node/mixin/parameterized_node.rb +2 -2
- data/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +7 -3
- data/lib/rubocop/ast/node/pair_node.rb +4 -0
- data/lib/rubocop/ast/node/regexp_node.rb +9 -4
- data/lib/rubocop/ast/node/resbody_node.rb +21 -0
- data/lib/rubocop/ast/node/rescue_node.rb +49 -0
- data/lib/rubocop/ast/node_pattern.rb +44 -870
- data/lib/rubocop/ast/node_pattern/builder.rb +72 -0
- data/lib/rubocop/ast/node_pattern/comment.rb +45 -0
- data/lib/rubocop/ast/node_pattern/compiler.rb +104 -0
- data/lib/rubocop/ast/node_pattern/compiler/atom_subcompiler.rb +56 -0
- data/lib/rubocop/ast/node_pattern/compiler/binding.rb +78 -0
- data/lib/rubocop/ast/node_pattern/compiler/debug.rb +168 -0
- data/lib/rubocop/ast/node_pattern/compiler/node_pattern_subcompiler.rb +146 -0
- data/lib/rubocop/ast/node_pattern/compiler/sequence_subcompiler.rb +420 -0
- data/lib/rubocop/ast/node_pattern/compiler/subcompiler.rb +57 -0
- data/lib/rubocop/ast/node_pattern/lexer.rb +70 -0
- data/lib/rubocop/ast/node_pattern/lexer.rex +39 -0
- data/lib/rubocop/ast/node_pattern/lexer.rex.rb +182 -0
- data/lib/rubocop/ast/node_pattern/method_definer.rb +143 -0
- data/lib/rubocop/ast/node_pattern/node.rb +275 -0
- data/lib/rubocop/ast/node_pattern/parser.racc.rb +470 -0
- data/lib/rubocop/ast/node_pattern/parser.rb +66 -0
- data/lib/rubocop/ast/node_pattern/parser.y +103 -0
- data/lib/rubocop/ast/node_pattern/sets.rb +37 -0
- data/lib/rubocop/ast/node_pattern/with_meta.rb +111 -0
- data/lib/rubocop/ast/processed_source.rb +44 -3
- data/lib/rubocop/ast/rubocop_compatibility.rb +31 -0
- data/lib/rubocop/ast/traversal.rb +149 -172
- data/lib/rubocop/ast/version.rb +1 -1
- metadata +28 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9e5dc8ddfc947af0653c81c0579c18eba59551567d977dc3bf0a4ca4ea92d59
|
4
|
+
data.tar.gz: 4110b86811007a0a28e52c090f45b34449a0e3a6ede4cec97463052c1fb3a8a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 827480d8986177910eee3a5d7bebafd9eb169818d755d79c16f9d4a3f89ebcd486494f35f07fbf3e0f6ffcc2a82da74a86b0475504c79b4fb1de3b3ad732a78f
|
7
|
+
data.tar.gz: 6daa124ee67a95fbc6e91cf5cc0a1179e9aad6718fd8a3f9d54b48c5209b45ede07875e1becbdae84ee2106458bb23538fc144a8aefcc35e922204fcb4c30619
|
data/lib/rubocop/ast.rb
CHANGED
@@ -5,7 +5,22 @@ require 'forwardable'
|
|
5
5
|
require 'set'
|
6
6
|
|
7
7
|
require_relative 'ast/ext/range'
|
8
|
+
require_relative 'ast/ext/set'
|
9
|
+
require_relative 'ast/node_pattern/method_definer'
|
8
10
|
require_relative 'ast/node_pattern'
|
11
|
+
require_relative 'ast/node/mixin/descendence'
|
12
|
+
require_relative 'ast/node_pattern/builder'
|
13
|
+
require_relative 'ast/node_pattern/comment'
|
14
|
+
require_relative 'ast/node_pattern/compiler'
|
15
|
+
require_relative 'ast/node_pattern/compiler/subcompiler'
|
16
|
+
require_relative 'ast/node_pattern/compiler/atom_subcompiler'
|
17
|
+
require_relative 'ast/node_pattern/compiler/binding'
|
18
|
+
require_relative 'ast/node_pattern/compiler/node_pattern_subcompiler'
|
19
|
+
require_relative 'ast/node_pattern/compiler/sequence_subcompiler'
|
20
|
+
require_relative 'ast/node_pattern/lexer'
|
21
|
+
require_relative 'ast/node_pattern/node'
|
22
|
+
require_relative 'ast/node_pattern/parser'
|
23
|
+
require_relative 'ast/node_pattern/sets'
|
9
24
|
require_relative 'ast/sexp'
|
10
25
|
require_relative 'ast/node'
|
11
26
|
require_relative 'ast/node/mixin/method_identifier_predicates'
|
@@ -28,6 +43,7 @@ require_relative 'ast/node/break_node'
|
|
28
43
|
require_relative 'ast/node/case_match_node'
|
29
44
|
require_relative 'ast/node/case_node'
|
30
45
|
require_relative 'ast/node/class_node'
|
46
|
+
require_relative 'ast/node/const_node'
|
31
47
|
require_relative 'ast/node/def_node'
|
32
48
|
require_relative 'ast/node/defined_node'
|
33
49
|
require_relative 'ast/node/ensure_node'
|
@@ -47,6 +63,7 @@ require_relative 'ast/node/or_node'
|
|
47
63
|
require_relative 'ast/node/pair_node'
|
48
64
|
require_relative 'ast/node/range_node'
|
49
65
|
require_relative 'ast/node/regexp_node'
|
66
|
+
require_relative 'ast/node/rescue_node'
|
50
67
|
require_relative 'ast/node/resbody_node'
|
51
68
|
require_relative 'ast/node/return_node'
|
52
69
|
require_relative 'ast/node/self_class_node'
|
@@ -60,6 +77,10 @@ require_relative 'ast/node/while_node'
|
|
60
77
|
require_relative 'ast/node/yield_node'
|
61
78
|
require_relative 'ast/builder'
|
62
79
|
require_relative 'ast/processed_source'
|
80
|
+
require_relative 'ast/rubocop_compatibility'
|
63
81
|
require_relative 'ast/token'
|
64
82
|
require_relative 'ast/traversal'
|
65
83
|
require_relative 'ast/version'
|
84
|
+
|
85
|
+
::RuboCop::AST::NodePattern::Parser.autoload :WithMeta, "#{__dir__}/ast/node_pattern/with_meta"
|
86
|
+
::RuboCop::AST::NodePattern::Compiler.autoload :Debug, "#{__dir__}/ast/node_pattern/compiler/debug"
|
data/lib/rubocop/ast/builder.rb
CHANGED
@@ -16,6 +16,7 @@ module RuboCop
|
|
16
16
|
class Builder < Parser::Builders::Default
|
17
17
|
self.emit_forward_arg = true
|
18
18
|
|
19
|
+
# @api private
|
19
20
|
NODE_MAP = {
|
20
21
|
and: AndNode,
|
21
22
|
alias: AliasNode,
|
@@ -27,6 +28,7 @@ module RuboCop
|
|
27
28
|
case_match: CaseMatchNode,
|
28
29
|
case: CaseNode,
|
29
30
|
class: ClassNode,
|
31
|
+
const: ConstNode,
|
30
32
|
def: DefNode,
|
31
33
|
defined?: DefinedNode,
|
32
34
|
defs: DefNode,
|
@@ -48,6 +50,7 @@ module RuboCop
|
|
48
50
|
or: OrNode,
|
49
51
|
pair: PairNode,
|
50
52
|
regexp: RegexpNode,
|
53
|
+
rescue: RescueNode,
|
51
54
|
resbody: ResbodyNode,
|
52
55
|
return: ReturnNode,
|
53
56
|
csend: SendNode,
|
data/lib/rubocop/ast/node.rb
CHANGED
@@ -21,41 +21,67 @@ module RuboCop
|
|
21
21
|
class Node < Parser::AST::Node # rubocop:disable Metrics/ClassLength
|
22
22
|
include RuboCop::AST::Sexp
|
23
23
|
extend NodePattern::Macros
|
24
|
+
include RuboCop::AST::Descendence
|
24
25
|
|
26
|
+
# @api private
|
25
27
|
# <=> isn't included here, because it doesn't return a boolean.
|
26
|
-
COMPARISON_OPERATORS = %i[== === != <= >= > <].freeze
|
28
|
+
COMPARISON_OPERATORS = %i[== === != <= >= > <].to_set.freeze
|
27
29
|
|
30
|
+
# @api private
|
28
31
|
TRUTHY_LITERALS = %i[str dstr xstr int float sym dsym array
|
29
32
|
hash regexp true irange erange complex
|
30
|
-
rational regopt].freeze
|
31
|
-
|
33
|
+
rational regopt].to_set.freeze
|
34
|
+
# @api private
|
35
|
+
FALSEY_LITERALS = %i[false nil].to_set.freeze
|
36
|
+
# @api private
|
32
37
|
LITERALS = (TRUTHY_LITERALS + FALSEY_LITERALS).freeze
|
38
|
+
# @api private
|
33
39
|
COMPOSITE_LITERALS = %i[dstr xstr dsym array hash irange
|
34
|
-
erange regexp].freeze
|
40
|
+
erange regexp].to_set.freeze
|
41
|
+
# @api private
|
35
42
|
BASIC_LITERALS = (LITERALS - COMPOSITE_LITERALS).freeze
|
43
|
+
# @api private
|
36
44
|
MUTABLE_LITERALS = %i[str dstr xstr array hash
|
37
|
-
regexp irange erange].freeze
|
45
|
+
regexp irange erange].to_set.freeze
|
46
|
+
# @api private
|
38
47
|
IMMUTABLE_LITERALS = (LITERALS - MUTABLE_LITERALS).freeze
|
39
48
|
|
49
|
+
# @api private
|
40
50
|
EQUALS_ASSIGNMENTS = %i[lvasgn ivasgn cvasgn gvasgn
|
41
|
-
casgn masgn].freeze
|
42
|
-
|
51
|
+
casgn masgn rasgn mrasgn].to_set.freeze
|
52
|
+
# @api private
|
53
|
+
SHORTHAND_ASSIGNMENTS = %i[op_asgn or_asgn and_asgn].to_set.freeze
|
54
|
+
# @api private
|
43
55
|
ASSIGNMENTS = (EQUALS_ASSIGNMENTS + SHORTHAND_ASSIGNMENTS).freeze
|
44
56
|
|
45
|
-
|
46
|
-
|
47
|
-
|
57
|
+
# @api private
|
58
|
+
BASIC_CONDITIONALS = %i[if while until].to_set.freeze
|
59
|
+
# @api private
|
60
|
+
CONDITIONALS = (BASIC_CONDITIONALS + [:case]).freeze
|
61
|
+
# @api private
|
62
|
+
POST_CONDITION_LOOP_TYPES = %i[while_post until_post].to_set.freeze
|
63
|
+
# @api private
|
48
64
|
LOOP_TYPES = (POST_CONDITION_LOOP_TYPES + %i[while until for]).freeze
|
49
|
-
|
50
|
-
|
65
|
+
# @api private
|
66
|
+
VARIABLES = %i[ivar gvar cvar lvar].to_set.freeze
|
67
|
+
# @api private
|
68
|
+
REFERENCES = %i[nth_ref back_ref].to_set.freeze
|
69
|
+
# @api private
|
51
70
|
KEYWORDS = %i[alias and break case class def defs defined?
|
52
71
|
kwbegin do else ensure for if module next
|
53
72
|
not or postexe redo rescue retry return self
|
54
73
|
super zsuper then undef until when while
|
55
|
-
yield].freeze
|
56
|
-
|
57
|
-
|
58
|
-
|
74
|
+
yield].to_set.freeze
|
75
|
+
# @api private
|
76
|
+
OPERATOR_KEYWORDS = %i[and or].to_set.freeze
|
77
|
+
# @api private
|
78
|
+
SPECIAL_KEYWORDS = %w[__FILE__ __LINE__ __ENCODING__].to_set.freeze
|
79
|
+
# @api private
|
80
|
+
ARGUMENT_TYPES = %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg].to_set.freeze
|
81
|
+
|
82
|
+
LITERAL_RECURSIVE_METHODS = (COMPARISON_OPERATORS + %i[* ! <=>]).freeze
|
83
|
+
LITERAL_RECURSIVE_TYPES = (OPERATOR_KEYWORDS + COMPOSITE_LITERALS + %i[begin pair]).freeze
|
84
|
+
private_constant :LITERAL_RECURSIVE_METHODS, :LITERAL_RECURSIVE_TYPES
|
59
85
|
|
60
86
|
# @see https://www.rubydoc.info/gems/ast/AST/Node:initialize
|
61
87
|
def initialize(type, children = [], properties = {})
|
@@ -92,6 +118,16 @@ module RuboCop
|
|
92
118
|
@mutable_attributes[:parent] = node
|
93
119
|
end
|
94
120
|
|
121
|
+
# @return [Boolean]
|
122
|
+
def parent?
|
123
|
+
!!parent
|
124
|
+
end
|
125
|
+
|
126
|
+
# @return [Boolean]
|
127
|
+
def root?
|
128
|
+
!parent
|
129
|
+
end
|
130
|
+
|
95
131
|
def complete!
|
96
132
|
@mutable_attributes.freeze
|
97
133
|
each_child_node(&:complete!)
|
@@ -116,12 +152,50 @@ module RuboCop
|
|
116
152
|
|
117
153
|
# Returns the index of the receiver node in its siblings. (Sibling index
|
118
154
|
# uses zero based numbering.)
|
155
|
+
# Use is discouraged, this is a potentially slow method.
|
119
156
|
#
|
120
|
-
# @return [Integer] the index of the receiver node in its siblings
|
157
|
+
# @return [Integer, nil] the index of the receiver node in its siblings
|
121
158
|
def sibling_index
|
122
159
|
parent&.children&.index { |sibling| sibling.equal?(self) }
|
123
160
|
end
|
124
161
|
|
162
|
+
# Use is discouraged, this is a potentially slow method and can lead
|
163
|
+
# to even slower algorithms
|
164
|
+
# @return [Node, nil] the right (aka next) sibling
|
165
|
+
def right_sibling
|
166
|
+
return unless parent
|
167
|
+
|
168
|
+
parent.children[sibling_index + 1].freeze
|
169
|
+
end
|
170
|
+
|
171
|
+
# Use is discouraged, this is a potentially slow method and can lead
|
172
|
+
# to even slower algorithms
|
173
|
+
# @return [Node, nil] the left (aka previous) sibling
|
174
|
+
def left_sibling
|
175
|
+
i = sibling_index
|
176
|
+
return if i.nil? || i.zero?
|
177
|
+
|
178
|
+
parent.children[i - 1].freeze
|
179
|
+
end
|
180
|
+
|
181
|
+
# Use is discouraged, this is a potentially slow method and can lead
|
182
|
+
# to even slower algorithms
|
183
|
+
# @return [Array<Node>] the left (aka previous) siblings
|
184
|
+
def left_siblings
|
185
|
+
return [].freeze unless parent
|
186
|
+
|
187
|
+
parent.children[0...sibling_index].freeze
|
188
|
+
end
|
189
|
+
|
190
|
+
# Use is discouraged, this is a potentially slow method and can lead
|
191
|
+
# to even slower algorithms
|
192
|
+
# @return [Array<Node>] the right (aka next) siblings
|
193
|
+
def right_siblings
|
194
|
+
return [].freeze unless parent
|
195
|
+
|
196
|
+
parent.children[sibling_index + 1..-1].freeze
|
197
|
+
end
|
198
|
+
|
125
199
|
# Common destructuring method. This can be used to normalize
|
126
200
|
# destructuring for different variations of the node.
|
127
201
|
# Some node types override this with their own custom
|
@@ -163,106 +237,10 @@ module RuboCop
|
|
163
237
|
each_ancestor.to_a
|
164
238
|
end
|
165
239
|
|
166
|
-
#
|
167
|
-
#
|
168
|
-
#
|
169
|
-
# Note that this is different from `node.children.each { |child| ... }`
|
170
|
-
# which yields all children including non-node elements.
|
171
|
-
#
|
172
|
-
# @overload each_child_node
|
173
|
-
# Yield all nodes.
|
174
|
-
# @overload each_child_node(type)
|
175
|
-
# Yield only nodes matching the type.
|
176
|
-
# @param [Symbol] type a node type
|
177
|
-
# @overload each_child_node(type_a, type_b, ...)
|
178
|
-
# Yield only nodes matching any of the types.
|
179
|
-
# @param [Symbol] type_a a node type
|
180
|
-
# @param [Symbol] type_b a node type
|
181
|
-
# @yieldparam [Node] node each child node
|
182
|
-
# @return [self] if a block is given
|
183
|
-
# @return [Enumerator] if no block is given
|
184
|
-
def each_child_node(*types)
|
185
|
-
return to_enum(__method__, *types) unless block_given?
|
186
|
-
|
187
|
-
children.each do |child|
|
188
|
-
next unless child.is_a?(Node)
|
189
|
-
|
190
|
-
yield child if types.empty? || types.include?(child.type)
|
191
|
-
end
|
192
|
-
|
193
|
-
self
|
194
|
-
end
|
195
|
-
|
196
|
-
# Returns an array of child nodes.
|
197
|
-
# This is a shorthand for `node.each_child_node.to_a`.
|
198
|
-
#
|
199
|
-
# @return [Array<Node>] an array of child nodes
|
200
|
-
def child_nodes
|
201
|
-
each_child_node.to_a
|
202
|
-
end
|
203
|
-
|
204
|
-
# Calls the given block for each descendant node with depth first order.
|
205
|
-
# If no block is given, an `Enumerator` is returned.
|
206
|
-
#
|
207
|
-
# @overload each_descendant
|
208
|
-
# Yield all nodes.
|
209
|
-
# @overload each_descendant(type)
|
210
|
-
# Yield only nodes matching the type.
|
211
|
-
# @param [Symbol] type a node type
|
212
|
-
# @overload each_descendant(type_a, type_b, ...)
|
213
|
-
# Yield only nodes matching any of the types.
|
214
|
-
# @param [Symbol] type_a a node type
|
215
|
-
# @param [Symbol] type_b a node type
|
216
|
-
# @yieldparam [Node] node each descendant node
|
217
|
-
# @return [self] if a block is given
|
218
|
-
# @return [Enumerator] if no block is given
|
219
|
-
def each_descendant(*types, &block)
|
220
|
-
return to_enum(__method__, *types) unless block_given?
|
221
|
-
|
222
|
-
visit_descendants(types, &block)
|
223
|
-
|
224
|
-
self
|
225
|
-
end
|
226
|
-
|
227
|
-
# Returns an array of descendant nodes.
|
228
|
-
# This is a shorthand for `node.each_descendant.to_a`.
|
229
|
-
#
|
230
|
-
# @return [Array<Node>] an array of descendant nodes
|
231
|
-
def descendants
|
232
|
-
each_descendant.to_a
|
233
|
-
end
|
234
|
-
|
235
|
-
# Calls the given block for the receiver and each descendant node in
|
236
|
-
# depth-first order.
|
237
|
-
# If no block is given, an `Enumerator` is returned.
|
238
|
-
#
|
239
|
-
# This method would be useful when you treat the receiver node as the root
|
240
|
-
# of a tree and want to iterate over all nodes in the tree.
|
241
|
-
#
|
242
|
-
# @overload each_node
|
243
|
-
# Yield all nodes.
|
244
|
-
# @overload each_node(type)
|
245
|
-
# Yield only nodes matching the type.
|
246
|
-
# @param [Symbol] type a node type
|
247
|
-
# @overload each_node(type_a, type_b, ...)
|
248
|
-
# Yield only nodes matching any of the types.
|
249
|
-
# @param [Symbol] type_a a node type
|
250
|
-
# @param [Symbol] type_b a node type
|
251
|
-
# @yieldparam [Node] node each node
|
252
|
-
# @return [self] if a block is given
|
253
|
-
# @return [Enumerator] if no block is given
|
254
|
-
def each_node(*types, &block)
|
255
|
-
return to_enum(__method__, *types) unless block_given?
|
256
|
-
|
257
|
-
yield self if types.empty? || types.include?(type)
|
258
|
-
|
259
|
-
visit_descendants(types, &block)
|
260
|
-
|
261
|
-
self
|
262
|
-
end
|
263
|
-
|
240
|
+
# Note: Some rare nodes may have no source, like `s(:args)` in `foo {}`
|
241
|
+
# @return [String, nil]
|
264
242
|
def source
|
265
|
-
loc.expression
|
243
|
+
loc.expression&.source
|
266
244
|
end
|
267
245
|
|
268
246
|
def source_range
|
@@ -389,10 +367,10 @@ module RuboCop
|
|
389
367
|
define_method(recursive_kind) do
|
390
368
|
case type
|
391
369
|
when :send
|
392
|
-
|
370
|
+
LITERAL_RECURSIVE_METHODS.include?(method_name) &&
|
393
371
|
receiver.send(recursive_kind) &&
|
394
372
|
arguments.all?(&recursive_kind)
|
395
|
-
when
|
373
|
+
when LITERAL_RECURSIVE_TYPES
|
396
374
|
children.compact.all?(&recursive_kind)
|
397
375
|
else
|
398
376
|
send(kind_filter)
|
@@ -581,15 +559,6 @@ module RuboCop
|
|
581
559
|
end
|
582
560
|
end
|
583
561
|
|
584
|
-
protected
|
585
|
-
|
586
|
-
def visit_descendants(types, &block)
|
587
|
-
each_child_node do |child|
|
588
|
-
yield child if types.empty? || types.include?(child.type)
|
589
|
-
child.visit_descendants(types, &block)
|
590
|
-
end
|
591
|
-
end
|
592
|
-
|
593
562
|
private
|
594
563
|
|
595
564
|
def visit_ancestors(types)
|
@@ -12,6 +12,7 @@ module RuboCop
|
|
12
12
|
include MethodIdentifierPredicates
|
13
13
|
|
14
14
|
VOID_CONTEXT_METHODS = %i[each tap].freeze
|
15
|
+
private_constant :VOID_CONTEXT_METHODS
|
15
16
|
|
16
17
|
# The `send` node associated with this block.
|
17
18
|
#
|
@@ -25,7 +26,7 @@ module RuboCop
|
|
25
26
|
# @return [Array<Node>]
|
26
27
|
def arguments
|
27
28
|
if numblock_type?
|
28
|
-
[] # Numbered parameters have no block arguments.
|
29
|
+
[].freeze # Numbered parameters have no block arguments.
|
29
30
|
else
|
30
31
|
node_parts[1]
|
31
32
|
end
|
@@ -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
|