1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
# frozen_string_literal: true
module Parser
##
# {Parser::TreeRewriter} offers a basic API that makes it easy to rewrite
# existing ASTs. It's built on top of {Parser::AST::Processor} and
# {Parser::Source::TreeRewriter}
#
# For example, assume you want to remove `do` tokens from a while statement.
# You can do this as following:
#
# require 'parser/current'
#
# class RemoveDo < Parser::TreeRewriter
# def on_while(node)
# # Check if the statement starts with "do"
# if node.location.begin.is?('do')
# remove(node.location.begin)
# end
# end
# end
#
# code = <<-EOF
# while true do
# puts 'hello'
# end
# EOF
#
# ast = Parser::CurrentRuby.parse code
# buffer = Parser::Source::Buffer.new('(example)', source: code)
# rewriter = RemoveDo.new
#
# # Rewrite the AST, returns a String with the new form.
# puts rewriter.rewrite(buffer, ast)
#
# This would result in the following Ruby code:
#
# while true
# puts 'hello'
# end
#
# Keep in mind that {Parser::TreeRewriter} does not take care of indentation when
# inserting/replacing code so you'll have to do this yourself.
#
# See also [a blog entry](http://whitequark.org/blog/2013/04/26/lets-play-with-ruby-code/)
# describing rewriters in greater detail.
#
# @api public
#
class TreeRewriter < Parser::AST::Processor
##
# Rewrites the AST/source buffer and returns a String containing the new
# version.
#
# @param [Parser::Source::Buffer] source_buffer
# @param [Parser::AST::Node] ast
# @param [Symbol] crossing_deletions:, different_replacements:, swallowed_insertions:
# policy arguments for TreeRewriter (optional)
# @return [String]
#
def rewrite(source_buffer,
ast,
**policy)
@source_rewriter = Parser::Source::TreeRewriter.new(source_buffer, **policy)
process(ast)
@source_rewriter.process
end
##
# Returns `true` if the specified node is an assignment node, returns false
# otherwise.
#
# @param [Parser::AST::Node] node
# @return [Boolean]
#
def assignment?(node)
[:lvasgn, :ivasgn, :gvasgn, :cvasgn, :casgn].include?(node.type)
end
##
# Removes the source range.
#
# @param [Parser::Source::Range] range
#
def remove(range)
@source_rewriter.remove(range)
end
##
# Wraps the given source range with the given values.
#
# @param [Parser::Source::Range] range
# @param [String] content
#
def wrap(range, before, after)
@source_rewriter.wrap(range, before, after)
end
##
# Inserts new code before the given source range.
#
# @param [Parser::Source::Range] range
# @param [String] content
#
def insert_before(range, content)
@source_rewriter.insert_before(range, content)
end
##
# Inserts new code after the given source range.
#
# @param [Parser::Source::Range] range
# @param [String] content
#
def insert_after(range, content)
@source_rewriter.insert_after(range, content)
end
##
# Replaces the code of the source range `range` with `content`.
#
# @param [Parser::Source::Range] range
# @param [String] content
#
def replace(range, content)
@source_rewriter.replace(range, content)
end
end
end
|