Module: QIO::BaseIO

Included in:
QueuedInputIO
Defined in:
lib/qio/base_io.rb

Overview

Classes that want to mimic IO can acqire much of its functionality simply by including this module and over-riding the following methods:

close
closed?
eof?
sysread(maxlen, outbuf=nil)
sysseek(offset, whence=IO::SEEK_SET)
syswrite(string)

The following methds are not provided. If you know what you’re doing, and you know that you’re going to need it, you may also over-ride:

autoclose=(bool)
autoclose?
close_on_exec=(bool)
close_on_exec?
close_read
close_write
fcntl(integer_cmd, arg)
fileno
flush
fsync
ioctl(integer_cmd, arg)
pid
reopen(other_io_or_path, mode_str=nil)
stat
sync
sync=(bool)
ungetbyte(string_or_integer)
ungetc(string)

You get all the following for free, but if that’s not good enough for you, and you’re sure you can do better, you may over-ride:

<<(obj)
advise(advice, offset=0, len=0)
binmode #TODO!
binmode? #TODO!
bytes
chars
codepoints
each
each_byte
each_char
each_codepoint
each_line
eof
external_encoding #TODO!
fdatasync
getbyte
getc   #TODO!
gets(sep=$/, limit=nil)
internal_encoding #TODO!
isatty
lineno
lineno=(lineno)
lines(sep=$/, limit=nil)
pos
pos=(pos)
print(*args)
printf(format_string, *args)
putc(obj)
puts(*args)
read(length=nil, buffer=nil)
read_nonblock(maxlen, outbuf=nil)
readbyte
reachar
readline(sep=$/, limit=nil)
readlines(sep=$/, limit=nil)
readpartial(maxlen, outbuf=nil)
rewind
seek(amount, whence=IO::SEEK_SET)
set_encoding(ext_enc, int_enc=nil, opt=nil) #TODO!
tell
to_i  # if you defined fileno
tty?
write(string)
write_nonblock(string)

Instance Method Summary collapse

Instance Method Details

#<<(obj) ⇒ Object

Implementation relies on: write



88
89
90
91
# File 'lib/qio/base_io.rb', line 88

def <<(obj)
  write(obj.to_s)
  self
end

#advise(advice, offset = 0, len = 0) ⇒ Object

No-op



94
# File 'lib/qio/base_io.rb', line 94

def advise(advice, offset=0, len=0); end

#autoclose=(bool) ⇒ Object

NotImplementedError

Raises:

  • (NotImplementedError)


97
98
99
# File 'lib/qio/base_io.rb', line 97

def autoclose=(bool)
  raise NotImplementedError
end

#autoclose?Boolean

NotImplementedError

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


102
103
104
# File 'lib/qio/base_io.rb', line 102

def autoclose?
  raise NotImplementedError
end

#binmodeObject

TODO: Implement binmode.



107
108
# File 'lib/qio/base_io.rb', line 107

def binmode
end

#binmode?Boolean

TODO: Implement: binmode?

Returns:

  • (Boolean)


111
112
113
# File 'lib/qio/base_io.rb', line 111

def binmode?
  true
end

#bytesObject Also known as: each_byte

Implementation relies on: getbyte



116
117
118
119
120
121
# File 'lib/qio/base_io.rb', line 116

def bytes
  return to_enum :bytes unless block_given?
  while b = getbyte
    yield b
  end
end

#charsObject Also known as: each_char

Implementation relies on: getc



125
126
127
128
129
130
# File 'lib/qio/base_io.rb', line 125

def chars
  return to_enum :chars unless block_given?
  while c = getc
    yield c
  end
end

#closeObject

Over-ride me!

Raises:

  • (NotImplementedError)


134
135
136
# File 'lib/qio/base_io.rb', line 134

def close
  raise NotImplementedError, "Subclass should over-ride!"
end

#close_on_exec=(bool) ⇒ Object

NotImplementedError

Raises:

  • (NotImplementedError)


139
140
141
# File 'lib/qio/base_io.rb', line 139

def close_on_exec=(bool)
  raise NotImplementedError
end

#close_on_exec?Boolean

NotImplementedError

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


144
145
146
# File 'lib/qio/base_io.rb', line 144

def close_on_exec?
  raise NotImplementedError
end

#close_readObject

NotImplementedError

Raises:

  • (NotImplementedError)


149
150
151
# File 'lib/qio/base_io.rb', line 149

def close_read
  raise NotImplementedError
end

#close_writeObject

NotImplementedError

Raises:

  • (NotImplementedError)


154
155
156
# File 'lib/qio/base_io.rb', line 154

def close_write
  raise NotImplementedError
end

#closed?Boolean

Over-ride me!

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


159
160
161
# File 'lib/qio/base_io.rb', line 159

def closed?
  raise NotImplementedError, "Subclass should over-ride!"
end

#codepointsObject Also known as: each_codepoint

Implementation relies on: getc



164
165
166
167
168
169
170
171
# File 'lib/qio/base_io.rb', line 164

def codepoints
  return to_enum :codepoints unless block_given?
  while c = getc
    c.codepoints.each do |cp|
      yield cp
    end
  end
end

#eof?Boolean Also known as: eof

Over-ride me!

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


175
176
177
# File 'lib/qio/base_io.rb', line 175

def eof?
  raise NotImplementedError, "Subclass should over-ride!"
end

#external_encodingObject

TODO: Implement external_encoding

Raises:

  • (NotImplementedError)


181
182
183
# File 'lib/qio/base_io.rb', line 181

def external_encoding
  raise NotImplementedError
end

#fcntl(integer_cmd, arg) ⇒ Object

NotImplementedError

Raises:

  • (NotImplementedError)


186
187
188
# File 'lib/qio/base_io.rb', line 186

def fcntl(integer_cmd, arg)
  raise NotImplementedError
end

#fdatasyncObject

Implementation relies on: fsync



191
192
193
# File 'lib/qio/base_io.rb', line 191

def fdatasync
  fsync
end

#filenoObject Also known as: to_i

NotImplementedError

Raises:

  • (NotImplementedError)


196
197
198
# File 'lib/qio/base_io.rb', line 196

def fileno
  raise NotImplementedError
end

#flushObject

NotImplementedError

Raises:

  • (NotImplementedError)


202
203
204
# File 'lib/qio/base_io.rb', line 202

def flush
  raise NotImplementedError
end

#fsyncObject

NotImplementedError

Raises:

  • (NotImplementedError)


207
208
209
# File 'lib/qio/base_io.rb', line 207

def fsync
  raise NotImplementedError
end

#getbyteObject

Implementation relies on: read



212
213
214
# File 'lib/qio/base_io.rb', line 212

def getbyte
  read(1)
end

#getcObject

TODO: Implement getc (probably need to know about encoding conversions first)

Raises:

  • (NotImplementedError)


217
218
219
# File 'lib/qio/base_io.rb', line 217

def getc
  raise NotImplementedError
end

#gets(sep = $/, limit = nil) ⇒ Object

Implementation relies on: getc TODO: Maybe it should rely on getbyte instead, so we don’t read too many bytes on accident.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/qio/base_io.rb', line 223

def gets(sep=$/, limit=nil)
  return nil if eof?
  if limit.nil? && sep.is_a?(Integer) #TODO: compare this logic with ::IO#getc
    limit = sep.to_i
    sep = $/
  end
  if !limit.nil? && limit < 0
    raise ArgumentError, ('negative limit %1d given' % limit)
  end
  sep = "\n\n" if sep == ""
  line = ""
  while (c = getc)
    line << c
    break if !sep.nil? && line.end_with?(sep)
    break if !limit.nil? && line.bytesize >= limit
  end
  if !limit.nil? && limit >= 0 && line.bytesize > limit
    leftovers = line.byteslice(limit .. -1) #TODO: what should we do with this?
    line = line.byteslice(0,limit)
  end
  $. = (lineno += 1)
  $_ = line
end

#internal_encodingObject

TODO: Implement internal_encoding

Raises:

  • (NotImplementedError)


248
249
250
# File 'lib/qio/base_io.rb', line 248

def internal_encoding
  raise NotImplementedError
end

#ioctl(integer_cmd, arg) ⇒ Object

NotImplementedError

Raises:

  • (NotImplementedError)


253
254
255
# File 'lib/qio/base_io.rb', line 253

def ioctl(integer_cmd, arg)
  raise NotImplementedError
end

#isattyObject Also known as: tty?

Always returns false



258
259
260
# File 'lib/qio/base_io.rb', line 258

def isatty
  false
end

#linenoObject

Implementation relies on gets to properly keep this up-to-date.



264
265
266
# File 'lib/qio/base_io.rb', line 264

def lineno
  @lineno || uninitialized!
end

#lineno=(lineno) ⇒ Object



268
269
270
# File 'lib/qio/base_io.rb', line 268

def lineno=(lineno)
  @lineno = lineno
end

#lines(sep = $/, limit = nil) ⇒ Object Also known as: each, each_line

Implementation relies on: gets



273
274
275
276
277
278
# File 'lib/qio/base_io.rb', line 273

def lines(sep=$/, limit=nil)
  return to_enum :lines unless block_given?
  while s = gets
    yield s
  end
end

#pidObject

NotImplementedError

Raises:

  • (NotImplementedError)


283
284
285
# File 'lib/qio/base_io.rb', line 283

def pid
  raise NotImplementedError
end

#posObject Also known as: tell

Subclass is responsible for keeping pos up-to-date!



288
289
290
# File 'lib/qio/base_io.rb', line 288

def pos
  @pos || uninitialized!
end

#pos=(pos) ⇒ Object

Subclass is responsible for keeping pos up-to-date!



294
295
296
# File 'lib/qio/base_io.rb', line 294

def pos=(pos)
  @pos = pos
end

Implementation relies on write.



299
300
301
302
303
304
305
306
307
308
309
# File 'lib/qio/base_io.rb', line 299

def print(*args)
  args = [$_] if args.size == 0
  first_one = true
  args.each do |obj|
    write(obj.to_s)
    write($,) unless first_one || $,.nil?
    first_one = false
  end
  write($\) unless $\.nil?
  nil
end

#printf(format_string, *args) ⇒ Object

Implementation relies on print.



312
313
314
# File 'lib/qio/base_io.rb', line 312

def printf(format_string, *args)
  print(Kernel.sprintf(format_string, *args))
end

#putc(obj) ⇒ Object

Implementation relies on write.



317
318
319
320
321
322
323
# File 'lib/qio/base_io.rb', line 317

def putc(obj)
  if obj.is_a?(Numeric)
    write((obj.to_i & 0xff).chr)
  else
    write(obj.to_s.byteslice(0))
  end
end

#puts(*args) ⇒ Object



325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/qio/base_io.rb', line 325

def puts(*args)
  if args.size == 0
    write("\n")
  else
    args.flatten.each do |line|
      line = line.to_s
      write(line)
      write("\n") unless line.end_with?("\n")
    end
  end
  nil
end

#read(length = nil, buffer = nil) ⇒ Object



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# File 'lib/qio/base_io.rb', line 338

def read(length=nil, buffer=nil)
  if !length.nil? && length < 0
    raise ArgumentError, ('negative length %1d given' % length)
  end

  buffer = buffer.nil? ? "" : buffer.replace("")
  if length.nil?
    begin
      buffer << readpartial until eof?
    rescue EOFError
    end
    # TODO: Apply encoding conversion to buffer.
    buffer
  elsif length == 0
    buffer
  else
    begin
      while buffer.bytesize < length && !eof?
        buffer << readpartial(length - buffer.bytesize)
        # TODO: Code Review - result should be ASCII-8BIT. Is it?
      end
    rescue EOFError
    end
    buffer.empty? ? nil : buffer
  end
end

#read_nonblock(maxlen, outbuf = nil) ⇒ Object



365
366
367
368
369
# File 'lib/qio/base_io.rb', line 365

def read_nonblock(maxlen, outbuf=nil)
  nonblock_readable do
    sysread(maxlen, outbuff)
  end
end

#readbyteObject

Implementation relies on getbyte



372
373
374
# File 'lib/qio/base_io.rb', line 372

def readbyte
  getbyte || raise(EOFError)
end

#readcharObject

Implementation relies on: getc



377
378
379
# File 'lib/qio/base_io.rb', line 377

def readchar
  getc || raise(EOFError)
end

#readline(sep = $/, limit = nil) ⇒ Object

Implementation relies on: gets



382
383
384
# File 'lib/qio/base_io.rb', line 382

def readline(sep=$/, limit=nil)
  gets(sep, limit) || raise(EOFError)
end

#readlines(sep = $/, limit = nil) ⇒ Object

Implementation relies on: gets



387
388
389
390
391
392
393
394
395
396
397
# File 'lib/qio/base_io.rb', line 387

def readlines(sep=$/, limit=nil)
  result = []
  loop do
    if (line = gets(sep, limit))
      break
    else
      result << line
    end
  end
  result
end

#readpartial(maxlen, outbuf = nil) ⇒ Object

Implementation relies on: read_nonblock



400
401
402
403
404
405
# File 'lib/qio/base_io.rb', line 400

def readpartial(maxlen, outbuf=nil)
  read_nonblock(maxlen, outbuf)
rescue IO::WaitReadable
  block_until_readable
  retry
end

#reopen(other_io_or_path, mode_str = nil) ⇒ Object

NotImplementedError

Raises:

  • (NotImplementedError)


408
409
410
# File 'lib/qio/base_io.rb', line 408

def reopen(other_io_or_path, mode_str=nil)
  raise NotImplementedError
end

#rewindObject

Implementation relies on: seek



413
414
415
# File 'lib/qio/base_io.rb', line 413

def rewind
  seek(0)
end

#seek(amount, whence = IO::SEEK_SET) ⇒ Object

Implementation relies on: sysseek



418
419
420
# File 'lib/qio/base_io.rb', line 418

def seek(amount, whence=IO::SEEK_SET)
  sysseek(amount, whence)
end

#set_encoding(ext_enc, int_enc = nil, opt = nil) ⇒ Object

TODO: Implement set_encoding

Raises:

  • (NotImplementedError)


423
424
425
# File 'lib/qio/base_io.rb', line 423

def set_encoding(ext_enc, int_enc=nil, opt=nil)
  raise NotImplementedError
end

#statObject

NotImplementedError

Raises:

  • (NotImplementedError)


428
429
430
# File 'lib/qio/base_io.rb', line 428

def stat
  raise NotImplementedError
end

#syncObject

NotImplementedError

Raises:

  • (NotImplementedError)


433
434
435
# File 'lib/qio/base_io.rb', line 433

def sync
  raise NotImplementedError
end

#sync=(bool) ⇒ Object

NotImplementedError

Raises:

  • (NotImplementedError)


438
439
440
# File 'lib/qio/base_io.rb', line 438

def sync=(bool)
  raise NotImplementedError
end

#sysread(maxlen, outbuf = nil) ⇒ Object

Over-ride me! Remember to count bytes, not chars. Remember to update pos. Remember to use consume_readable to wrap the atomic part of your update.

Raises:

  • (NotImplementedError)


446
447
448
# File 'lib/qio/base_io.rb', line 446

def sysread(maxlen, outbuf=nil)
  raise NotImplementedError
end

#sysseek(offset, whence = IO::SEEK_SET) ⇒ Object

Over-ride me! Remember to count bytes, not chars. Remember to update pos.

Raises:

  • (NotImplementedError)


453
454
455
# File 'lib/qio/base_io.rb', line 453

def sysseek(offset, whence=IO::SEEK_SET)
  raise NotImplementedError # TODO: provide best-effort implementation for sysseek
end

#syswrite(string) ⇒ Object

Over-ride me! Remember to count bytes, not chars. Remember to update pos. Remember to use consume_writable to wrap the atomic part of your update.

Raises:

  • (NotImplementedError)


461
462
463
# File 'lib/qio/base_io.rb', line 461

def syswrite(string)
  raise NotImplementedError
end

#ungetbyte(string_or_integer) ⇒ Object

NotImplementedError

Raises:

  • (NotImplementedError)


466
467
468
# File 'lib/qio/base_io.rb', line 466

def ungetbyte(string_or_integer)
  raise NotImplementedError
end

#ungetc(string) ⇒ Object

NotImplementedError

Raises:

  • (NotImplementedError)


471
472
473
# File 'lib/qio/base_io.rb', line 471

def ungetc(string)
  raise NotImplementedError
end

#write(string) ⇒ Object

Implementation relies on: write_nonblock



476
477
478
479
480
481
482
483
484
485
486
487
488
# File 'lib/qio/base_io.rb', line 476

def write(string)
  written = 0
  length = string.bytesize
  while written < length
    begin
      written += write_nonblock(string.byteslice(written, length - written))
    rescue IO::WaitWritable, Errno::EINTR
      block_until_writable
      retry
    end
  end
  written
end

#write_nonblock(string) ⇒ Object

Implementation relies on: syswrite



491
492
493
494
495
# File 'lib/qio/base_io.rb', line 491

def write_nonblock(string)
  nonblock_writable do
    syswrite(string)
  end
end