{"atom":"regression/argfiles","family":"regression","slug":"argfiles","header":{"atom":"regression/argfiles","kind":"whole-program — a minimal repro, not yet reduced to an atom","source":"curated"},"axes":null,"cols":null,"engines":["rakudo-2026.07","rakupp-3.14.0"],"kinds":["ref","pp"],"defFrom":"rakupp:t/regression/argfiles.raku","counts":{"a":1,"f":0,"d":0,"c":0,"r":0,"n":0},"files":["atoms/regression/argfiles.grid"],"records":[["0001","","# Regression: $*ARGFILES (issue #14) was undefined — `say $*ARGFILES` printed\n# (Any) and `.lines` yielded nothing, so the awk/perl-style one-liner\n# `$*ARGFILES.lines>>.words.classify(*[1])` produced an empty Bag.\n#\n# The reading machinery already existed (a bare `lines()` spans @*ARGS); what\n# was missing was the HANDLE. It is built on ACCESS, never at startup — a\n# program that doesn't mention it must not read files or block on stdin — and\n# holds the concatenated content of every file in @*ARGS, or reads $*IN when\n# there are none.\n#\n# Fixing it also fixed in-memory handles generally: the lines/get/words path\n# had no branch for a \"captured\" handle, so `run(…, :out).out.lines` — the\n# same shape — silently returned nothing.\n# Contract: exit 0 + last line PASS.\nmy @fail;\nmy $rakupp = $*EXECUTABLE.absolute;\nmy $dir = $*TMPDIR.add(\"rakupp-argf-{$*PID}\");\n$dir.mkdir;\nmy $a = $dir.add('a.txt'); $a.spurt(\"x\\ny\\n\");\nmy $b = $dir.add('b.txt'); $b.spurt(\"z\\n\");\n\nsub rp(*@args, :$in, :$err) {\n    my $p = $in\n        ?? do { my $q = run($rakupp, |@args, :in, :out, :err); $q.in.print($in); $q.in.close; $q }\n        !! run($rakupp, |@args, :out, :err);\n    my $o = $p.out.slurp(:close); my $e = $p.err.slurp(:close);\n    ($err ?? $e !! $o).chomp\n}\n\n# one file, two files — .lines spans them in order\n@fail.push('one file')  unless rp('-e', 'say $*ARGFILES.lines.join(\"|\")', $a.absolute) eq 'x|y';\n@fail.push('two files') unless rp('-e', 'say $*ARGFILES.lines.join(\"|\")', $a.absolute, $b.absolute) eq 'x|y|z';\n\n# the issue's own shape: classify over words of every line\n@fail.push('classify') unless rp('-e', 'say $*ARGFILES.lines>>.words.classify(*[0]).keys.sort.join(\",\")', $a.absolute) eq 'x,y';\n\n# .slurp / .get / .words / gist\n@fail.push('slurp') unless rp('-e', 'say $*ARGFILES.slurp.chars', $a.absolute) eq '4';\n@fail.push('get')   unless rp('-e', 'say $*ARGFILES.get', $a.absolute) eq 'x';\n@fail.push('words') unless rp('-e', 'say $*ARGFILES.words.join(\",\")', $a.absolute) eq 'x,y';\n@fail.push('gist')  unless rp('-e', 'say $*ARGFILES', $a.absolute)\n                            eq \"IO::ArgFiles(opened on \\\"{$a.absolute}\\\".IO)\";\n\n# no arguments: reads standard input\n@fail.push('stdin') unless rp('-e', 'say $*ARGFILES.lines.join(\"|\")', :in(\"p\\nq\\n\")) eq 'p|q';\n\n# it must not be built unless used — a program with a file argument that never\n# mentions $*ARGFILES still runs (and @*ARGS keeps the names)\n@fail.push('unused') unless rp('-e', 'say @*ARGS.elems', $a.absolute) eq '1';\n\n# a file that cannot be opened is FATAL, as in Rakudo — silently skipping it\n# turned a mistyped path into an empty result (this is how the issue's reporter\n# and I both chased a phantom for a while)\n@fail.push('missing file must fail')\n    unless rp('-e', 'say $*ARGFILES.lines.elems', '/nonexistent-rakupp-xyz', :err)\n             .contains('Failed to open file');\n\n# an UNDEFINED classify key keeps its gist (Nil, (Any), (Int)) instead of\n# collapsing to the empty string — the `*[1]` classifier on a line with fewer\n# than two words is exactly that case\n@fail.push('classify Nil key')\n    unless rp('-e', 'say (1,2).classify({ Nil }).Bag') eq 'Bag(Nil(2))';\n@fail.push('classify Any key')\n    unless rp('-e', 'say (1,2).classify({ Any }).Bag') eq 'Bag((Any)(2))';\n@fail.push('classify empty-string key stays empty')\n    unless rp('-e', 'say (1,2).classify({ \"\" }).Bag') eq 'Bag((2))';\n\n# the same in-memory-handle path, through a Proc\n@fail.push('proc.out.lines') unless rp('-e', 'my $p = run(\"printf\", \"a\\nb\\n\", :out); say $p.out.lines.join(\"|\")') eq 'a|b';\n\nunlink($a, $b);\nrmdir($dir);\n\nif @fail { note \"FAILED:\\n\" ~ @fail.join(\"\\n\"); say 'FAIL' }\nelse     { say 'PASS' }","output PASS","a",["PASS","PASS"],0,[["budget","43s"]]]]}