Class: Contrast::Utils::RubyAstRewriter Deprecated

Inherits:
Parser::TreeRewriter
  • Object
show all
Defined in:
lib/contrast/utils/ruby_ast_rewriter.rb

Overview

Deprecated.

Changes to this class are discouraged as this approach is being phased out with support for those language versions.

This utility allows us to parse and rewrite the AST in Ruby 2.5, allowing us to track String interpolation propagation by replacing those events with String#+ events instead.

TODO: RUBY-714 remove w/ EOL of 2.5

Constant Summary collapse

VARIABLES =
%i[ivar cvar gvar].cs__freeze

Instance Method Summary collapse

Instance Method Details

#on_dstr(node) ⇒ Object

This overloads the on_dstr method in Parser::AST::Processor to handle the replace within the given node.



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
# File 'lib/contrast/utils/ruby_ast_rewriter.rb', line 36

def on_dstr node
  return if node.children.all? { |child_node| child_node.type == :str }

  new_content = +'('
  node.children.each_with_index do |child_node, index|
    # A begin node looks like #{some_code} in ruby, we do a substring
    # from [2...-1] to get rid of the #{ & trailing }.
    if child_node.type == :begin
      code = child_node.
          location.
          expression.
          source_buffer.
          source[child_node.location.begin.begin_pos...child_node.location.end.end_pos]
      code = code[2...-1]
      new_content += "((#{ code }).to_s)"

    # For interpolations that use class, instance, or global variables,
    # those are NOT within a begin block, but instead are a ivar, cvar,
    # or gvar node, not stripping of interpolation markers required.
    elsif VARIABLES.include?(child_node.type)
      variable = child_node.children.first
      new_content << "((#{ variable }).to_s)"

    # When interpolation includes strings before or after an
    # interpolation they are simple :str nodes, in order to preserve
    # escaping we need to do a dump of the string value.
    elsif child_node.type == :str
      literal_value = child_node.children.first
      literal_value = literal_value.dump[1...-1]
      new_content <<  "\"#{ literal_value }\""
    end
    new_content << ' + ' unless index == node.children.length - 1
  end
  new_content << ')'
  if node.location.cs__respond_to?(:heredoc_body)
    replace(node.location.heredoc_body, new_content)
  else
    replace(node.location.expression, new_content)
  end
end

#rewrite(source_string) ⇒ String

Rewrite the given source_string, converting the interpolation action therein to a concatenation action

Parameters:

  • source_string (String)

    the String to rewrite

Returns:

  • (String)

    either the rewritten string or the original on error.



23
24
25
26
27
28
29
30
31
32
# File 'lib/contrast/utils/ruby_ast_rewriter.rb', line 23

def rewrite source_string
  ast = Parser::CurrentRuby.parse(source_string)
  buffer = Parser::Source::Buffer.new('rewrite')
  buffer.source = source_string
  begin
    super(buffer, ast)
  rescue StandardError => _e
    source_string
  end
end