Class: Rubino::Tools::ShellTool::CappedCapture
- Inherits:
-
Object
- Object
- Rubino::Tools::ShellTool::CappedCapture
- Defined in:
- lib/rubino/tools/shell_tool.rb
Overview
Bounded head+tail accumulator for a subprocess’s merged output (#539). Keeps at most cap bytes in memory no matter how much is appended: a ~10% HEAD slice (filled first) plus a sliding TAIL window (the rest of the budget), with the middle elided. Tail-biased because the bytes that matter on overflow — exit suffix, error, “N failures” — are at the end. ‘capped?` flips true once the producer has emitted MORE than the cap, so the reader can kill it; `to_s` renders the retained slice with a marker.
Instance Method Summary collapse
-
#append(bytes, raw_bytes: bytes.bytesize) ⇒ Object
Append already-UTF-8-scrubbed bytes, retaining only head+tail.
- #capped? ⇒ Boolean
-
#initialize(cap) ⇒ CappedCapture
constructor
Marker is a fixed worst-case width so it always fits inside the cap.
-
#to_s(capped: @capped) ⇒ Object
Render the retained output.
Constructor Details
#initialize(cap) ⇒ CappedCapture
Marker is a fixed worst-case width so it always fits inside the cap.
737 738 739 740 741 742 743 744 745 |
# File 'lib/rubino/tools/shell_tool.rb', line 737 def initialize(cap) @cap = [cap.to_i, 1_024].max @head_limit = [(@cap * 0.1).to_i, 1].max @tail_limit = @cap - @head_limit @head = +"" @tail = +"" @total = 0 @capped = false end |
Instance Method Details
#append(bytes, raw_bytes: bytes.bytesize) ⇒ Object
Append already-UTF-8-scrubbed bytes, retaining only head+tail. The cap is charged against raw_bytes (the bytes the pipe actually delivered) so a producer whose output scrubs to empty (‘cat /dev/zero` → pure NUL, deleted) is still capped on volume read, not on retained size (#539).
751 752 753 754 755 756 757 758 759 760 761 762 763 |
# File 'lib/rubino/tools/shell_tool.rb', line 751 def append(bytes, raw_bytes: bytes.bytesize) @total += raw_bytes if @head.bytesize < @head_limit take = @head_limit - @head.bytesize @head << bytes.byteslice(0, take) rest = bytes.byteslice(take, bytes.bytesize - take) push_tail(rest) if rest && !rest.empty? else push_tail(bytes) end @capped ||= @total > @cap self end |
#capped? ⇒ Boolean
765 766 767 |
# File 'lib/rubino/tools/shell_tool.rb', line 765 def capped? @capped end |
#to_s(capped: @capped) ⇒ Object
Render the retained output. When capped, splice in a marker that names the cap and that the producer was terminated, mirroring the elision note Util::Output.truncate uses so the model knows output was cut.
772 773 774 775 776 777 778 779 780 781 |
# File 'lib/rubino/tools/shell_tool.rb', line 772 def to_s(capped: @capped) head = scrub(@head) tail = scrub(@tail) return head + tail unless capped || @capped elided = [@total - head.bytesize - tail.bytesize, 0].max marker = "\n... [#{elided} bytes elided · output capped at #{@cap} bytes " \ "— command terminated] ...\n" head + marker + tail end |