File tree Expand file tree Collapse file tree 5 files changed +92
-4
lines changed Expand file tree Collapse file tree 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|
611611 node.copy(predicate: predicate)
612612end
613613
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"
615618program = SyntaxTree .parse(source)
616619
617620SyntaxTree ::Formatter .format (source, program)
618- # => "if a = 1\nend\n"
621+ # => "if a = 1\n perform_work\n do_more_work\ nend\n"
619622
620623SyntaxTree ::Formatter .format (source, program.accept(visitor))
621- # => "if (a = 1)\nend\n"
624+ # => "if (a = 1)\n perform_work\ nend\n"
622625```
623626
624627### WithScope
Original file line number Diff line number Diff line change @@ -4,10 +4,11 @@ module SyntaxTree
44 # This visitor walks through the tree and copies each node as it is being
55 # visited. This is useful for mutating the tree before it is formatted.
66 class MutationVisitor < BasicVisitor
7- attr_reader :mutations
7+ attr_reader :mutations , :removals
88
99 def initialize
1010 @mutations = [ ]
11+ @removals = [ ]
1112 end
1213
1314 # Create a new mutation based on the given query that will mutate the node
@@ -19,13 +20,23 @@ def mutate(query, &block)
1920 mutations << [ Pattern . new ( query ) . compile , block ]
2021 end
2122
23+ def remove ( query )
24+ @removals << Pattern . new ( query ) . compile
25+ end
26+
2227 # This is the base visit method for each node in the tree. It first creates
2328 # a copy of the node using the visit_* methods defined below. Then it checks
2429 # each mutation in sequence and calls it if it finds a match.
2530 def visit ( node )
2631 return unless node
2732 result = node . accept ( self )
2833
34+ removals . each do |removal_pattern |
35+ if removal_pattern . call ( result )
36+ return RemovedNode . new ( location : result . location )
37+ end
38+ end
39+
2940 mutations . each do |( pattern , mutation ) |
3041 result = mutation . call ( result ) if pattern . call ( result )
3142 end
Original file line number Diff line number Diff line change @@ -9324,6 +9324,48 @@ def ambiguous?(q)
93249324 end
93259325 end
93269326
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 }
9359+ end
9360+
9361+ def format ( _q )
9362+ end
9363+
9364+ def ===( other )
9365+ other . is_a? ( RemovedNode )
9366+ end
9367+ end
9368+
93279369 # RescueEx represents the list of exceptions being rescued in a rescue clause.
93289370 #
93299371 # begin
Original file line number Diff line number Diff line change @@ -320,6 +320,9 @@ class Visitor < BasicVisitor
320320 # Visit a RegexpLiteral node.
321321 alias visit_regexp_literal visit_child_nodes
322322
323+ # Visit a RemovedNode node.
324+ alias visit_removed_node visit_child_nodes
325+
323326 # Visit a Rescue node.
324327 alias visit_rescue visit_child_nodes
325328
Original file line number Diff line number Diff line change @@ -21,6 +21,35 @@ def test_mutates_based_on_patterns
2121 assert_equal ( expected , SyntaxTree ::Formatter . format ( source , program ) )
2222 end
2323
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+
2453 private
2554
2655 def build_mutation
You can’t perform that action at this time.
0 commit comments