Skip to content

Commit 5fe97e6

Browse files
authored
Merge pull request #5 from kettle-rb/fix/infinite-recursion-on-non-mergeable-stmt
2 parents 6f081dd + ebe0b56 commit 5fe97e6

37 files changed

+2344
-72
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ Please file a bug if you notice a violation of semantic versioning.
2020

2121
### Added
2222

23+
- `body_has_mergeable_statements?` private method to check if a block body contains statements that can be signature-matched
24+
- `mergeable_statement?` private method to determine if a node type can generate signatures for merging
25+
- `max_recursion_depth` option (defaults to `Float::INFINITY`) as a safety valve for edge cases
26+
2327
### Changed
2428

2529
### Deprecated
@@ -28,6 +32,8 @@ Please file a bug if you notice a violation of semantic versioning.
2832

2933
### Fixed
3034

35+
- **Fixed infinite recursion** when merging `CallNode` blocks (like `git_source`) that have matching signatures but non-mergeable body content (e.g., just string literals). The fix detects when a block body contains only literals/expressions with no signature-matchable statements and treats the node atomically instead of recursing.
36+
3137
### Security
3238

3339
## [1.1.1] - 2025-12-04

README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,33 @@ merger = Prism::Merge::SmartMerger.new(
298298
# Result: Existing configs keep destination values, new configs added from template
299299
```
300300

301+
### Recursion Depth Limit
302+
303+
Prism::Merge automatically detects when block bodies contain only literals or simple expressions (no mergeable statements) and treats them atomically. However, as a safety valve for edge cases, you can limit recursion depth:
304+
305+
```ruby
306+
# Limit recursive merging to 3 levels deep
307+
merger = Prism::Merge::SmartMerger.new(
308+
template,
309+
destination,
310+
max_recursion_depth: 3,
311+
)
312+
313+
# Disable recursive merging entirely (treat all nodes atomically)
314+
merger = Prism::Merge::SmartMerger.new(
315+
template,
316+
destination,
317+
max_recursion_depth: 0,
318+
)
319+
```
320+
321+
**When to use:**
322+
323+
- **`Float::INFINITY`** (default) - Normal operation, recursion terminates naturally based on content analysis.
324+
- NOTE: If you get `stack level too deep (SystemStackError)`, please file a [bug](https://github.com/kettle-rb/prism-merge/issues)!
325+
- **Finite value** - Safety valve if you encounter edge cases with unexpected deep recursion
326+
- **`0`** - Disable recursive merging entirely; all matching nodes are treated atomically
327+
301328
### Custom Signature Generator
302329

303330
By default, Prism::Merge uses intelligent structural signatures to match nodes. The signature determines how nodes are matched between template and destination files.
@@ -332,7 +359,7 @@ The following node types support **recursive body merging**, where nested conten
332359
- `ClassNode` - class bodies are recursively merged
333360
- `ModuleNode` - module bodies are recursively merged
334361
- `SingletonClassNode` - singleton class bodies are recursively merged
335-
- `CallNode` with block - block bodies are recursively merged (e.g., `configure do ... end`)
362+
- `CallNode` with block - block bodies are recursively merged **only when the body contains mergeable statements** (e.g., `describe do ... end` with nested `it` blocks). Blocks containing only literals or simple expressions (like `git_source(:github) { |repo| "https://..." }`) are treated atomically.
336363
- `BeginNode` - begin/rescue/ensure blocks are recursively merged
337364

338365
#### Custom Signature Generator

docs/Prism.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ <h5 class="example_title"><div class='inline'><p>With debug information</p>
142142
</div>
143143

144144
<div id="footer">
145-
Generated on Thu Dec 4 15:41:08 2025 by
145+
Generated on Thu Dec 4 17:20:40 2025 by
146146
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
147147
0.9.37 (ruby-3.4.7).
148148
</div>

docs/Prism/Merge.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ <h2>
158158
</div>
159159

160160
<div id="footer">
161-
Generated on Thu Dec 4 15:41:08 2025 by
161+
Generated on Thu Dec 4 17:20:40 2025 by
162162
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
163163
0.9.37 (ruby-3.4.7).
164164
</div>

docs/Prism/Merge/ConflictResolver.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ <h3 class="signature first" id="resolve-instance_method">
852852
</div>
853853

854854
<div id="footer">
855-
Generated on Thu Dec 4 15:41:08 2025 by
855+
Generated on Thu Dec 4 17:20:41 2025 by
856856
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
857857
0.9.37 (ruby-3.4.7).
858858
</div>

docs/Prism/Merge/DebugLogger.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ <h3 class="signature first" id="debug-class_method">
322322
</div>
323323

324324
<div id="footer">
325-
Generated on Thu Dec 4 15:41:08 2025 by
325+
Generated on Thu Dec 4 17:20:40 2025 by
326326
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
327327
0.9.37 (ruby-3.4.7).
328328
</div>

docs/Prism/Merge/DestinationParseError.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ <h2>Constructor Details</h2>
175175
</div>
176176

177177
<div id="footer">
178-
Generated on Thu Dec 4 15:41:08 2025 by
178+
Generated on Thu Dec 4 17:20:40 2025 by
179179
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
180180
0.9.37 (ruby-3.4.7).
181181
</div>

docs/Prism/Merge/Error.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ <h2>Direct Known Subclasses</h2>
128128
</div>
129129

130130
<div id="footer">
131-
Generated on Thu Dec 4 15:41:08 2025 by
131+
Generated on Thu Dec 4 17:20:40 2025 by
132132
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
133133
0.9.37 (ruby-3.4.7).
134134
</div>

docs/Prism/Merge/FileAligner.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ <h3 class="signature first" id="align-instance_method">
633633
</div>
634634

635635
<div id="footer">
636-
Generated on Thu Dec 4 15:41:08 2025 by
636+
Generated on Thu Dec 4 17:20:40 2025 by
637637
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
638638
0.9.37 (ruby-3.4.7).
639639
</div>

docs/Prism/Merge/FileAligner/Anchor.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,7 @@ <h3 class="signature " id="template_range-instance_method">
901901
</div>
902902

903903
<div id="footer">
904-
Generated on Thu Dec 4 15:41:08 2025 by
904+
Generated on Thu Dec 4 17:20:41 2025 by
905905
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
906906
0.9.37 (ruby-3.4.7).
907907
</div>

0 commit comments

Comments
 (0)