@@ -191,9 +191,63 @@ def read_until(pattern, offset = 0, chomp: false)
191191 # Read a single line from the stream.
192192 #
193193 # @parameter separator [String] The line separator, defaults to `\n`.
194+ # @parameter limit [Integer] The maximum number of bytes to read.
194195 # @parameter *options [Hash] Additional options, passed to {read_until}.
195- def gets ( separator = NEWLINE , **options )
196- read_until ( separator , **options )
196+ def gets ( separator = NEWLINE , limit = nil , chomp : false )
197+ # If the separator is an integer, it is actually the limit:
198+ if separator . is_a? ( Integer )
199+ limit = separator
200+ separator = NEWLINE
201+ end
202+
203+ # If no separator is given, this is the same as a read operation:
204+ if separator . nil?
205+ return read ( limit )
206+ end
207+
208+ # We don't want to split on the separator, so we subtract the size of the separator:
209+ split_offset = separator . bytesize - 1
210+
211+ @buffer ||= read_next
212+ return nil if @buffer . nil?
213+
214+ offset = 0
215+ until index = @buffer . index ( separator , offset )
216+ offset = @buffer . bytesize - split_offset
217+ offset = 0 if offset < 0
218+
219+ # If we have gone past the limit, we are done:
220+ if limit and offset >= limit
221+ @buffer . freeze
222+ matched = @buffer . byteslice ( 0 , limit )
223+ @buffer = @buffer . byteslice ( limit , @buffer . bytesize )
224+ return matched
225+ end
226+
227+ # Read more data:
228+ if chunk = read_next
229+ @buffer << chunk
230+ else
231+ # No more data could be read, return the remaining data:
232+ buffer = @buffer
233+ @buffer = nil
234+
235+ return @buffer
236+ end
237+ end
238+
239+ # Freeze the buffer, as this enables us to use byteslice without generating a hidden copy:
240+ @buffer . freeze
241+
242+ if limit and index > limit
243+ line = @buffer . byteslice ( 0 , limit )
244+ @buffer = @buffer . byteslice ( limit , @buffer . bytesize )
245+ else
246+ line = @buffer . byteslice ( 0 , index +( chomp ? 0 : separator . bytesize ) )
247+ @buffer = @buffer . byteslice ( index +separator . bytesize , @buffer . bytesize )
248+ end
249+
250+ return line
197251 end
198252 end
199253
0 commit comments