parser_node_ext 0.1.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0d6b0cc2e9e72c692cbc566acb7ef8cd180f428b5f473ce82457e26bdffc661
4
- data.tar.gz: 37de56dc2293bb387ca423291bf7a6fa84be97ebf21c1652aba095b76cc9817d
3
+ metadata.gz: 54f47aa3cbd58cec27d151340e935bf687be7c9cb63c523cdd8174869aebaf7e
4
+ data.tar.gz: e3e940453872b9bd0abd24a2b11b8d07c59e35613717b365b9810b0461cd1f28
5
5
  SHA512:
6
- metadata.gz: 998948687de1e0555ae1f8d2e69452c382a4320d69f5106d75ba6855a5ef0b3718bf3a28acf36a3f1a1f0e4fc86f19ed7f5d8c9e482719ddf32d26fdf3887b82
7
- data.tar.gz: f339dfc3553d68ddffa96ffd4903832346cc1d29cb679eb1ec21dbe94a64551af9535de1f0d1548b90ef8e49df017cf8efa3a2f0503268cb4a9dcbdc49ed109a
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- parser_node_ext (0.1.0)
4
+ parser_node_ext (0.4.0)
5
5
  parser
6
6
 
7
7
  GEM
@@ -28,6 +28,7 @@ GEM
28
28
 
29
29
  PLATFORMS
30
30
  x86_64-darwin-21
31
+ x86_64-linux
31
32
 
32
33
  DEPENDENCIES
33
34
  parser_node_ext!
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ParserNodeExt
4
- VERSION = "0.1.0"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -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 Synvert::Core::MethodNotSupported, "#{method_name} is not handled for #{debug_info}"
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 [Synvert::Core::MethodNotSupported] if calls on other node.
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 Synvert::Core::MethodNotSupported, "#{left_value} is not handled for #{debug_info}"
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 [Synvert::Core::MethodNotSupported] if calls on other node.
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 Synvert::Core::MethodNotSupported, "arguments is not handled for #{debug_info}"
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 [Synvert::Core::MethodNotSupported] if calls on other node.
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 Synvert::Core::MethodNotSupported, "body is not handled for #{debug_info}"
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 [Synvert::Core::MethodNotSupported] if calls on other node.
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 Synvert::Core::MethodNotSupported, "condition is not handled for #{debug_info}"
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 [Synvert::Core::MethodNotSupported] if calls on other node.
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 Synvert::Core::MethodNotSupported, "keys is not handled for #{debug_info}"
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 [Synvert::Core::MethodNotSupported] if calls on other node.
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 Synvert::Core::MethodNotSupported, "keys is not handled for #{debug_info}"
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
@@ -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.1.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-06-26 00:00:00.000000000 Z
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