synvert-core 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile +0 -3
- data/Guardfile +0 -9
- data/README.md +30 -12
- data/Rakefile +1 -15
- data/lib/synvert/core/engine/erb.rb +1 -1
- data/lib/synvert/core/engine.rb +1 -1
- data/lib/synvert/core/node_ext.rb +0 -466
- data/lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb +20 -17
- data/lib/synvert/core/rewriter/condition/if_exist_condition.rb +1 -1
- data/lib/synvert/core/rewriter/condition/unless_exist_condition.rb +1 -1
- data/lib/synvert/core/rewriter/instance.rb +83 -133
- data/lib/synvert/core/rewriter/scope/query_scope.rb +2 -2
- data/lib/synvert/core/rewriter/scope/within_scope.rb +4 -4
- data/lib/synvert/core/rewriter.rb +0 -10
- data/lib/synvert/core/version.rb +1 -1
- data/lib/synvert/core.rb +4 -6
- data/spec/synvert/core/engine/erb_spec.rb +3 -3
- data/spec/synvert/core/node_ext_spec.rb +0 -795
- data/spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb +21 -1
- data/spec/synvert/core/rewriter/instance_spec.rb +47 -115
- data/spec/synvert/core/rewriter/scope/goto_scope_spec.rb +1 -4
- data/spec/synvert/core/rewriter/scope/query_scope_spec.rb +1 -4
- data/spec/synvert/core/rewriter/scope/within_scope_spec.rb +1 -4
- data/synvert-core-ruby.gemspec +4 -2
- metadata +44 -61
- data/lib/synvert/core/array_ext.rb +0 -48
- data/lib/synvert/core/node_query/compiler/array.rb +0 -34
- data/lib/synvert/core/node_query/compiler/attribute.rb +0 -39
- data/lib/synvert/core/node_query/compiler/attribute_list.rb +0 -24
- data/lib/synvert/core/node_query/compiler/basic_selector.rb +0 -28
- data/lib/synvert/core/node_query/compiler/boolean.rb +0 -23
- data/lib/synvert/core/node_query/compiler/comparable.rb +0 -86
- data/lib/synvert/core/node_query/compiler/dynamic_attribute.rb +0 -51
- data/lib/synvert/core/node_query/compiler/expression.rb +0 -41
- data/lib/synvert/core/node_query/compiler/float.rb +0 -23
- data/lib/synvert/core/node_query/compiler/identifier.rb +0 -41
- data/lib/synvert/core/node_query/compiler/integer.rb +0 -23
- data/lib/synvert/core/node_query/compiler/invalid_operator_error.rb +0 -7
- data/lib/synvert/core/node_query/compiler/nil.rb +0 -23
- data/lib/synvert/core/node_query/compiler/parse_error.rb +0 -7
- data/lib/synvert/core/node_query/compiler/regexp.rb +0 -37
- data/lib/synvert/core/node_query/compiler/selector.rb +0 -113
- data/lib/synvert/core/node_query/compiler/string.rb +0 -23
- data/lib/synvert/core/node_query/compiler/symbol.rb +0 -23
- data/lib/synvert/core/node_query/compiler.rb +0 -25
- data/lib/synvert/core/node_query/lexer.rex +0 -99
- data/lib/synvert/core/node_query/lexer.rex.rb +0 -299
- data/lib/synvert/core/node_query/parser.racc.rb +0 -306
- data/lib/synvert/core/node_query/parser.y +0 -60
- data/lib/synvert/core/node_query.rb +0 -36
- data/lib/synvert/core/rewriter/action/append_action.rb +0 -28
- data/lib/synvert/core/rewriter/action/delete_action.rb +0 -34
- data/lib/synvert/core/rewriter/action/insert_action.rb +0 -34
- data/lib/synvert/core/rewriter/action/insert_after_action.rb +0 -22
- data/lib/synvert/core/rewriter/action/prepend_action.rb +0 -44
- data/lib/synvert/core/rewriter/action/remove_action.rb +0 -56
- data/lib/synvert/core/rewriter/action/replace_action.rb +0 -33
- data/lib/synvert/core/rewriter/action/replace_with_action.rb +0 -36
- data/lib/synvert/core/rewriter/action/wrap_action.rb +0 -37
- data/lib/synvert/core/rewriter/action.rb +0 -102
- data/spec/synvert/core/node_query/lexer_spec.rb +0 -580
- data/spec/synvert/core/node_query/parser_spec.rb +0 -337
- data/spec/synvert/core/rewriter/action/append_action_spec.rb +0 -70
- data/spec/synvert/core/rewriter/action/delete_action_spec.rb +0 -26
- data/spec/synvert/core/rewriter/action/insert_action_spec.rb +0 -70
- data/spec/synvert/core/rewriter/action/insert_after_action_spec.rb +0 -26
- data/spec/synvert/core/rewriter/action/prepend_action_spec.rb +0 -175
- data/spec/synvert/core/rewriter/action/remove_action_spec.rb +0 -26
- data/spec/synvert/core/rewriter/action/replace_action_spec.rb +0 -28
- data/spec/synvert/core/rewriter/action/replace_with_action_spec.rb +0 -59
- data/spec/synvert/core/rewriter/action/wrap_action_spec.rb +0 -31
- data/spec/synvert/core/rewriter/action_spec.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71ae91a324677995dbfd9b1251ebf2a0a01e7c25289dcebcf86abb07599b1db8
|
4
|
+
data.tar.gz: 4370235d14aee70f57b6b02313637e9d24b13ca2aee61b71e4fa4022f78bc3f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8bcd68a69575a6cd5c5c0bc7a91f82d09d2f438ab06988c01ad14c7d97c863bc2556f5c3ad7d054e35cfcb830cb778ec10a9797952a56a9391062b4bf3ce2a3f
|
7
|
+
data.tar.gz: be7b4c9fda8428c0d2a8c29350f6d2c60c40577c0f990ed5d8f4d2742fc2545fc8ddbd139298aaf39a9e69e9e9bf83fe29385745ac7ef10459da836572df9327
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/Guardfile
CHANGED
@@ -3,14 +3,5 @@
|
|
3
3
|
guard :rspec, cmd: 'bundle exec rspec' do
|
4
4
|
watch(%r{^spec/.+_spec\.rb$})
|
5
5
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
6
|
-
watch('lib/synvert/core/node_query/lexer.rex.rb') { 'spec/synvert/core/node_query/lexer_spec.rb' }
|
7
|
-
watch('lib/synvert/core/node_query/compiler.rb') { 'spec/synvert/core/node_query/parser_spec.rb' }
|
8
|
-
watch(%r{^lib/synvert/core/node_query/compiler/.*\.rb$}) { 'spec/synvert/core/node_query/parser_spec.rb' }
|
9
|
-
watch('lib/synvert/core/node_query/parser.racc.rb') { 'spec/synvert/core/node_query/parser_spec.rb' }
|
10
6
|
watch('spec/spec_helper.rb') { "spec" }
|
11
7
|
end
|
12
|
-
|
13
|
-
guard :rake, task: 'generate' do
|
14
|
-
watch('lib/synvert/core/node_query/lexer.rex')
|
15
|
-
watch('lib/synvert/core/node_query/parser.y')
|
16
|
-
end
|
data/README.md
CHANGED
@@ -8,29 +8,46 @@
|
|
8
8
|
Synvert core provides a set of DSLs to rewrite ruby code. e.g.
|
9
9
|
|
10
10
|
```ruby
|
11
|
-
Synvert::Rewriter.new '
|
11
|
+
Synvert::Rewriter.new 'factory_bot', 'convert_factory_girl_to_factory_bot' do
|
12
12
|
description <<~EOS
|
13
|
-
It converts
|
13
|
+
It converts FactoryGirl to FactoryBot
|
14
14
|
|
15
15
|
```ruby
|
16
|
-
|
17
|
-
|
18
|
-
end.flatten
|
16
|
+
require 'factory_girl'
|
17
|
+
require 'factory_girl_rails'
|
19
18
|
```
|
20
19
|
|
21
20
|
=>
|
22
21
|
|
23
22
|
```ruby
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
require 'factory_bot'
|
24
|
+
require 'factory_bot_rails'
|
25
|
+
```
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
FactoryGirl.create(:user)
|
29
|
+
FactoryGirl.build(:user)
|
30
|
+
```
|
31
|
+
|
32
|
+
=>
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
FactoryBot.create(:user)
|
36
|
+
FactoryBot.build(:user)
|
27
37
|
```
|
28
38
|
EOS
|
29
39
|
|
30
|
-
within_files Synvert::
|
31
|
-
|
32
|
-
|
33
|
-
|
40
|
+
within_files Synvert::RAILS_TEST_FILES do
|
41
|
+
find_node '.const[name=FactoryGirl]' do
|
42
|
+
replace_with 'FactoryBot'
|
43
|
+
end
|
44
|
+
|
45
|
+
find_node ".send[receiver=nil][message=require][arguments.size=1][arguments.first='factory_girl']" do
|
46
|
+
replace :arguments, with: "'factory_bot'"
|
47
|
+
end
|
48
|
+
|
49
|
+
with_node type: 'send', receiver: nil, message: 'require', arguments: { size: 1, first: "'factory_girl_rails'" } do
|
50
|
+
replace :arguments, with: "'factory_bot_rails'"
|
34
51
|
end
|
35
52
|
end
|
36
53
|
end
|
@@ -56,6 +73,7 @@ DSLs are as follows
|
|
56
73
|
|
57
74
|
Scopes:
|
58
75
|
|
76
|
+
* [find_node](./Synvert/Core/Rewriter/Instance.html#find_node-instance_method) - recursively find matching ast nodes by node query language
|
59
77
|
* [within_node](./Synvert/Core/Rewriter/Instance.html#within_node-instance_method) - recursively find matching ast nodes
|
60
78
|
* [with_node](./Synvert/Core/Rewriter/Instance.html#with_node-instance_method) - alias to within_node
|
61
79
|
* [goto_node](./Synvert/Core/Rewriter/Instance.html#goto_node-instance_method) - go to a child node
|
data/Rakefile
CHANGED
@@ -2,21 +2,7 @@
|
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require 'rspec/core/rake_task'
|
5
|
-
RSpec::Core::RakeTask.new(:spec)
|
6
|
-
require 'oedipus_lex'
|
7
|
-
Rake.application.rake_require "oedipus_lex"
|
8
|
-
|
9
|
-
file "lib/synvert/core/node_query/lexer.rex.rb" => "lib/synvert/core/node_query/lexer.rex"
|
10
|
-
file "lib/synvert/core/node_query/parser.racc.rb" => "lib/synvert/core/node_query/parser.y"
|
11
5
|
|
12
|
-
|
13
|
-
task :parser => "lib/synvert/core/node_query/parser.racc.rb"
|
14
|
-
task :generate => [:lexer, :parser]
|
15
|
-
|
16
|
-
rule '.racc.rb' => '.y' do |t|
|
17
|
-
cmd = "bundle exec racc -l -v -o #{t.name} #{t.source}"
|
18
|
-
sh cmd
|
19
|
-
end
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
20
7
|
|
21
8
|
task :default => :spec
|
22
|
-
task :spec => :generate
|
data/lib/synvert/core/engine.rb
CHANGED
@@ -29,311 +29,6 @@ module Parser::AST
|
|
29
29
|
# Source Code to Ast Node
|
30
30
|
# {https://synvert-playground.xinminlabs.com/ruby}
|
31
31
|
class Node
|
32
|
-
TYPE_CHILDREN = {
|
33
|
-
and: %i[left_value right_value],
|
34
|
-
arg: %i[name],
|
35
|
-
begin: %i[body],
|
36
|
-
block: %i[caller arguments body],
|
37
|
-
blockarg: %i[name],
|
38
|
-
const: %i[parent_const name],
|
39
|
-
class: %i[name parent_class body],
|
40
|
-
csend: %i[receiver message arguments],
|
41
|
-
cvasgn: %i[left_value right_value],
|
42
|
-
cvar: %i[name],
|
43
|
-
def: %i[name arguments body],
|
44
|
-
definded?: %i[arguments],
|
45
|
-
defs: %i[self name arguments body],
|
46
|
-
hash: %i[pairs],
|
47
|
-
ivasgn: %i[left_value right_value],
|
48
|
-
ivar: %i[name],
|
49
|
-
lvar: %i[name],
|
50
|
-
lvasgn: %i[left_value right_value],
|
51
|
-
masgn: %i[left_value right_value],
|
52
|
-
module: %i[name body],
|
53
|
-
or: %i[left_value right_value],
|
54
|
-
or_asgn: %i[left_value right_value],
|
55
|
-
pair: %i[key value],
|
56
|
-
restarg: %i[name],
|
57
|
-
send: %i[receiver message arguments],
|
58
|
-
super: %i[arguments],
|
59
|
-
zsuper: %i[]
|
60
|
-
}
|
61
|
-
|
62
|
-
# Initialize a Node.
|
63
|
-
#
|
64
|
-
# It extends {Parser::AST::Node} and set parent for its child nodes.
|
65
|
-
def initialize(type, children = [], properties = {})
|
66
|
-
@mutable_attributes = {}
|
67
|
-
super
|
68
|
-
# children could be nil for s(:array)
|
69
|
-
Array(children).each do |child_node|
|
70
|
-
if child_node.is_a?(Parser::AST::Node)
|
71
|
-
child_node.parent = self
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Get the parent node.
|
77
|
-
# @return [Parser::AST::Node] parent node.
|
78
|
-
def parent
|
79
|
-
@mutable_attributes[:parent]
|
80
|
-
end
|
81
|
-
|
82
|
-
# Set the parent node.
|
83
|
-
# @param node [Parser::AST::Node] parent node.
|
84
|
-
def parent=(node)
|
85
|
-
@mutable_attributes[:parent] = node
|
86
|
-
end
|
87
|
-
|
88
|
-
# Get the sibling nodes.
|
89
|
-
# @return [Array<Parser::AST::Node>] sibling nodes.
|
90
|
-
def siblings
|
91
|
-
index = parent.children.index(self)
|
92
|
-
parent.children[index + 1..]
|
93
|
-
end
|
94
|
-
|
95
|
-
# Dyamically defined method
|
96
|
-
# caller, key, left_value, message, name, pairs, parent_class, parent_const, receivr, rgith_value and value.
|
97
|
-
# based on const TYPE_CHILDREN.
|
98
|
-
%i[
|
99
|
-
caller
|
100
|
-
key
|
101
|
-
left_value
|
102
|
-
message
|
103
|
-
name
|
104
|
-
pairs
|
105
|
-
parent_class
|
106
|
-
parent_const
|
107
|
-
receiver
|
108
|
-
right_value
|
109
|
-
value
|
110
|
-
].each do |method_name|
|
111
|
-
define_method(method_name) do
|
112
|
-
index = TYPE_CHILDREN[type]&.index(method_name)
|
113
|
-
return children[index] if index
|
114
|
-
|
115
|
-
raise Synvert::Core::MethodNotSupported, "#{method_name} is not handled for #{debug_info}"
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# Return the left value of node.
|
120
|
-
# It supports :and, :cvagn, :lvasgn, :masgn, :or and :or_asgn nodes.
|
121
|
-
# @example
|
122
|
-
# node # s(:or_asgn, s(:lvasgn, :a), s(:int, 1))
|
123
|
-
# node.left_value # :a
|
124
|
-
# @return [Parser::AST::Node] left value of node.
|
125
|
-
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
126
|
-
def left_value
|
127
|
-
return children[0].children[0] if type == :or_asgn
|
128
|
-
|
129
|
-
index = TYPE_CHILDREN[type]&.index(:left_value)
|
130
|
-
return children[index] if index
|
131
|
-
|
132
|
-
raise Synvert::Core::MethodNotSupported, "#{left_value} is not handled for #{debug_info}"
|
133
|
-
end
|
134
|
-
|
135
|
-
# Get arguments of node.
|
136
|
-
# It supports :block, :csend, :def, :defined?, :defs and :send nodes.
|
137
|
-
# @example
|
138
|
-
# node # s(:send, s(:const, nil, :FactoryGirl), :create, s(:sym, :post), s(:hash, s(:pair, s(:sym, :title), s(:str, "post"))))
|
139
|
-
# node.arguments # [s(:sym, :post), s(:hash, s(:pair, s(:sym, :title), s(:str, "post")))]
|
140
|
-
# @return [Array<Parser::AST::Node>] arguments of node.
|
141
|
-
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
142
|
-
def arguments
|
143
|
-
case type
|
144
|
-
when :def, :block
|
145
|
-
children[1].children
|
146
|
-
when :defs
|
147
|
-
children[2].children
|
148
|
-
when :send, :csend
|
149
|
-
children[2..-1]
|
150
|
-
when :defined?
|
151
|
-
children
|
152
|
-
else
|
153
|
-
raise Synvert::Core::MethodNotSupported, "arguments is not handled for #{debug_info}"
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
# Get body of node.
|
158
|
-
# It supports :begin, :block, :class, :def, :defs and :module node.
|
159
|
-
# @example
|
160
|
-
# 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)))
|
161
|
-
# node.body # [s(:send, nil, :include, s(:const, s(:const, nil, :EmailSpec), :Helpers))]
|
162
|
-
# @return [Array<Parser::AST::Node>] body of node.
|
163
|
-
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
164
|
-
def body
|
165
|
-
case type
|
166
|
-
when :begin
|
167
|
-
children
|
168
|
-
when :def, :block, :class, :module
|
169
|
-
return [] if children[2].nil?
|
170
|
-
|
171
|
-
:begin == children[2].type ? children[2].body : children[2..-1]
|
172
|
-
when :defs
|
173
|
-
return [] if children[3].nil?
|
174
|
-
|
175
|
-
:begin == children[3].type ? children[3].body : children[3..-1]
|
176
|
-
else
|
177
|
-
raise Synvert::Core::MethodNotSupported, "body is not handled for #{debug_info}"
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
# Get condition of node.
|
182
|
-
# It supports :if node.
|
183
|
-
# @example
|
184
|
-
# node # s(:if, s(:defined?, s(:const, nil, :Bundler)), nil, nil)
|
185
|
-
# node.condition # s(:defined?, s(:const, nil, :Bundler))
|
186
|
-
# @return [Parser::AST::Node] condition of node.
|
187
|
-
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
188
|
-
def condition
|
189
|
-
if :if == type
|
190
|
-
children[0]
|
191
|
-
else
|
192
|
-
raise Synvert::Core::MethodNotSupported, "condition is not handled for #{debug_info}"
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
# Get keys of :hash node.
|
197
|
-
# @example
|
198
|
-
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)), s(:pair, s(:str, "foo"), s(:str, "bar")))
|
199
|
-
# node.keys # [s(:sym, :foo), s(:str, "foo")]
|
200
|
-
# @return [Array<Parser::AST::Node>] keys of node.
|
201
|
-
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
202
|
-
def keys
|
203
|
-
if :hash == type
|
204
|
-
children.map { |child| child.children[0] }
|
205
|
-
else
|
206
|
-
raise Synvert::Core::MethodNotSupported, "keys is not handled for #{debug_info}"
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
# Get values of :hash node.
|
211
|
-
# @example
|
212
|
-
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)), s(:pair, s(:str, "foo"), s(:str, "bar")))
|
213
|
-
# node.values # [s(:sym, :bar), s(:str, "bar")]
|
214
|
-
# @return [Array<Parser::AST::Node>] values of node.
|
215
|
-
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
216
|
-
def values
|
217
|
-
if :hash == type
|
218
|
-
children.map { |child| child.children[1] }
|
219
|
-
else
|
220
|
-
raise Synvert::Core::MethodNotSupported, "keys is not handled for #{debug_info}"
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
# Check if :hash node contains specified key.
|
225
|
-
# @example
|
226
|
-
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)))
|
227
|
-
# node.key?(:foo) # true
|
228
|
-
# @param [Symbol, String] key value.
|
229
|
-
# @return [Boolean] true if specified key exists.
|
230
|
-
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
231
|
-
def key?(key)
|
232
|
-
if :hash == type
|
233
|
-
children.any? { |pair_node| pair_node.key.to_value == key }
|
234
|
-
else
|
235
|
-
raise Synvert::Core::MethodNotSupported, "key? is not handled for #{debug_info}"
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
# Get :hash value node according to specified key.
|
240
|
-
# @example
|
241
|
-
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)))
|
242
|
-
# node.hash_value(:foo) # s(:sym, :bar)
|
243
|
-
# @param [Symbol, String] key value.
|
244
|
-
# @return [Parser::AST::Node] hash value of node.
|
245
|
-
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
246
|
-
def hash_value(key)
|
247
|
-
if :hash == type
|
248
|
-
value_node = children.find { |pair_node| pair_node.key.to_value == key }
|
249
|
-
value_node&.value
|
250
|
-
else
|
251
|
-
raise Synvert::Core::MethodNotSupported, "hash_value is not handled for #{debug_info}"
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
# Return the exact value of node.
|
256
|
-
# It supports :array, :begin, :erange, :false, :float, :irange, :int, :str, :sym and :true nodes.
|
257
|
-
# @example
|
258
|
-
# node # s(:array, s(:str, "str"), s(:sym, :str))
|
259
|
-
# node.to_value # ['str', :str]
|
260
|
-
# @return [Object] exact value.
|
261
|
-
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
262
|
-
def to_value
|
263
|
-
case type
|
264
|
-
when :int, :float, :str, :sym
|
265
|
-
children.last
|
266
|
-
when :true
|
267
|
-
true
|
268
|
-
when :false
|
269
|
-
false
|
270
|
-
when :nil
|
271
|
-
nil
|
272
|
-
when :array
|
273
|
-
children.map(&:to_value)
|
274
|
-
when :irange
|
275
|
-
(children.first.to_value..children.last.to_value)
|
276
|
-
when :erange
|
277
|
-
(children.first.to_value...children.last.to_value)
|
278
|
-
when :begin
|
279
|
-
children.first.to_value
|
280
|
-
else
|
281
|
-
self
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
# Respond key value and source for hash node, e.g.
|
286
|
-
# @example
|
287
|
-
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)))
|
288
|
-
# node.foo_value # :bar
|
289
|
-
# node.foo_source # ":bar"
|
290
|
-
def method_missing(method_name, *args, &block)
|
291
|
-
if :args == type && children.respond_to?(method_name)
|
292
|
-
return children.send(method_name, *args, &block)
|
293
|
-
elsif :hash == type && method_name.to_s.include?('_value')
|
294
|
-
key = method_name.to_s.sub('_value', '')
|
295
|
-
return hash_value(key.to_sym)&.to_value if key?(key.to_sym)
|
296
|
-
return hash_value(key.to_s)&.to_value if key?(key.to_s)
|
297
|
-
|
298
|
-
return nil
|
299
|
-
elsif :hash == type && method_name.to_s.include?('_source')
|
300
|
-
key = method_name.to_s.sub('_source', '')
|
301
|
-
return hash_value(key.to_sym)&.to_source if key?(key.to_sym)
|
302
|
-
return hash_value(key.to_s)&.to_source if key?(key.to_s)
|
303
|
-
|
304
|
-
return nil
|
305
|
-
end
|
306
|
-
|
307
|
-
super
|
308
|
-
end
|
309
|
-
|
310
|
-
def respond_to_missing?(method_name, *args)
|
311
|
-
if :args == type && children.respond_to?(method_name)
|
312
|
-
return true
|
313
|
-
elsif :hash == type && method_name.to_s.include?('_value')
|
314
|
-
key = method_name.to_s.sub('_value', '')
|
315
|
-
return true if key?(key.to_sym) || key?(key.to_s)
|
316
|
-
elsif :hash == type && method_name.to_s.include?('_source')
|
317
|
-
key = method_name.to_s.sub('_source', '')
|
318
|
-
return true if key?(key.to_sym) || key?(key.to_s)
|
319
|
-
end
|
320
|
-
|
321
|
-
super
|
322
|
-
end
|
323
|
-
|
324
|
-
# Return the debug info.
|
325
|
-
#
|
326
|
-
# @return [String] file, line, source and node.
|
327
|
-
def debug_info
|
328
|
-
"\n" +
|
329
|
-
[
|
330
|
-
"file: #{loc.expression.source_buffer.name}",
|
331
|
-
"line: #{loc.expression.line}",
|
332
|
-
"source: #{to_source}",
|
333
|
-
"node: #{inspect}"
|
334
|
-
].join("\n")
|
335
|
-
end
|
336
|
-
|
337
32
|
# Get the file name of node.
|
338
33
|
#
|
339
34
|
# @return [String] file name.
|
@@ -341,13 +36,6 @@ module Parser::AST
|
|
341
36
|
loc.expression&.source_buffer.name
|
342
37
|
end
|
343
38
|
|
344
|
-
# Get the source code of node.
|
345
|
-
#
|
346
|
-
# @return [String] source code.
|
347
|
-
def to_source
|
348
|
-
loc.expression&.source
|
349
|
-
end
|
350
|
-
|
351
39
|
# Get the column of node.
|
352
40
|
#
|
353
41
|
# @return [Integer] column.
|
@@ -362,113 +50,6 @@ module Parser::AST
|
|
362
50
|
loc.expression.line
|
363
51
|
end
|
364
52
|
|
365
|
-
# Get child node by the name.
|
366
|
-
#
|
367
|
-
# @param child_name [String] name of child node.
|
368
|
-
# @return [Parser::AST::Node] the child node.
|
369
|
-
def child_node_by_name(child_name)
|
370
|
-
direct_child_name, nested_child_name = child_name.to_s.split('.', 2)
|
371
|
-
if respond_to?(direct_child_name)
|
372
|
-
child_node = send(direct_child_name)
|
373
|
-
|
374
|
-
return child_node.child_node_by_name(nested_child_name) if nested_child_name
|
375
|
-
|
376
|
-
return nil if child_node.nil?
|
377
|
-
|
378
|
-
return child_node if child_node.is_a?(Parser::AST::Node)
|
379
|
-
|
380
|
-
return child_node
|
381
|
-
end
|
382
|
-
|
383
|
-
raise Synvert::Core::MethodNotSupported,
|
384
|
-
"child_node_by_name is not handled for #{debug_info}, child_name: #{child_name}"
|
385
|
-
end
|
386
|
-
|
387
|
-
# Get the source range of child node.
|
388
|
-
#
|
389
|
-
# @param child_name [String] name of child node.
|
390
|
-
# @return [Parser::Source::Range] source range of child node.
|
391
|
-
def child_node_range(child_name)
|
392
|
-
case [type, child_name.to_sym]
|
393
|
-
when %i[block pipes], %i[def parentheses], %i[defs parentheses]
|
394
|
-
Parser::Source::Range.new(
|
395
|
-
'(string)',
|
396
|
-
arguments.first.loc.expression.begin_pos - 1,
|
397
|
-
arguments.last.loc.expression.end_pos + 1
|
398
|
-
)
|
399
|
-
when %i[block arguments], %i[def arguments], %i[defs arguments]
|
400
|
-
Parser::Source::Range.new(
|
401
|
-
'(string)',
|
402
|
-
arguments.first.loc.expression.begin_pos,
|
403
|
-
arguments.last.loc.expression.end_pos
|
404
|
-
)
|
405
|
-
when %i[class name], %i[def name], %i[defs name]
|
406
|
-
loc.name
|
407
|
-
when %i[defs dot]
|
408
|
-
loc.operator
|
409
|
-
when %i[defs self]
|
410
|
-
Parser::Source::Range.new('(string)', loc.operator.begin_pos - 'self'.length, loc.operator.begin_pos)
|
411
|
-
when %i[send dot], %i[csend dot]
|
412
|
-
loc.dot
|
413
|
-
when %i[send message], %i[csend message]
|
414
|
-
if loc.operator
|
415
|
-
Parser::Source::Range.new('(string)', loc.selector.begin_pos, loc.operator.end_pos)
|
416
|
-
else
|
417
|
-
loc.selector
|
418
|
-
end
|
419
|
-
when %i[send parentheses], %i[csend parentheses]
|
420
|
-
if loc.begin && loc.end
|
421
|
-
Parser::Source::Range.new('(string)', loc.begin.begin_pos, loc.end.end_pos)
|
422
|
-
end
|
423
|
-
else
|
424
|
-
direct_child_name, nested_child_name = child_name.to_s.split('.', 2)
|
425
|
-
if respond_to?(direct_child_name)
|
426
|
-
child_node = send(direct_child_name)
|
427
|
-
|
428
|
-
return child_node.child_node_range(nested_child_name) if nested_child_name
|
429
|
-
|
430
|
-
return nil if child_node.nil?
|
431
|
-
|
432
|
-
if child_node.is_a?(Parser::AST::Node)
|
433
|
-
return(
|
434
|
-
Parser::Source::Range.new(
|
435
|
-
'(string)',
|
436
|
-
child_node.loc.expression.begin_pos,
|
437
|
-
child_node.loc.expression.end_pos
|
438
|
-
)
|
439
|
-
)
|
440
|
-
end
|
441
|
-
|
442
|
-
# arguments
|
443
|
-
return nil if child_node.empty?
|
444
|
-
|
445
|
-
return(
|
446
|
-
Parser::Source::Range.new(
|
447
|
-
'(string)',
|
448
|
-
child_node.first.loc.expression.begin_pos,
|
449
|
-
child_node.last.loc.expression.end_pos
|
450
|
-
)
|
451
|
-
)
|
452
|
-
end
|
453
|
-
|
454
|
-
raise Synvert::Core::MethodNotSupported,
|
455
|
-
"child_node_range is not handled for #{debug_info}, child_name: #{child_name}"
|
456
|
-
end
|
457
|
-
end
|
458
|
-
|
459
|
-
# Recursively iterate all child nodes of node.
|
460
|
-
#
|
461
|
-
# @yield [child] Gives a child node.
|
462
|
-
# @yieldparam child [Parser::AST::Node] child node
|
463
|
-
def recursive_children(&block)
|
464
|
-
children.each do |child|
|
465
|
-
if child.is_a?(Parser::AST::Node)
|
466
|
-
stop = yield child
|
467
|
-
child.recursive_children(&block) unless stop == :stop
|
468
|
-
end
|
469
|
-
end
|
470
|
-
end
|
471
|
-
|
472
53
|
# Match node with rules.
|
473
54
|
# It provides some additional keywords to match rules, +any+, +contain+, +not+, +in+, +not_in+, +gt+, +gte+, +lt+, +lte+.
|
474
55
|
# @example
|
@@ -506,53 +87,6 @@ module Parser::AST
|
|
506
87
|
end
|
507
88
|
end
|
508
89
|
|
509
|
-
# Get rewritten source code.
|
510
|
-
# @example
|
511
|
-
# node.rewritten_source("create({{arguments}})") # "create(:post)"
|
512
|
-
# @param code [String] raw code.
|
513
|
-
# @return [String] rewritten code, replace string in block !{{ }} in raw code.
|
514
|
-
# @raise [Synvert::Core::MethodNotSupported] if string in block !{{ }} does not support.
|
515
|
-
def rewritten_source(code)
|
516
|
-
code.gsub(/{{(.*?)}}/m) do
|
517
|
-
old_code = Regexp.last_match(1)
|
518
|
-
if respond_to?(old_code.split('.').first)
|
519
|
-
evaluated = child_node_by_name(old_code)
|
520
|
-
case evaluated
|
521
|
-
when Parser::AST::Node
|
522
|
-
if evaluated.type == :args
|
523
|
-
evaluated.loc.expression.source[1...-1]
|
524
|
-
else
|
525
|
-
evaluated.loc.expression.source
|
526
|
-
end
|
527
|
-
when Array
|
528
|
-
if evaluated.size > 0
|
529
|
-
file_source = evaluated.first.loc.expression.source_buffer.source
|
530
|
-
source = file_source[evaluated.first.loc.expression.begin_pos...evaluated.last.loc.expression.end_pos]
|
531
|
-
lines = source.split "\n"
|
532
|
-
lines_count = lines.length
|
533
|
-
if lines_count > 1 && lines_count == evaluated.size
|
534
|
-
new_code = []
|
535
|
-
lines.each_with_index { |line, index|
|
536
|
-
new_code << (index == 0 ? line : line[evaluated.first.indent - 2..-1])
|
537
|
-
}
|
538
|
-
new_code.join("\n")
|
539
|
-
else
|
540
|
-
source
|
541
|
-
end
|
542
|
-
end
|
543
|
-
when String, Symbol, Integer, Float
|
544
|
-
evaluated
|
545
|
-
when NilClass
|
546
|
-
'nil'
|
547
|
-
else
|
548
|
-
raise Synvert::Core::MethodNotSupported, "rewritten_source is not handled for #{evaluated.inspect}"
|
549
|
-
end
|
550
|
-
else
|
551
|
-
"{{#{old_code}}}"
|
552
|
-
end
|
553
|
-
end
|
554
|
-
end
|
555
|
-
|
556
90
|
# Strip curly braces for hash.
|
557
91
|
# @example
|
558
92
|
# node # s(:hash, s(:pair, s(:sym, :foo), s(:str, "bar")))
|