module IO::Like_1_9_2
Public Class Methods
# File lib/io/like-1.9.2.rb 7 def initialize(*args) 8 super(*args) 9 @init_external_encoding = Encoding.default_external 10 @init_internal_encoding = Encoding.default_internal 11 end
Public Instance Methods
# File lib/io/like-1.9.2.rb 16 def binmode 17 raise IOError, "closed stream" if closed? 18 set_encoding(Encoding::BINARY,nil) 19 self 20 end
# File lib/io/like-1.9.2.rb 25 def binmode? 26 external_encoding == Encoding::BINARY 27 end
# File lib/io/like-1.9.2.rb 37 def close_on_exec=(coe) 38 raise NotImplementedError 39 end
# File lib/io/like-1.9.2.rb 31 def close_on_exec?() 32 raise NotImplementedError 33 end
Reads each byte from the stream and calls the given block once for each character, passing the byte as an argument.
When called without a block, returns an instance of Enumerator
which will iterate over each byte in the same manner.
NOTE: This method ignores Errno::EAGAIN
and Errno::EINTR
raised by unbuffered_read. Therefore, this method always blocks. Aside from that exception and the conversion of EOFError
results into nil
results, this method will also raise the same errors and block at the same times as unbuffered_read.
# File lib/io/like-1.9.2.rb 58 def each_byte 59 unless block_given? 60 self.to_enum(:each_byte) 61 else 62 while (byte = getbyte) 63 yield byte 64 end 65 self 66 end 67 end
As each_byte
but yields characters (encoded strings of length 1) instead of bytes
# File lib/io/like-1.9.2.rb 77 def each_char 78 unless block_given? 79 self.to_enum(:each_char) 80 else 81 while (char = getc) 82 yield char 83 end 84 self 85 end 86 end
As each_char
but yields codepoints instead of characters.
# File lib/io/like-1.9.2.rb 95 def each_codepoint 96 unless block_given? 97 self.to_enum(:each_codepoint) 98 else 99 while (char = getc) 100 yield char.codepoints.next 101 end 102 self 103 end 104 end
Reads each line from the stream using gets
and calls the given block once for each line, passing the line as an argument. Alternatively if no block is given returns an enumerator
NOTE: When sep_string is not nil
, this method ignores Errno::EAGAIN
and Errno::EINTR
raised by unbuffered_read. Therefore, this method always blocks. Aside from that exception and the conversion of EOFError
results into nil
results, this method will also raise the same errors and block at the same times as unbuffered_read.
# File lib/io/like-1.9.2.rb 126 def each_line(sep = :io_like, limit = :io_like) 127 unless block_given? 128 self.to_enum(:each) 129 else 130 while line = gets(sep, limit) 131 yield line 132 end 133 self 134 end 135 end
Returns the Encoding
object used for the external encoding.
# File lib/io/like-1.9.2.rb 591 def external_encoding 592 if writable? 593 @external_encoding || (Encoding.default_internal ? @init_external_encoding : nil ) 594 else 595 @external_encoding || (Encoding.default_internal ? @init_external_encoding : Encoding.default_external) 596 end 597 end
Calls readbyte
and either returns the result or nil
if on EOFError
.
Raises IOError
if closed? returns true
. Raises IOError
unless readable? returns true
. Raises all errors raised by unbuffered_read except for EOFError
.
NOTE: This method ignores Errno::EAGAIN
and Errno::EINTR
raised by unbuffered_read. Therefore, this method always blocks. Aside from that exception and the conversion of EOFError
results into nil
results, this method will also raise the same errors and block at the same times as unbuffered_read. nil at eof
# File lib/io/like-1.9.2.rb 157 def getbyte 158 readbyte() 159 rescue EOFError 160 nil 161 end
Calls readline
and either returns the result or nil
if readline
raises EOFError
.
If readline
returns some data, $.
is set to the value of lineno.
NOTE: Due to limitations of MRI up to version 1.9.x when running managed (Ruby) code, this method fails to set $_
to the returned data; however, other implementations may allow it.
# File lib/io/like-1.9.2.rb 181 def gets(sep_string = :io_like, limit = :io_like) 182 # Set the last read line in the global. 183 $_ = readline(sep_string, limit) 184 # Set the last line number in the global. 185 $. = lineno 186 # Return the last read line. 187 $_ 188 rescue EOFError 189 nil 190 end
Returns the Encoding
object used for internal conversion or nil if no internal conversion has been specified.
# File lib/io/like-1.9.2.rb 604 def internal_encoding 605 @internal_encoding || (@init_internal_encoding == external_encoding ? nil : @init_internal_encoding) 606 end
Writes the given object(s), if any, to the stream using write
after converting them to strings by calling their to_s
methods. If no objects are given, $_
is used. The field separator ($,
) is written between successive objects if it is not nil
. The output record separator ($\
) is written after all other data if it is not nil
.
Raises IOError
if closed? returns true
. Raises IOError
unless writable? returns true
.
NOTE: This method ignores Errno::EAGAIN
and Errno::EINTR
raised by unbuffered_write. Therefore, this method always blocks if unable to immediately write [obj, ...]
completely. Aside from that exception, this method will also raise the same errors and block at the same times as unbuffered_write.
# File lib/io/like-1.9.2.rb 211 def print(*args) 212 args << $_ if args.empty? 213 first_arg = true 214 args.each do |arg| 215 # Write a field separator before writing each argument after the first 216 # one unless no field separator is specified. 217 if first_arg then 218 first_arg = false 219 elsif ! $,.nil? then 220 write($,) 221 end 222 223 # If the argument is nil, write 'nil'; otherwise, write the stringified 224 # form of the argument. 225 if arg.nil? then 226 write("") 227 else 228 write(arg) 229 end 230 end 231 232 # Write the output record separator if one is specified. 233 write($\) unless $\.nil? 234 nil 235 end
Writes the given object(s), if any, to the stream using write
after converting them to strings using their to_s
methods. Unlike print
, Array instances are recursively processed. A record separator character is written after each object which does not end with the record separator already. If no objects are given, a single record separator is written.
Raises IOError
if closed? returns true
. Raises IOError
unless writable? returns true
.
NOTE: This method ignores Errno::EAGAIN
and Errno::EINTR
raised by unbuffered_write. Therefore, this method always blocks if unable to immediately write [obj, ...]
completely. Aside from that exception, this method will also raise the same errors and block at the same times as unbuffered_write.
NOTE: In order to be compatible with IO#puts
, the record separator is currently hardcoded to be a single newline ("\n"
) even though the documentation implies that the output record separator ($\
) should be used.
# File lib/io/like-1.9.2.rb 261 def puts(*args) 262 # Set the output record separator such that this method is compatible with 263 # IO#puts. 264 ors = "\n" 265 266 # Write only the record separator if no arguments are given. 267 if args.length == 0 then 268 write(ors) 269 return 270 end 271 272 # Write each argument followed by the record separator. Recursively 273 # process arguments which are Array instances. 274 __io_like__array_flatten(args) do |string| 275 write(string.nil? ? '' : string) 276 write(ors) if string.nil? || string.index(ors, -ors.length).nil? 277 end 278 nil 279 end
If length is specified and is a positive integer, at most length bytes are returned. Truncated data will occur if there is insufficient data left to fulfill the request. If the read starts at the end of data, nil
is returned.
If length is unspecified or nil
, an attempt to return all remaining data is made. Partial data will be returned if a low-level error is raised after some data is retrieved. If no data would be returned at all, an empty String
is returned.
If buffer is specified, it will be converted to a String
using its to_str
method if necessary and will be filled with the returned data if any.
Raises IOError
if closed? returns true
. Raises IOError
unless readable? returns true
.
NOTE: Because this method relies on unbuffered_read, it will also raise the same errors and block at the same times as that function.
# File lib/io/like-1.9.2.rb 303 def read(length = nil, buffer = nil) 304 # Check the validity of the method arguments. 305 unless length.nil? || length >= 0 then 306 raise ArgumentError, "negative length #{length} given" 307 end 308 buffer = buffer.nil? ? ''.force_encoding(Encoding::BINARY) : buffer.to_str 309 buffer.slice!(0..-1) unless buffer.empty? 310 311 if length.nil? then 312 # Read and return everything. 313 begin 314 loop do 315 buffer << __io_like__buffered_read(4096) 316 end 317 rescue EOFError 318 # Ignore this. 319 rescue SystemCallError 320 # Reraise the error if there is nothing to return. 321 raise if buffer.empty? 322 end 323 buffer.force_encoding(__io_like__external_encoding) 324 buffer.encode!(__io_like__internal_encoding,__io_like__encoding_options) if !binmode? || @internal_encoding 325 else 326 # Read and return up to length bytes. 327 enc = buffer.encoding 328 begin 329 buffer << __io_like__buffered_read(length) 330 rescue EOFError 331 # Return nil to the caller at end of file when requesting a specific 332 # amount of data. 333 return nil 334 end 335 buffer.force_encoding(enc) 336 end 337 buffer 338 end
Returns at most length bytes from the data stream using only the internal read buffer if the buffer is not empty.
If internal buffer is empty sets nonblocking mode via nonblock=(true) and then reads from the underlying stream
Raises Errno::EBADF
if nonblocking mode is not supported Raises EOFError
when there is no more data in the stream. Raises IOError
if closed? returns true
. Raises IOError
unless readable? returns true
.
This method will raise errors directly from buffered_read to be handled by the caller. If unbuffered_read raises Errno::EAGAIN
or Errno::EWOULDBLOCK
the exception will be extended with IO::WaitReadable
.
# File lib/io/like-1.9.2.rb 530 def read_nonblock(*args) 531 begin 532 super(*args) 533 rescue IO::WaitReadable 534 raise 535 rescue Errno::EWOULDBLOCK, Errno::EAGAIN => ex 536 ex.extend(IO::WaitReadable) 537 raise ex 538 end 539 end
Returns the next 8-bit byte (0..255) from the stream.
Raises EOFError
when there is no more data in the stream. Raises IOError
if closed? returns true
. Raises IOError
unless readable? returns true
.
NOTE: This method ignores Errno::EAGAIN
and Errno::EINTR
raised by unbuffered_read. Therefore, this method always blocks. Aside from that exception, this method will also raise the same errors and block at the same times as unbuffered_read.
# File lib/io/like-1.9.2.rb 353 def readbyte 354 __io_like__buffered_read(1).getbyte(0) 355 end
Returns the next character (encoded string of length 1) from the stream
Raises EOFError
when there is no more data in the stream. Raises IOError
if closed? returns true
. Raises IOError
unless readable? returns true
.
NOTE: This method ignores Errno::EAGAIN
and Errno::EINTR
raised by unbuffered_read. Therefore, this method always blocks. Aside from that exception, this method will also raise the same errors and block at the same times as unbuffered_read.
# File lib/io/like-1.9.2.rb 370 def readchar 371 __io_like__buffered_read_chars(1) 372 end
Returns the next line from the stream, where lines are separated by sep_string. Increments lineno by 1
for each call regardless of the value of sep_string.
If sep_string is not nil
and not a String
, it is first converted to a String
using its to_str
method and processing continues as follows.
If sep_string is nil
, a line is defined as the remaining contents of the stream. Partial data will be returned if a low-level error of any kind is raised after some data is retrieved. This is equivalent to calling read
without any arguments except that this method will raise an EOFError
if called at the end of the stream.
If sep_string is an empty String
, a paragraph is returned, where a paragraph is defined as data followed by 2 or more successive newline characters. A maximum of 2 newlines are returned at the end of the returned data. Fewer may be returned if the stream ends before at least 2 successive newlines are seen.
Any other value for sep_string is used as a delimiter to mark the end of a line. The returned data includes this delimiter unless the stream ends before the delimiter is seen.
In any case, the end of the stream terminates the current line.
If the limit argument is given, only that many bytesi, plus whatever is required to complete a partial multibyte character, will be read from the underlying stream while searching for the separator. If the separator is not found the partial data will be returned.
Raises EOFError
when there is no more data in the stream. Raises IOError
if closed? returns true
. Raises IOError
unless readable? returns true
.
NOTE: When sep_string is not nil
, this method ignores Errno::EAGAIN
and Errno::EINTR
raised by unbuffered_read. Therefore, this method will always block in that case. Aside from that exception, this method will raise the same errors and block at the same times as unbuffered_read.
# File lib/io/like-1.9.2.rb 423 def readline(sep_string = :io_like , limit = :io_like) 424 if sep_string == :io_like 425 #no args 426 limit = 0 427 sep_string = $/ 428 elsif limit == :io_like 429 if sep_string.nil? 430 limit = 0 431 elsif sep_string.respond_to?(:to_int) 432 #single arg (limit) 433 limit = sep_string.to_int 434 sep_string = $/ 435 elsif sep_string.respond_to?(:to_str) 436 #single arg (seperator) 437 sep_string = sep_string.to_str if sep_string 438 limit = 0 439 else 440 raise ArgumentError, "invalid args #{sep_string}, #{limit}" 441 end 442 else 443 #two args 444 limit = limit.to_int if limit 445 sep_string = sep_string.to_str if sep_string 446 end 447 448 buffer = '' 449 begin 450 if sep_string.nil? then 451 # A nil line separator means that the user wants to capture all the 452 # remaining input. 453 while limit <= 0 || buffer.bytesize < limit 454 buffer << __io_like__buffered_read_chars(limit <= 0 ? 4096 : limit - buffer.bytesize) 455 end 456 else 457 begin 458 459 # Record if the user requested paragraphs rather than lines. 460 paragraph_requested = sep_string.empty? 461 # An empty line separator string indicates that the user wants to 462 # return paragraphs. A pair of newlines in the stream is used to 463 # mark this. 464 sep_string = "\n\n" if paragraph_requested 465 466 # GG: I can't find any general guidance on how this should work in terms of searching 467 # when the separator encoding (suually from source file) doesn't match 468 # the default internal/external encoding. So instead we'll just do 469 # a binary match. 470 471 if paragraph_requested then 472 # If the user requested paragraphs instead of lines, we need to 473 # consume and discard all newlines remaining at the front of the 474 # input. 475 char = __io_like__buffered_read(1) 476 char = __io_like__buffered_read(1) while char == "\n" 477 # Put back the last character. 478 __io_like__unread(char[0]) 479 end 480 481 # Add each character from the input to the buffer until either the 482 # buffer has the right ending or the end of the input is reached. 483 while buffer.index(sep_string, -sep_string.length).nil? && (limit == 0 || buffer.bytesize < limit) do 484 buffer << __io_like__buffered_read_chars(1) 485 end 486 487 if paragraph_requested then 488 # If the user requested paragraphs instead of lines, we need to 489 # consume and discard all newlines remaining at the front of the 490 # input. 491 char = __io_like__buffered_read(1) 492 char = __io_like__buffered_read(1) while char == "\n" 493 # Put back the last character. 494 __io_like__unread(char[0]) 495 end 496 497 rescue Errno::EAGAIN, Errno::EINTR 498 retry if read_ready? 499 end 500 end 501 rescue EOFError, SystemCallError 502 # Reraise the error if there is nothing to return. 503 raise if buffer.empty? 504 end 505 # Increment the number of times this method has returned a "line". 506 self.lineno += 1 507 508 buffer 509 end
Sets external and internal encodings and encoding options. Encodings can be specified as a single string with external and internal encoding names separate by a colon, or separately as name strings or <code>Encoding</code> objects. If the final argument is a <code>Hash</code> it will be used to specify conversion options during encoding operations.
TODO: There are no rubyspecs for the option argument
# File lib/io/like-1.9.2.rb 558 def set_encoding(enc,arg2=:io_like, arg3=:io_like) 559 if enc.respond_to?(:to_str) 560 ext,int = enc.to_str.split(":", 2) 561 @external_encoding = Encoding.find(ext) 562 @internal_encoding = Encoding.find(int) if int && int != ext 563 elsif Encoding === enc 564 @external_encoding = enc 565 elsif enc.nil? 566 @external_encoding = nil 567 @init_external_encoding = writable? ? nil : Encoding.default_external 568 end 569 570 if arg2.respond_to?(:to_str) 571 @internal_encoding = Encoding.find(arg2.to_str) 572 elsif Encoding === arg2 573 @internal_encoding = arg2 if arg2 != @external_encoding 574 elsif Hash === arg2 575 @encoding_options = arg2 576 elsif arg2.nil? 577 @internal_encoding = nil 578 @init_internal_encoding = writable? ? nil : Encoding.default_internal 579 end 580 581 if Hash === arg3 582 @encoding_options = arg3 583 end 584 self 585 end
Reads and returns up to length bytes directly from the data stream, bypassing the internal read buffer.
Returns ""
if length is 0
regardless of the status of the data stream. This is for compatibility with IO#sysread
.
Raises EOFError
if reading begins at the end of the stream. Raises IOError
if closed? returns true
.
NOTE: Because this method relies on unbuffered_read, it will also raise the same errors and block at the same times as that function.
# File lib/io/like-1.9.2.rb 623 def sysread(length, buffer = nil) 624 buffer = buffer.nil? ? '' : buffer.to_str 625 buffer.slice!(0..-1) unless buffer.empty? 626 return buffer if length == 0 627 628 raise IOError, 'closed stream' if closed? 629 raise IOError, 'not opened for reading' unless readable? 630 631 # Flush the internal write buffer for writable, non-duplexed objects. 632 __io_like__buffered_flush if writable? && ! duplexed? 633 634 buffer << unbuffered_read(length) 635 end
A string argument is forced to ‘binary’ encoding and then passed on to unread.
The low byte of an integer argument is converted to a binary string and passed on to unread.
# File lib/io/like-1.9.2.rb 647 def ungetbyte(string) 648 raise IOError, 'closed stream' if closed? 649 raise IOError, 'not opened for reading' unless readable? 650 651 return nil if string.nil? 652 653 if Fixnum === string 654 int = string & 0xFF 655 __io_like__unread(int.chr(Encoding::BINARY)) 656 else 657 __io_like__unread(string.to_str) 658 end 659 nil 660 end
A string arguement is encoded to external_encoding
, then forced to ‘binary’ and passed to unread
An integer argument is treated as a codepoint in the internal_encoding
, converted to a character with external_encoding
, then forced to ‘binary’ and passed to unread. TODO: Raise doc bug against MRI as above behaviour is undocumented (although tested by rubyspec)
Raises IOError
if closed? returns true
. Raises IOError
unless readable? returns true
.
# File lib/io/like-1.9.2.rb 677 def ungetc(string) 678 raise IOError, 'closed stream' if closed? 679 raise IOError, 'not opened for reading' unless readable? 680 681 return nil if string.nil? 682 683 if string.respond_to?(:to_int) 684 #is expected to be a codepoint in the internal encoding 685 chr = string.to_int.chr(__io_like__internal_encoding) 686 __io_like__unread(chr.encode!(__io_like__external_encoding, __io_like__encoding_options)) 687 else 688 __io_like__unread(string.to_str.encode(__io_like__external_encoding, __io_like__encoding_options)) 689 end 690 nil 691 end
The argument is converted to a string with to_s
, converted to external_encoding
if not already ‘binary’, forced to ‘binary’ and then written to the stream. The number of bytes written is returned. TODO: rubyspec for encodings on write.
The entire contents of string are written, blocking as necessary even if the data stream does not block.
Raises IOError
if closed? returns true
. Raises IOError
unless writable? returns true
.
NOTE: This method ignores Errno::EAGAIN
and Errno::EINTR
raised by unbuffered_write. Therefore, this method always blocks if unable to immediately write string completely. Aside from that exception, this method will also raise the same errors and block at the same times as unbuffered_write.
# File lib/io/like-1.9.2.rb 713 def write(string) 714 super(__io_like__write_encode(string)) 715 end
The argument is converted to a string with to_s
, converted to external_encoding
if not already ‘binary’, forced to ‘binary’ and then written to the stream.
As many bytes as possible are written without blocking or SystemCallError from unbuffered_write is passed directly through to be handled by the caller.
Raises IOError
if closed? returns true
. Raises IOError
unless writable? returns true
. TODO: rubyspec to test raises IO::WaitWritable
.
# File lib/io/like-1.9.2.rb 731 def write_nonblock(string) 732 begin 733 super(__io_like__write_encode(string)) 734 rescue IO::WaitWritable 735 raise 736 rescue Errno::EAGAIN => ex 737 ex.extend(IO::WaitWritable) 738 raise ex 739 end 740 end
Private Instance Methods
reads length bytes from the stream and converts to characters in external_encoding
, ensuring that the last character is complete.
# File lib/io/like-1.9.2.rb 746 def __io_like__buffered_read_chars(length) 747 748 buffer = __io_like__buffered_read(length) 749 750 buffer.force_encoding(__io_like__external_encoding) 751 752 # read one byte at a time until the last character is valid (or EOF) 753 begin 754 until buffer[-1].valid_encoding? 755 buffer.force_encoding(Encoding::BINARY) 756 buffer << __io_like__buffered_read(1) 757 buffer.force_encoding(__io_like__external_encoding) 758 end 759 rescue EOFError 760 # return the invalid characters 761 rescue SystemCallError 762 # hmm, return the invalid encoded sequence, or raise the error? 763 raise 764 end 765 766 # Strictly buffer might now be longer than length bytes, but we cna't return 767 # a partial character and in the degenerate case where length=1, no multibyte 768 # character could ever be returned. 769 # MRI does not honour the length argument in these cases either 770 buffer.encode!(__io_like__internal_encoding, __io_like__encoding_options) 771 772 #TODO: Not sure why the buffer is not considered tainted when we read the whole file in at once 773 buffer.taint 774 end
lazy instantiation of encoding options
# File lib/io/like-1.9.2.rb 790 def __io_like__encoding_options 791 @encoding_options ||= {} 792 end
the real external encoding to use, if not set
# File lib/io/like-1.9.2.rb 795 def __io_like__external_encoding 796 external_encoding || Encoding::default_external 797 end
the real internal encoding to use, if not set
# File lib/io/like-1.9.2.rb 800 def __io_like__internal_encoding 801 internal_encoding || Encoding::default_internal || __io_like__external_encoding 802 end
Returns a reference to the internal read buffer which is always a binary encoded string.
# File lib/io/like-1.9.2.rb 806 def __io_like__internal_read_buffer 807 @__io_like__read_buffer ||= String.new('').force_encoding(Encoding::BINARY) 808 end
Returns a reference to the internal write buffer which is always a binary encoded string.
# File lib/io/like-1.9.2.rb 812 def __io_like__internal_write_buffer 813 @__io_like__write_buffer ||= String.new('').force_encoding(Encoding::BINARY) 814 end
force string to binary and insert back into the read buffer TODO: Find out why unread is not a private method for IO::Like
# File lib/io/like-1.9.2.rb 778 def __io_like__unread(string) 779 enc = string.encoding 780 string.force_encoding(Encoding::BINARY) 781 begin 782 __io_like__internal_read_buffer.insert(0, string) 783 ensure 784 string.force_encoding(enc) 785 end 786 nil 787 end
Encode a string for writing to the stream, ie convert to external_encoding
unless it is already ‘binary’
# File lib/io/like-1.9.2.rb 818 def __io_like__write_encode(string) 819 string = string.to_s 820 unless string.encoding == Encoding::BINARY 821 string.encode(__io_like__external_encoding, __io_like__encoding_options) 822 else 823 string 824 end 825 end