Skip to content

Commit

Permalink
Merge pull request #3183 from ruby/relocation
Browse files Browse the repository at this point in the history
Relocation API
  • Loading branch information
kddnewton authored Oct 16, 2024
2 parents c2407a9 + 5ea6042 commit 6d06ea9
Show file tree
Hide file tree
Showing 9 changed files with 1,075 additions and 0 deletions.
34 changes: 34 additions & 0 deletions docs/relocation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 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:

```ruby
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.

```ruby
# 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:

```ruby
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.
1 change: 1 addition & 0 deletions lib/prism.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module Prism
autoload :Pack, "prism/pack"
autoload :Pattern, "prism/pattern"
autoload :Reflection, "prism/reflection"
autoload :Relocation, "prism/relocation"
autoload :Serialize, "prism/serialize"
autoload :StringQuery, "prism/string_query"
autoload :Translation, "prism/translation"
Expand Down
Loading

0 comments on commit 6d06ea9

Please sign in to comment.