I'm trying to read a line from an io in a non-blocking way.
Unfortunately readline
blocks. I think I can solve this with read_nonblock
with an additional buffer where I store partial result, check if there are multiple lines in the buffer, etc.. but it seems a bit complicated for a simple task like this. Is there a better way to do this?
Note: I'm using event demultiplexing (select
) and I'm quite happy with it, I don't want to create threads, use EventMachine, etc...
I think the read_nonblock solution is probably the way to go. Simple, not maximally efficient monkey-patch version:
class IO
def readline_nonblock
rlnb_buffer = ""
while ch = self.read_nonblock(1)
rlnb_buffer << ch
if ch == "\n" then
result = rlnb_buffer
return result
end
end
end
end
That throws an exception if there's no data ready, just like read_nonblock, so you have to rescue that to just get a nil back, etc.
This implementation improves on Mark Reed's answer by not discarding data read that does not end in a newline:
class IO
def readline_nonblock
buffer = ""
buffer << read_nonblock(1) while buffer[-1] != "\n"
buffer
rescue IO::WaitReadable => blocking
raise blocking if buffer.empty?
buffer
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With