Relocation¶ ↑
Prism
parses deterministically for the same input. This provides a nice property that is exposed through the #node_id
API on nodes. Effectively this means that for the same input, these values will remain consistent every time the source is parsed. This means we can reparse the source same with a #node_id
value and find the exact same node again.
The Relocation
module provides an API around this property. It allows you to “save” nodes and locations using a minimal amount of memory (just the node_id and a field identifier) and then reify them later. This minimizes the amount of memory you need to allocate to store this information because it does not keep around a pointer to the source string.
Getting started¶ ↑
To get started with the Relocation
module, you would first instantiate a Repository
object. You do this through a DSL that chains method calls for configuration. For example, if for every entry in the repository you want to store the start and end lines, the start and end code unit columns for in UTF-16, and the leading comments, you would:
repository = Prism::Relocation.filepath("path/to/file").lines.code_unit_columns(Encoding::UTF_16).leading_comments
Now that you have the repository, you can pass it into any of the save*
APIs on nodes or locations to create entries in the repository that will be lazily reified.
# assume that node is a Prism::ClassNode object entry = node.constant_path.save(repository)
Now that you have the entry object, you do not need to keep around a reference to the repository, it will be cleaned up on its own when the last entry is reified. Now, whenever you need to, you may call the associated field methods on the entry object, as in:
entry.start_line entry.end_line entry.start_code_units_column entry.end_code_units_column entry.leading_comments
Note that if you had configured other fields to be saved, you would be able to access them as well. The first time one of these fields is accessed, the repository will reify every entry it knows about and then clean itself up. In this way, you can effectively treat them as if you had kept around lightweight versions of Prism::Node
or Prism::Location
objects.