ma
marcoroth
GitHub
herb
Workspace
GitHub
CI Pipeline Executions
Filtered
Runs
Demo
Insights
Compare tasks
Analytics
Sign in
Toggle sidebar
Overview
⌘K
herb
Loading workspace stats
Loading workspace insights...
Statistics interval
7 days
30 days
Latest CI Pipeline Executions
Status
Fix filter
Filter
Fuzzy
Filter range
Sort by
Sort by
Start time
Sort ascending
Sort descending
Succeeded
analysis/rust-block-aliases
58f9a06a Analysis: Follow state through a block parameter
by Marco Roth
M
Succeeded
analysis/rust-block-aliases
69c0182c Analysis: Follow state through a block parameter A block's parameters carry whatever that block iterates, so `item` inside `@items.each do |item|` is `@items`, one at a time. Matching is by name, so nothing connected the two, and everything reached through a parameter was attributed to nothing. Ruby learned this within one template in #2280. The two ports learn it here, and the Ruby trace learns it across a render call. `affected_templates` and `state_flow` answer which templates a piece of state reaches, and they missed one shape of it. A partial rendered by `render partial:, collection:` was traced, and the same partial rendered from inside `@posts.each do |post|` was not, so `herb dependencies` and `herb actionview flow` left a template out of an answer whose whole product is that list. The collector now records the blocks open around a render call, with the names each one binds, and a local whose value is one of those names carries whatever its block iterates. `analyze` parses with `iteration_nodes` so a block that runs per item and a block that runs once are different node types. Without it, `form_with model: @post do |f|` would look like a collection and `f` would carry `@post` into every partial rendered inside the form. The C extension has always accepted the option; only its hand written signature did not mention it. Reaching the item template makes it addressable, and addressable is what made it wrong: its slots came back as an identity, which is a client writing one value into every item. A render inside an iterating block is now per item the same way `collection:` is, and only the modes below a block that runs once are left alone. Neither port needed a new dependency or the trick Ruby uses. Ruby re-parses the block opening as `Prism.parse("#{code}\nend")`, because `@posts.each do |post|` is not valid Ruby on its own, but both ports already carry the parameters on the node as `block_arguments`. Rust had two further gaps in the way: it never recorded a block, because its kind match had no case for one, and it could not have read the expression anyway, because `content_of` had no case either. All three now assert the two nodes Ruby reports for the same template, kind, path and expression alike. Nothing else anywhere asserts that they agree, and every divergence found so far was found by reading two implementations side by side. This was filed as a granularity optimisation to defer until a benchmark justified it. That was wrong. It is coarser for reactivity, where under-reporting waits for the server, and simply incorrect for the analysis commands, where the list is the answer.
by Marco Roth
M
Previous
Next