Skip to content

Commit 56a0b40

Browse files
tobiclaude
andcommitted
Blank-body matrix revised: strict keeps historical suppression, strict2 surfaces
Suppression of blank-body inline error text is the historical behavior in BOTH lax and strict (matching current reference liquid, so both mode sections validate against the gem); strict2 is the new contract where an evaluated error must be visible regardless of body blankness. Raised-error mode is orthogonal: all modes raise. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent f223aa4 commit 56a0b40

1 file changed

Lines changed: 183 additions & 22 deletions

File tree

specs/liquid_ruby/blank_body_error_handling.yml

Lines changed: 183 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,18 @@
1111
# variables ({{ ... }}, {% echo %}) are never blank, so their errors always
1212
# print.
1313
#
14-
# MODE MATRIX (decided 2026-07-05): suppression is a LAX-MODE compatibility
15-
# behavior. In strict and strict2 the error text must SURFACE even for blank
16-
# bodies — silent failure of an erroring condition is not acceptable in the
17-
# strict modes. NOTE: reference liquid currently suppresses in every parse
18-
# mode (BlockBody.rescue_render_node's `unless blank_tag` guard, kept for
19-
# backwards compatibility); the strict/strict2 specs below therefore define
20-
# required behavior beyond current reference conformance.
14+
# MODE MATRIX:
15+
# - lax inline-error mode preserves the historical blank-body suppression.
16+
# - strict inline-error mode also preserves that historical suppression for
17+
# backwards compatibility.
18+
# - strict2 is the new behavior: blank bodies must NOT suppress inline error
19+
# text. If an error is evaluated, strict2 should make it visible.
20+
# - raised-error mode is separate from inline-error output. With raised errors
21+
# enabled, all modes raise; blank-body suppression only controls rendered
22+
# inline error TEXT.
2123
#
22-
# All lax expectations in this file were validated verbatim against reference
23-
# liquid (line_numbers: true).
24+
# Lax/strict expectations were validated against current reference liquid.
25+
# Strict2 expectations intentionally define the new desired behavior.
2426

2527
specs:
2628

@@ -155,31 +157,44 @@ specs:
155157
ERROR TEXT of a blank tag is suppressed; evaluation and side effects are
156158
unchanged.
157159
158-
# ── Strict modes: suppression does NOT apply ────────────────────────────────
160+
# ── Strict mode: historical inline-error suppression remains ────────────────
159161

160-
- name: blank_if_body_shows_error_text_strict
162+
- name: blank_if_body_suppresses_error_text_strict
161163
template: "{% if 5 > \"x\" %}{% endif %}"
162164
error_mode: :strict
163165
render_errors: true
164-
expected: "Liquid error (line 1): comparison of Integer with String failed"
166+
expected: ""
167+
complexity: 750
168+
hint: |
169+
QUIRK: strict mode still preserves the historical inline-error text
170+
suppression for blank block bodies. The condition is evaluated and the
171+
error is recorded/raised in raised-error mode, but render_errors/inline
172+
output stays empty for compatibility.
173+
174+
- name: blank_unless_body_suppresses_error_text_strict
175+
template: "{% unless 5 > \"x\" %} {% endunless %}"
176+
error_mode: :strict
177+
render_errors: true
178+
expected: ""
165179
complexity: 750
166180
hint: |
167-
In strict mode the blank-body suppression does NOT apply: an erroring
168-
condition surfaces its error text even when the body is blank. Silent
169-
failure is a lax-only compatibility behavior. (Reference liquid currently
170-
suppresses here too — this spec defines the required strict behavior.)
181+
Whitespace-only unless bodies are blank in strict mode too. This documents
182+
the compatibility behavior that strict2 intentionally changes.
171183
172-
- name: blank_for_body_shows_error_text_strict
184+
- name: blank_for_body_suppresses_error_text_strict
173185
template: "{% for i in (1..3) offset: xs %}{% endfor %}"
174186
environment:
175187
xs: "bad"
176188
error_mode: :strict
177189
render_errors: true
178-
expected: "Liquid error (line 1): invalid integer"
190+
expected: ""
179191
complexity: 750
180192
hint: |
181-
Same rule for loops: strict mode surfaces the invalid-offset error even
182-
with a blank body.
193+
QUIRK: strict-mode inline-error suppression applies to blank for bodies.
194+
The invalid offset is evaluated, but because the body is blank the inline
195+
"Liquid error (...)" text is not written to output.
196+
197+
# ── strict2: blank bodies must not suppress inline errors ───────────────────
183198

184199
- name: blank_if_body_shows_error_text_strict2
185200
template: "{% if 5 > \"x\" %}{% endif %}"
@@ -188,5 +203,151 @@ specs:
188203
expected: "Liquid error (line 1): comparison of Integer with String failed"
189204
complexity: 750
190205
hint: |
191-
strict2 follows strict: no blank-body suppression. Every erroring
192-
condition is visible.
206+
NEW STRICT2 CONTRACT: strict2 stops the historical blank-body suppression.
207+
The body is blank, but the condition still errors, so inline-error output
208+
must include the "Liquid error (...)" text.
209+
210+
- name: whitespace_if_body_shows_error_text_strict2
211+
template: "{% if 5 > \"x\" %} {% endif %}"
212+
error_mode: strict2
213+
render_errors: true
214+
expected: "Liquid error (line 1): comparison of Integer with String failed"
215+
complexity: 750
216+
hint: |
217+
NEW STRICT2 CONTRACT: whitespace-only text is blank for lax/strict
218+
compatibility, but strict2 must not hide the condition error text.
219+
220+
- name: assign_if_body_shows_error_text_strict2
221+
template: "{% if 5 > \"x\" %}{% assign a = 1 %}{% endif %}"
222+
error_mode: strict2
223+
render_errors: true
224+
expected: "Liquid error (line 1): comparison of Integer with String failed"
225+
complexity: 750
226+
hint: |
227+
NEW STRICT2 CONTRACT: assign nodes produce no output and used to make the
228+
body blank enough to suppress inline errors. strict2 should surface the
229+
error text anyway.
230+
231+
- name: comment_if_body_shows_error_text_strict2
232+
template: "{% if 5 > \"x\" %}{% comment %}c{% endcomment %}{% endif %}"
233+
error_mode: strict2
234+
render_errors: true
235+
expected: "Liquid error (line 1): comparison of Integer with String failed"
236+
complexity: 750
237+
hint: |
238+
NEW STRICT2 CONTRACT: comments are blank output, but strict2 should not use
239+
blankness as a reason to hide an erroring condition.
240+
241+
- name: capture_if_body_shows_error_text_strict2
242+
template: "{% if 5 > \"x\" %}{% capture c %}text{% endcapture %}{% endif %}"
243+
error_mode: strict2
244+
render_errors: true
245+
expected: "Liquid error (line 1): comparison of Integer with String failed"
246+
complexity: 750
247+
hint: |
248+
NEW STRICT2 CONTRACT: capture writes to a variable, not output. That made
249+
it blank for historical suppression, but strict2 should still render the
250+
condition error text.
251+
252+
- name: blank_unless_body_shows_error_text_strict2
253+
template: "{% unless 5 > \"x\" %} {% endunless %}"
254+
error_mode: strict2
255+
render_errors: true
256+
expected: "Liquid error (line 1): comparison of Integer with String failed"
257+
complexity: 750
258+
hint: |
259+
NEW STRICT2 CONTRACT: unless follows if. A blank unless body does not hide
260+
the error text from evaluating its condition.
261+
262+
- name: blank_for_body_shows_error_text_strict2
263+
template: "{% for i in (1..3) offset: xs %}{% endfor %}"
264+
environment:
265+
xs: "bad"
266+
error_mode: strict2
267+
render_errors: true
268+
expected: "Liquid error (line 1): invalid integer"
269+
complexity: 750
270+
hint: |
271+
NEW STRICT2 CONTRACT: for follows the same rule. A blank body should not
272+
hide an invalid offset error in strict2.
273+
274+
# ── Raised-error mode: blankness never swallows the exception ───────────────
275+
276+
- name: blank_if_body_raises_error_lax
277+
template: "{% if 5 > \"x\" %}{% endif %}"
278+
error_mode: :lax
279+
errors:
280+
render_error:
281+
- Liquid::ArgumentError
282+
- comparison of Integer with String failed
283+
complexity: 750
284+
hint: |
285+
Blank-body suppression only affects inline rendered error TEXT. With raised
286+
errors enabled, the evaluated condition raises even in lax mode.
287+
288+
- name: blank_if_body_raises_error_strict
289+
template: "{% if 5 > \"x\" %}{% endif %}"
290+
error_mode: :strict
291+
errors:
292+
render_error:
293+
- Liquid::ArgumentError
294+
- comparison of Integer with String failed
295+
complexity: 750
296+
hint: |
297+
Strict raised-error mode raises the condition error. There is no output
298+
suppression path because rendering aborts with the exception.
299+
300+
- name: blank_if_body_raises_error_strict2
301+
template: "{% if 5 > \"x\" %}{% endif %}"
302+
error_mode: strict2
303+
errors:
304+
render_error:
305+
- Liquid::ArgumentError
306+
- comparison of Integer with String failed
307+
complexity: 750
308+
hint: |
309+
strict2 also raises when strict_errors are enabled. The strict2 inline
310+
behavior differs from lax/strict, but raised-error behavior is the same:
311+
evaluated errors raise.
312+
313+
- name: blank_for_body_raises_error_lax
314+
template: "{% for i in (1..3) offset: xs %}{% endfor %}"
315+
environment:
316+
xs: "bad"
317+
error_mode: :lax
318+
errors:
319+
render_error:
320+
- Liquid::ArgumentError
321+
- invalid integer
322+
complexity: 750
323+
hint: |
324+
The invalid offset is evaluated before the loop body. Inline lax mode may
325+
hide the rendered text for blank bodies, but raised-error mode still raises.
326+
327+
- name: blank_for_body_raises_error_strict
328+
template: "{% for i in (1..3) offset: xs %}{% endfor %}"
329+
environment:
330+
xs: "bad"
331+
error_mode: :strict
332+
errors:
333+
render_error:
334+
- Liquid::ArgumentError
335+
- invalid integer
336+
complexity: 750
337+
hint: |
338+
Strict raised-error mode raises the invalid offset even though the body is
339+
blank.
340+
341+
- name: blank_for_body_raises_error_strict2
342+
template: "{% for i in (1..3) offset: xs %}{% endfor %}"
343+
environment:
344+
xs: "bad"
345+
error_mode: strict2
346+
errors:
347+
render_error:
348+
- Liquid::ArgumentError
349+
- invalid integer
350+
complexity: 750
351+
hint: |
352+
strict2 raised-error mode raises the invalid offset. The strict2 contract
353+
also surfaces this error in inline-error mode.

0 commit comments

Comments
 (0)