Class: ASTTransform::StatementRenderer

Inherits:
Object
  • Object
show all
Defined in:
lib/ast_transform/statement_renderer.rb

Overview

Renders individual statements to text via Unparser, working around the two consequences of unparsing them in isolation (line-aligned emission places each statement independently, so each is ripped out of its context):

  • Isolation loses the surrounding scope's local variables, making Unparser re-parse identifiers as method calls and fail its dstr round-trip verification — so a renderer is built once per tree with every local bound anywhere in it, and feeds Unparser that set on each render.
  • Unparser normalizes some single-line constructs into multi-line form, which would push following statements off their lines — so renders taller than their source are compressed back to one line when safely possible.

Immutable: configured with the tree's locals at construction, no per-render state.

Constant Summary collapse

LOCAL_BINDING_TYPES =

Node types that bind a local variable name: assignments plus every method/block parameter flavor.

[:lvasgn, :arg, :optarg, :restarg, :kwarg, :kwoptarg, :blockarg, :shadowarg].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(local_variables:) ⇒ StatementRenderer

Returns a new instance of StatementRenderer.

Parameters:

  • local_variables (Set<Symbol>)

    every local bound in the tree the statements come from.



40
41
42
# File 'lib/ast_transform/statement_renderer.rb', line 40

def initialize(local_variables:)
  @local_variables = local_variables
end

Class Method Details

.for_tree(node) ⇒ Object

Builds a renderer for statements of +node+'s tree, holding every local bound anywhere in it — an over-approximation that is safe because the set only informs Unparser's re-parse verification, never the rendered text.



24
25
26
# File 'lib/ast_transform/statement_renderer.rb', line 24

def for_tree(node)
  new(local_variables: collect_local_variables(node))
end

Instance Method Details

#aligned_render(node) ⇒ Object

Renders node no taller than its source when safely possible. Unparser normalizes some single-line constructs into multi-line form (e.g. modifier-if into if/end); when the render is taller than the statement's source, compress it back to one line — verified by re-parse so a statement that cannot be safely single-lined (e.g. containing a heredoc) falls back to its multi-line render.



54
55
56
57
58
59
60
61
62
63
# File 'lib/ast_transform/statement_renderer.rb', line 54

def aligned_render(node)
  render = unparse(node)
  loc = node.loc
  return render unless loc.respond_to?(:last_line) && loc.line

  source_height = loc.last_line - loc.line + 1
  return render if render.count("\n") < source_height

  compress_to_single_line(render) || render
end

#unparse(node) ⇒ String

Returns Unparser's render, informed of the tree's locals.

Parameters:

  • node (Parser::AST::Node)

    the statement to render.

Returns:

  • (String)

    Unparser's render, informed of the tree's locals.



46
47
48
# File 'lib/ast_transform/statement_renderer.rb', line 46

def unparse(node)
  Unparser.unparse(node, static_local_variables: @local_variables)
end