From f7d5f6a6f3c3e404463103383b749340f89009aa Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 15 Oct 2024 01:04:11 +1300 Subject: [PATCH] Add support for `read_until(limit:)`. --- lib/io/stream/generic.rb | 13 +++++++++---- test/io/stream/buffered.rb | 12 +++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/io/stream/generic.rb b/lib/io/stream/generic.rb index f5fba8e..9188f1d 100644 --- a/lib/io/stream/generic.rb +++ b/lib/io/stream/generic.rb @@ -86,9 +86,11 @@ def readpartial(size = nil) end # Efficiently read data from the stream until encountering pattern. - # @param pattern [String] The pattern to match. - # @return [String] The contents of the stream up until the pattern, which is consumed but not returned. - def read_until(pattern, offset = 0, chomp: true) + # @parameter pattern [String] The pattern to match. + # @parameter offset [Integer] The offset to start searching from. + # @parameter limit [Integer] The maximum number of bytes to read, including the pattern (even if chomped). + # @returns [String | Nil] The contents of the stream up until the pattern, which is consumed but not returned. + def read_until(pattern, offset = 0, limit: nil, chomp: true) # We don't want to split on the pattern, so we subtract the size of the pattern. split_offset = pattern.bytesize - 1 @@ -97,9 +99,12 @@ def read_until(pattern, offset = 0, chomp: true) offset = 0 if offset < 0 - return unless fill_read_buffer + return nil if limit and offset >= limit + return nil unless fill_read_buffer end + return nil if limit and index >= limit + @read_buffer.freeze matched = @read_buffer.byteslice(0, index+(chomp ? 0 : pattern.bytesize)) @read_buffer = @read_buffer.byteslice(index+pattern.bytesize, @read_buffer.bytesize) diff --git a/test/io/stream/buffered.rb b/test/io/stream/buffered.rb index 1f28f5d..ba5521d 100644 --- a/test/io/stream/buffered.rb +++ b/test/io/stream/buffered.rb @@ -154,7 +154,17 @@ expect(client.read_until("\n")).to be == "world" expect(client.read_until("\n")).to be_nil end - + + it "can read with a limit" do + server.write("hello\nworld\n") + server.close + + expect(client.read_until("\n", limit: 4)).to be_nil + expect(client.read_until("\n", limit: 5)).to be_nil + expect(client.read_until("\n", limit: 6)).to be == "hello" + expect(client.read_until("\n", limit: nil)).to be == "world" + end + with "with 1-byte block size" do it "can read a line with a multi-byte pattern" do server.write("hello\nworld\n")