From eed5b1209e175408f15e72275fe6ef7c7f34ac94 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Sat, 6 Jun 2020 23:05:15 -0400 Subject: [PATCH] + New methods as_nested_actions and as_replacements to output representations of Source::TreeRewriter --- lib/parser/source/tree_rewriter.rb | 38 +++++++++++++++++++++++ lib/parser/source/tree_rewriter/action.rb | 8 +++++ test/test_source_tree_rewriter.rb | 33 ++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/lib/parser/source/tree_rewriter.rb b/lib/parser/source/tree_rewriter.rb index caf52d2c2..97804465e 100644 --- a/lib/parser/source/tree_rewriter.rb +++ b/lib/parser/source/tree_rewriter.rb @@ -260,6 +260,44 @@ def process chunks.join end + ## + # Returns a representation of the rewriter as an ordered list of replacements. + # + # rewriter.as_replacements # => [ [1...1, '('], + # [2...4, 'foo'], + # [5...6, ''], + # [6...6, '!'], + # [10...10, ')'], + # ] + # + # This representation is sufficient to recreate the result of `process` but it is + # not sufficient to recreate completely the rewriter for further merging/actions. + # See `as_nested_actions` + # + # @return [Array] an ordered list of pairs of range & replacement + # + def as_replacements + @action_root.ordered_replacements + end + + ## + # Returns a representation of the rewriter as nested insertions (:wrap) and replacements. + # + # rewriter.as_actions # =>[ [:wrap, 1...10, '(', ')'], + # [:wrap, 2...6, '', '!'], # aka "insert_after" + # [:replace, 2...4, 'foo'], + # [:replace, 5...6, ''], # aka "removal" + # ], + # + # Contrary to `as_replacements`, this representation is sufficient to recreate exactly + # the rewriter. + # + # @return [Array<(Symbol, Range, String{, String})>] + # + def as_nested_actions + @action_root.nested_actions + end + ## # Provides a protected block where a sequence of multiple rewrite actions # are handled atomically. If any of the actions failed by clobbering, diff --git a/lib/parser/source/tree_rewriter/action.rb b/lib/parser/source/tree_rewriter/action.rb index 4c420840e..26cc02600 100644 --- a/lib/parser/source/tree_rewriter/action.rb +++ b/lib/parser/source/tree_rewriter/action.rb @@ -46,6 +46,14 @@ def ordered_replacements reps end + def nested_actions + actions = [] + actions << [:wrap, @range, @insert_before, @insert_after] if !@insert_before.empty? || + !@insert_after.empty? + actions << [:replace, @range, @replacement] if @replacement + actions.concat(@children.flat_map(&:nested_actions)) + end + def insertion? !insert_before.empty? || !insert_after.empty? || (replacement && !replacement.empty?) end diff --git a/test/test_source_tree_rewriter.rb b/test/test_source_tree_rewriter.rb index 718e3d4e1..4fca87be1 100644 --- a/test/test_source_tree_rewriter.rb +++ b/test/test_source_tree_rewriter.rb @@ -265,6 +265,39 @@ def test_merge [:wrap, @hello.join(@world), '@', '@'], ]) end + + def representation_example + Parser::Source::TreeRewriter.new(@buf) + .wrap(range(1...10), '(', ')') + .insert_after(range(2...6), '!') + .replace(range(2...4), 'foo') + .remove(range(5...6)) + end + + def test_nested_actions + result = representation_example.as_nested_actions + + assert_equal( [ [:wrap, 1...10, '(', ')'], + [:wrap, 2...6, '', '!'], # aka "insert_after" + [:replace, 2...4, 'foo'], + [:replace, 5...6, ''], # aka "removal" + ], + result.each {|arr| arr[1] = arr[1].to_range } + ) + end + + def test_ordered_replacements + result = representation_example.as_replacements + + assert_equal( [ [ 1...1, '('], + [ 2...4, 'foo'], + [ 5...6, ''], + [ 6...6, '!'], + [ 10...10, ')'], + ], + result.map {|r, s| [r.to_range, s]} + ) + end end class TestSourceTreeRewriterImport < Minitest::Test