parser_node_ext 0.1.0 → 0.4.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/CHANGELOG.md +19 -0
- data/Gemfile.lock +2 -1
- data/lib/parser_node_ext/version.rb +1 -1
- data/lib/parser_node_ext.rb +155 -15
- data/sig/parser_node_ext.rbs +15 -13
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54f47aa3cbd58cec27d151340e935bf687be7c9cb63c523cdd8174869aebaf7e
|
4
|
+
data.tar.gz: e3e940453872b9bd0abd24a2b11b8d07c59e35613717b365b9810b0461cd1f28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 573b0ae05b18d25c04bc1efeac3f763c3872eee302d1b23fa11c054d32a1ea84afc86e7984e3ae6892f55bc39c4b0c8faadf133da1d53af6b387b8a57f55f685
|
7
|
+
data.tar.gz: b8b718a0dec190ce6b563fa9edd842d38869a58f7bc43799297e6ed88268f2fd5427315791c5b4cec62046d510056165b60683d36709d86790675eb19b14b655
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# CHANGELOG
|
2
|
+
|
3
|
+
## 0.4.0 (2022-07-07)
|
4
|
+
|
5
|
+
* raise `MethodNotSupported` error
|
6
|
+
|
7
|
+
## 0.3.0 (2022-07-04)
|
8
|
+
|
9
|
+
* Add `Node#to_hash`
|
10
|
+
|
11
|
+
## 0.2.0 (2022-06-27)
|
12
|
+
|
13
|
+
* Add `Node#to_value`
|
14
|
+
* Add `Node#to_source`
|
15
|
+
* Support `xxx_value` and `xxx_source` for `hash` node
|
16
|
+
|
17
|
+
## 0.1.0 (2022-06-26)
|
18
|
+
|
19
|
+
* Abstract from synvert-core
|
data/Gemfile.lock
CHANGED
data/lib/parser_node_ext.rb
CHANGED
@@ -5,8 +5,6 @@ require_relative "parser_node_ext/version"
|
|
5
5
|
require 'parser'
|
6
6
|
|
7
7
|
module ParserNodeExt
|
8
|
-
class Error < StandardError; end
|
9
|
-
|
10
8
|
class MethodNotSupported < StandardError; end
|
11
9
|
# Your code goes here...
|
12
10
|
|
@@ -95,7 +93,7 @@ module ParserNodeExt
|
|
95
93
|
index = TYPE_CHILDREN[type]&.index(method_name)
|
96
94
|
return children[index] if index
|
97
95
|
|
98
|
-
raise
|
96
|
+
raise MethodNotSupported, "#{method_name} is not handled for #{debug_info}"
|
99
97
|
end
|
100
98
|
end
|
101
99
|
|
@@ -105,14 +103,14 @@ module ParserNodeExt
|
|
105
103
|
# node # s(:or_asgn, s(:lvasgn, :a), s(:int, 1))
|
106
104
|
# node.left_value # :a
|
107
105
|
# @return [Parser::AST::Node] left value of node.
|
108
|
-
# @raise [
|
106
|
+
# @raise [MethodNotSupported] if calls on other node.
|
109
107
|
def left_value
|
110
108
|
return children[0].children[0] if type == :or_asgn
|
111
109
|
|
112
110
|
index = TYPE_CHILDREN[type]&.index(:left_value)
|
113
111
|
return children[index] if index
|
114
112
|
|
115
|
-
raise
|
113
|
+
raise MethodNotSupported, "#{left_value} is not handled for #{debug_info}"
|
116
114
|
end
|
117
115
|
|
118
116
|
# Get arguments of node.
|
@@ -121,7 +119,7 @@ module ParserNodeExt
|
|
121
119
|
# node # s(:send, s(:const, nil, :FactoryGirl), :create, s(:sym, :post), s(:hash, s(:pair, s(:sym, :title), s(:str, "post"))))
|
122
120
|
# node.arguments # [s(:sym, :post), s(:hash, s(:pair, s(:sym, :title), s(:str, "post")))]
|
123
121
|
# @return [Array<Parser::AST::Node>] arguments of node.
|
124
|
-
# @raise [
|
122
|
+
# @raise [MethodNotSupported] if calls on other node.
|
125
123
|
def arguments
|
126
124
|
case type
|
127
125
|
when :def, :block
|
@@ -133,7 +131,7 @@ module ParserNodeExt
|
|
133
131
|
when :defined?
|
134
132
|
children
|
135
133
|
else
|
136
|
-
raise
|
134
|
+
raise MethodNotSupported, "arguments is not handled for #{debug_info}"
|
137
135
|
end
|
138
136
|
end
|
139
137
|
|
@@ -143,7 +141,7 @@ module ParserNodeExt
|
|
143
141
|
# node # s(:block, s(:send, s(:const, nil, :RSpec), :configure), s(:args, s(:arg, :config)), s(:send, nil, :include, s(:const, s(:const, nil, :EmailSpec), :Helpers)))
|
144
142
|
# node.body # [s(:send, nil, :include, s(:const, s(:const, nil, :EmailSpec), :Helpers))]
|
145
143
|
# @return [Array<Parser::AST::Node>] body of node.
|
146
|
-
# @raise [
|
144
|
+
# @raise [MethodNotSupported] if calls on other node.
|
147
145
|
def body
|
148
146
|
case type
|
149
147
|
when :begin
|
@@ -157,7 +155,7 @@ module ParserNodeExt
|
|
157
155
|
|
158
156
|
:begin == children[3].type ? children[3].body : children[3..-1]
|
159
157
|
else
|
160
|
-
raise
|
158
|
+
raise MethodNotSupported, "body is not handled for #{debug_info}"
|
161
159
|
end
|
162
160
|
end
|
163
161
|
|
@@ -167,12 +165,12 @@ module ParserNodeExt
|
|
167
165
|
# node # s(:if, s(:defined?, s(:const, nil, :Bundler)), nil, nil)
|
168
166
|
# node.condition # s(:defined?, s(:const, nil, :Bundler))
|
169
167
|
# @return [Parser::AST::Node] condition of node.
|
170
|
-
# @raise [
|
168
|
+
# @raise [MethodNotSupported] if calls on other node.
|
171
169
|
def condition
|
172
170
|
if :if == type
|
173
171
|
children[0]
|
174
172
|
else
|
175
|
-
raise
|
173
|
+
raise MethodNotSupported, "condition is not handled for #{debug_info}"
|
176
174
|
end
|
177
175
|
end
|
178
176
|
|
@@ -181,12 +179,12 @@ module ParserNodeExt
|
|
181
179
|
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)), s(:pair, s(:str, "foo"), s(:str, "bar")))
|
182
180
|
# node.keys # [s(:sym, :foo), s(:str, "foo")]
|
183
181
|
# @return [Array<Parser::AST::Node>] keys of node.
|
184
|
-
# @raise [
|
182
|
+
# @raise [MethodNotSupported] if calls on other node.
|
185
183
|
def keys
|
186
184
|
if :hash == type
|
187
185
|
children.map { |child| child.children[0] }
|
188
186
|
else
|
189
|
-
raise
|
187
|
+
raise MethodNotSupported, "keys is not handled for #{debug_info}"
|
190
188
|
end
|
191
189
|
end
|
192
190
|
|
@@ -195,13 +193,155 @@ module ParserNodeExt
|
|
195
193
|
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)), s(:pair, s(:str, "foo"), s(:str, "bar")))
|
196
194
|
# node.values # [s(:sym, :bar), s(:str, "bar")]
|
197
195
|
# @return [Array<Parser::AST::Node>] values of node.
|
198
|
-
# @raise [
|
196
|
+
# @raise [MethodNotSupported] if calls on other node.
|
199
197
|
def values
|
200
198
|
if :hash == type
|
201
199
|
children.map { |child| child.children[1] }
|
202
200
|
else
|
203
|
-
raise
|
201
|
+
raise MethodNotSupported, "keys is not handled for #{debug_info}"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Check if :hash node contains specified key.
|
206
|
+
# @example
|
207
|
+
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)))
|
208
|
+
# node.key?(:foo) # true
|
209
|
+
# @param [Symbol, String] key value.
|
210
|
+
# @return [Boolean] true if specified key exists.
|
211
|
+
# @raise [MethodNotSupported] if calls on other node.
|
212
|
+
def key?(key)
|
213
|
+
if :hash == type
|
214
|
+
children.any? { |pair_node| pair_node.key.to_value == key }
|
215
|
+
else
|
216
|
+
raise MethodNotSupported, "key? is not handled for #{debug_info}"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Get :hash value node according to specified key.
|
221
|
+
# @example
|
222
|
+
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)))
|
223
|
+
# node.hash_value(:foo) # s(:sym, :bar)
|
224
|
+
# @param [Symbol, String] key value.
|
225
|
+
# @return [Parser::AST::Node] hash value of node.
|
226
|
+
# @raise [MethodNotSupported] if calls on other node.
|
227
|
+
def hash_value(key)
|
228
|
+
if :hash == type
|
229
|
+
value_node = children.find { |pair_node| pair_node.key.to_value == key }
|
230
|
+
value_node&.value
|
231
|
+
else
|
232
|
+
raise MethodNotSupported, "hash_value is not handled for #{debug_info}"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Return the exact value of node.
|
237
|
+
# It supports :array, :begin, :erange, :false, :float, :irange, :int, :str, :sym and :true nodes.
|
238
|
+
# @example
|
239
|
+
# node # s(:array, s(:str, "str"), s(:sym, :str))
|
240
|
+
# node.to_value # ['str', :str]
|
241
|
+
# @return [Object] exact value.
|
242
|
+
# @raise [MethodNotSupported] if calls on other node.
|
243
|
+
def to_value
|
244
|
+
case type
|
245
|
+
when :int, :float, :str, :sym
|
246
|
+
children.last
|
247
|
+
when :true
|
248
|
+
true
|
249
|
+
when :false
|
250
|
+
false
|
251
|
+
when :nil
|
252
|
+
nil
|
253
|
+
when :array
|
254
|
+
children.map(&:to_value)
|
255
|
+
when :irange
|
256
|
+
(children.first.to_value..children.last.to_value)
|
257
|
+
when :erange
|
258
|
+
(children.first.to_value...children.last.to_value)
|
259
|
+
when :begin
|
260
|
+
children.first.to_value
|
261
|
+
else
|
262
|
+
self
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# Get the source code of node.
|
267
|
+
#
|
268
|
+
# @return [String] source code.
|
269
|
+
def to_source
|
270
|
+
loc.expression&.source
|
271
|
+
end
|
272
|
+
|
273
|
+
# Convert node to a hash, so that it can be converted to a json.
|
274
|
+
def to_hash
|
275
|
+
result = { type: type }
|
276
|
+
if TYPE_CHILDREN[type]
|
277
|
+
TYPE_CHILDREN[type].each do |key|
|
278
|
+
value = send(key)
|
279
|
+
result[key] =
|
280
|
+
case value
|
281
|
+
when Array
|
282
|
+
value.map { |v| v.respond_to?(:to_hash) ? v.to_hash : v }
|
283
|
+
when Parser::AST::Node
|
284
|
+
value.to_hash
|
285
|
+
else
|
286
|
+
value
|
287
|
+
end
|
288
|
+
end
|
289
|
+
else
|
290
|
+
result[:children] = children.map { |c| c.respond_to?(:to_hash) ? c.to_hash : c }
|
291
|
+
end
|
292
|
+
result
|
293
|
+
end
|
294
|
+
|
295
|
+
# Respond key value and source for hash node, e.g.
|
296
|
+
# @example
|
297
|
+
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)))
|
298
|
+
# node.foo_value # :bar
|
299
|
+
# node.foo_source # ":bar"
|
300
|
+
def method_missing(method_name, *args, &block)
|
301
|
+
if :args == type && children.respond_to?(method_name)
|
302
|
+
return children.send(method_name, *args, &block)
|
303
|
+
elsif :hash == type && method_name.to_s.include?('_value')
|
304
|
+
key = method_name.to_s.sub('_value', '')
|
305
|
+
return hash_value(key.to_sym)&.to_value if key?(key.to_sym)
|
306
|
+
return hash_value(key.to_s)&.to_value if key?(key.to_s)
|
307
|
+
|
308
|
+
return nil
|
309
|
+
elsif :hash == type && method_name.to_s.include?('_source')
|
310
|
+
key = method_name.to_s.sub('_source', '')
|
311
|
+
return hash_value(key.to_sym)&.to_source if key?(key.to_sym)
|
312
|
+
return hash_value(key.to_s)&.to_source if key?(key.to_s)
|
313
|
+
|
314
|
+
return nil
|
315
|
+
end
|
316
|
+
|
317
|
+
super
|
318
|
+
end
|
319
|
+
|
320
|
+
def respond_to_missing?(method_name, *args)
|
321
|
+
if :args == type && children.respond_to?(method_name)
|
322
|
+
return true
|
323
|
+
elsif :hash == type && method_name.to_s.include?('_value')
|
324
|
+
key = method_name.to_s.sub('_value', '')
|
325
|
+
return true if key?(key.to_sym) || key?(key.to_s)
|
326
|
+
elsif :hash == type && method_name.to_s.include?('_source')
|
327
|
+
key = method_name.to_s.sub('_source', '')
|
328
|
+
return true if key?(key.to_sym) || key?(key.to_s)
|
204
329
|
end
|
330
|
+
|
331
|
+
super
|
332
|
+
end
|
333
|
+
|
334
|
+
# Return the debug info.
|
335
|
+
#
|
336
|
+
# @return [String] file, line, source and node.
|
337
|
+
def debug_info
|
338
|
+
"\n" +
|
339
|
+
[
|
340
|
+
"file: #{loc.expression.source_buffer.name}",
|
341
|
+
"line: #{loc.expression.line}",
|
342
|
+
"source: #{to_source}",
|
343
|
+
"node: #{inspect}"
|
344
|
+
].join("\n")
|
205
345
|
end
|
206
346
|
end
|
207
347
|
end
|
data/sig/parser_node_ext.rbs
CHANGED
@@ -2,17 +2,19 @@ module ParserNodeExt
|
|
2
2
|
VERSION: String
|
3
3
|
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
4
4
|
|
5
|
-
def arguments: Array[Parser::AST::Node]
|
6
|
-
def body: Array[Parser::AST::Node]
|
7
|
-
def caller: Parser::AST::Node
|
8
|
-
def key: Parser::AST::Node
|
9
|
-
def left_value: Parser::AST::Node | Symbol
|
10
|
-
def message: Symbol
|
11
|
-
def name: Parser::AST::Node | Symbol
|
12
|
-
def pairs: Array[Parser::AST::Node]
|
13
|
-
def parent_class: Parser::AST::Node
|
14
|
-
def receiver: Parser::AST::Node
|
15
|
-
def right_value: Parser::AST::Node
|
16
|
-
def self: Parser::AST::Node
|
17
|
-
def value: Parser::AST::Node
|
5
|
+
def arguments: () -> Array[Parser::AST::Node]
|
6
|
+
def body: () -> Array[Parser::AST::Node]
|
7
|
+
def caller: () -> Parser::AST::Node
|
8
|
+
def key: () -> Parser::AST::Node
|
9
|
+
def left_value: () -> Parser::AST::Node | Symbol
|
10
|
+
def message: () -> Symbol
|
11
|
+
def name: () -> Parser::AST::Node | Symbol
|
12
|
+
def pairs: () -> Array[Parser::AST::Node]
|
13
|
+
def parent_class: () -> Parser::AST::Node
|
14
|
+
def receiver: () -> Parser::AST::Node
|
15
|
+
def right_value: () -> Parser::AST::Node
|
16
|
+
def self: () -> Parser::AST::Node
|
17
|
+
def value: () -> Parser::AST::Node
|
18
|
+
|
19
|
+
def to_hash: () -> Hash
|
18
20
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parser_node_ext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Huang
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -33,6 +33,7 @@ extensions: []
|
|
33
33
|
extra_rdoc_files: []
|
34
34
|
files:
|
35
35
|
- ".rspec"
|
36
|
+
- CHANGELOG.md
|
36
37
|
- Gemfile
|
37
38
|
- Gemfile.lock
|
38
39
|
- README.md
|