File tree 5 files changed +92
-4
lines changed
5 files changed +92
-4
lines changed Original file line number Diff line number Diff line change @@ -611,14 +611,17 @@ visitor.mutate("IfNode[predicate: Assign | OpAssign]") do |node|
611
611
node.copy(predicate: predicate)
612
612
end
613
613
614
- source = " if a = 1; end"
614
+ # remove `do_more_work` method call node
615
+ visitor.remove(" SyntaxTree::VCall[value: SyntaxTree::Ident[value: 'do_more_work']]" )
616
+
617
+ source = " if a = 1; perform_work; do_more_work; end"
615
618
program = SyntaxTree .parse(source)
616
619
617
620
SyntaxTree ::Formatter .format (source, program)
618
- # => "if a = 1\nend\n"
621
+ # => "if a = 1\n perform_work\n do_more_work\ nend\n"
619
622
620
623
SyntaxTree ::Formatter .format (source, program.accept(visitor))
621
- # => "if (a = 1)\nend\n"
624
+ # => "if (a = 1)\n perform_work\ nend\n"
622
625
```
623
626
624
627
### WithScope
Original file line number Diff line number Diff line change @@ -4,10 +4,11 @@ module SyntaxTree
4
4
# This visitor walks through the tree and copies each node as it is being
5
5
# visited. This is useful for mutating the tree before it is formatted.
6
6
class MutationVisitor < BasicVisitor
7
- attr_reader :mutations
7
+ attr_reader :mutations , :removals
8
8
9
9
def initialize
10
10
@mutations = [ ]
11
+ @removals = [ ]
11
12
end
12
13
13
14
# Create a new mutation based on the given query that will mutate the node
@@ -19,13 +20,23 @@ def mutate(query, &block)
19
20
mutations << [ Pattern . new ( query ) . compile , block ]
20
21
end
21
22
23
+ def remove ( query )
24
+ @removals << Pattern . new ( query ) . compile
25
+ end
26
+
22
27
# This is the base visit method for each node in the tree. It first creates
23
28
# a copy of the node using the visit_* methods defined below. Then it checks
24
29
# each mutation in sequence and calls it if it finds a match.
25
30
def visit ( node )
26
31
return unless node
27
32
result = node . accept ( self )
28
33
34
+ removals . each do |removal_pattern |
35
+ if removal_pattern . call ( result )
36
+ return RemovedNode . new ( location : result . location )
37
+ end
38
+ end
39
+
29
40
mutations . each do |( pattern , mutation ) |
30
41
result = mutation . call ( result ) if pattern . call ( result )
31
42
end
Original file line number Diff line number Diff line change @@ -9324,6 +9324,48 @@ def ambiguous?(q)
9324
9324
end
9325
9325
end
9326
9326
9327
+ # RemovedNode is a blank node used in places of nodes that have been removed.
9328
+ class RemovedNode < Node
9329
+ # [Array[ Comment | EmbDoc ]] the comments attached to this node
9330
+ attr_reader :comments
9331
+
9332
+ def initialize ( location :)
9333
+ @location = location
9334
+ @comments = [ ]
9335
+ end
9336
+
9337
+ def accept ( visitor )
9338
+ visitor . visit_removed_node ( self )
9339
+ end
9340
+
9341
+ def child_nodes
9342
+ [ ]
9343
+ end
9344
+
9345
+ def copy ( location : self . location )
9346
+ node = RemovedNode . new (
9347
+ location : location
9348
+ )
9349
+
9350
+ node . comments . concat ( comments . map ( &:copy ) )
9351
+
9352
+ node
9353
+ end
9354
+
9355
+ alias deconstruct child_nodes
9356
+
9357
+ def deconstruct_keys ( _keys )
9358
+ { location : location , comments : comments }
9359
+ end
9360
+
9361
+ def format ( _q )
9362
+ end
9363
+
9364
+ def ===( other )
9365
+ other . is_a? ( RemovedNode )
9366
+ end
9367
+ end
9368
+
9327
9369
# RescueEx represents the list of exceptions being rescued in a rescue clause.
9328
9370
#
9329
9371
# begin
Original file line number Diff line number Diff line change @@ -320,6 +320,9 @@ class Visitor < BasicVisitor
320
320
# Visit a RegexpLiteral node.
321
321
alias visit_regexp_literal visit_child_nodes
322
322
323
+ # Visit a RemovedNode node.
324
+ alias visit_removed_node visit_child_nodes
325
+
323
326
# Visit a Rescue node.
324
327
alias visit_rescue visit_child_nodes
325
328
Original file line number Diff line number Diff line change @@ -21,6 +21,35 @@ def test_mutates_based_on_patterns
21
21
assert_equal ( expected , SyntaxTree ::Formatter . format ( source , program ) )
22
22
end
23
23
24
+ def test_removes_node
25
+ source = <<~RUBY
26
+ App.configure do |config|
27
+ config.config_value_a = 1
28
+ config.config_value_b = 2
29
+ config.config_value_c = 2
30
+ end
31
+ RUBY
32
+
33
+ expected = <<~RUBY
34
+ App.configure do |config|
35
+ config.config_value_a = 1
36
+
37
+ config.config_value_c = 2
38
+ end
39
+ RUBY
40
+
41
+ mutation_visitor = SyntaxTree . mutation do |mutation |
42
+ mutation . remove ( "SyntaxTree::Assign[
43
+ target: SyntaxTree::Field[
44
+ name: SyntaxTree::Ident[value: 'config_value_b']
45
+ ],
46
+ ]" )
47
+ end
48
+
49
+ program = SyntaxTree . parse ( source ) . accept ( mutation_visitor )
50
+ assert_equal ( expected , SyntaxTree ::Formatter . format ( source , program ) )
51
+ end
52
+
24
53
private
25
54
26
55
def build_mutation
You can’t perform that action at this time.
0 commit comments