io-like 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/NEWS +11 -0
- data/README +15 -1
- data/lib/io/like.rb +155 -105
- metadata +2 -2
data/NEWS
CHANGED
@@ -6,6 +6,17 @@ detailed information is available in the rest of the documentation.
|
|
6
6
|
<b>NOTE:</b> Date stamps in the following entries are in YYYY/MM/DD format.
|
7
7
|
|
8
8
|
|
9
|
+
== v0.3.0 (2009/04/29)
|
10
|
+
|
11
|
+
* Fixed the rewind method to work with write-only streams
|
12
|
+
* Fixed the read, gets, and readline methods to return partial data if they have
|
13
|
+
such data but receive low level errors before reaching a stopping point
|
14
|
+
* Renamed all private methods so that it is highly unlikely that they will be
|
15
|
+
accidentally overridden.
|
16
|
+
* Eliminated warnings caused by referencing uninitialized instance variables
|
17
|
+
* Improved the documentation for the read, gets, and readline methods
|
18
|
+
|
19
|
+
|
9
20
|
== v0.2.0 (2009/03/11)
|
10
21
|
|
11
22
|
* Added mspec tests borrowed from the rubyspec project
|
data/README
CHANGED
@@ -78,7 +78,7 @@ A simple ROT13 codec:
|
|
78
78
|
encode_rot13(@delegate_io.sysread(length))
|
79
79
|
end
|
80
80
|
|
81
|
-
def unbuffered_seek(offset, whence = IO::
|
81
|
+
def unbuffered_seek(offset, whence = IO::SEEK_SET)
|
82
82
|
@delegate_io.sysseek(offset, whence)
|
83
83
|
end
|
84
84
|
|
@@ -109,6 +109,20 @@ A simple ROT13 codec:
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
+
File.open('normal_file.txt') do |f|
|
113
|
+
ROT13Filter.open(f) do |rot13|
|
114
|
+
rot13.pos = 5
|
115
|
+
puts(rot13.read) # -> vf n grfg
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
File.open('rot13_file.txt') do |f|
|
120
|
+
ROT13Filter.open(f) do |rot13|
|
121
|
+
rot13.pos = 5
|
122
|
+
puts(rot13.read) # -> is a test
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
112
126
|
File.open('normal_file.txt') do |f|
|
113
127
|
ROT13Filter.open(f) do |rot13|
|
114
128
|
ROT13Filter.open(rot13) do |rot26| # ;-)
|
data/lib/io/like.rb
CHANGED
@@ -29,9 +29,10 @@ class IO # :nodoc:
|
|
29
29
|
# ...
|
30
30
|
# end
|
31
31
|
#
|
32
|
-
# This method must return the number of bytes written to the stream
|
33
|
-
#
|
34
|
-
#
|
32
|
+
# This method must either return the number of bytes written to the stream,
|
33
|
+
# which may be less than the length of _string_ in bytes, OR must raise an
|
34
|
+
# instance of SystemCallError. Errno::EAGAIN should be raised if no data can
|
35
|
+
# be written immediately and the write operation should not block.
|
35
36
|
# Errno::EINTR should be raised if the write operation is interrupted before
|
36
37
|
# any data is written.
|
37
38
|
#
|
@@ -100,9 +101,9 @@ class IO # :nodoc:
|
|
100
101
|
# returns +true+ and then sets a flag so that #closed? will return +true+.
|
101
102
|
def close
|
102
103
|
raise IOError, 'closed stream' if closed?
|
103
|
-
|
104
|
+
__io_like__close_read
|
104
105
|
flush if writable?
|
105
|
-
|
106
|
+
__io_like__close_write
|
106
107
|
nil
|
107
108
|
end
|
108
109
|
|
@@ -117,11 +118,11 @@ class IO # :nodoc:
|
|
117
118
|
# if #writable? returns +true+.
|
118
119
|
def close_read
|
119
120
|
raise IOError, 'closed stream' if closed?
|
120
|
-
if
|
121
|
+
if __io_like__closed_read? || ! duplexed? && writable? then
|
121
122
|
raise IOError, 'closing non-duplex IO for reading'
|
122
123
|
end
|
123
124
|
if duplexed? then
|
124
|
-
|
125
|
+
__io_like__close_read
|
125
126
|
else
|
126
127
|
close
|
127
128
|
end
|
@@ -139,12 +140,12 @@ class IO # :nodoc:
|
|
139
140
|
# if #readable? returns +true+.
|
140
141
|
def close_write
|
141
142
|
raise IOError, 'closed stream' if closed?
|
142
|
-
if
|
143
|
+
if __io_like__closed_write? || ! duplexed? && readable? then
|
143
144
|
raise IOError, 'closing non-duplex IO for reading'
|
144
145
|
end
|
145
146
|
if duplexed? then
|
146
147
|
flush
|
147
|
-
|
148
|
+
__io_like__close_write
|
148
149
|
else
|
149
150
|
close
|
150
151
|
end
|
@@ -157,8 +158,8 @@ class IO # :nodoc:
|
|
157
158
|
# Returns +true+ if this object is closed or otherwise unusable for read and
|
158
159
|
# write operations.
|
159
160
|
def closed?
|
160
|
-
(
|
161
|
-
(
|
161
|
+
(__io_like__closed_read? || ! readable?) &&
|
162
|
+
(__io_like__closed_write? || ! writable?)
|
162
163
|
end
|
163
164
|
|
164
165
|
# call-seq:
|
@@ -302,7 +303,7 @@ class IO # :nodoc:
|
|
302
303
|
# #unbuffered_write.
|
303
304
|
def flush
|
304
305
|
begin
|
305
|
-
|
306
|
+
__io_like__buffered_flush
|
306
307
|
rescue Errno::EAGAIN, Errno::EINTR
|
307
308
|
retry if write_ready?
|
308
309
|
end
|
@@ -370,8 +371,11 @@ class IO # :nodoc:
|
|
370
371
|
#
|
371
372
|
# Calls #readline with _sep_string_ as an argument and either returns the
|
372
373
|
# result or +nil+ if #readline raises EOFError. If #readline returns some
|
373
|
-
# data,
|
374
|
-
#
|
374
|
+
# data, <tt>$.</tt> is set to the value of #lineno.
|
375
|
+
#
|
376
|
+
# <b>NOTE:</b> Due to limitations of MRI up to version 1.9.x when running
|
377
|
+
# managed (Ruby) code, this method fails to set <tt>$_</tt> to the returned
|
378
|
+
# data; however, other implementations may allow it.
|
375
379
|
#
|
376
380
|
# Raises IOError if #closed? returns +true+. Raises IOError unless
|
377
381
|
# #readable? returns +true+. Raises all errors raised by #unbuffered_read
|
@@ -379,9 +383,9 @@ class IO # :nodoc:
|
|
379
383
|
#
|
380
384
|
# <b>NOTE:</b> When _sep_string_ is not +nil+, this method ignores
|
381
385
|
# Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore,
|
382
|
-
# this method always
|
383
|
-
#
|
384
|
-
#
|
386
|
+
# this method will always block in that case. Aside from that exception,
|
387
|
+
# this method will raise the same errors and block at the same times as
|
388
|
+
# #unbuffered_read.
|
385
389
|
def gets(sep_string = $/)
|
386
390
|
# Set the last read line in the global.
|
387
391
|
$_ = readline(sep_string)
|
@@ -484,8 +488,8 @@ class IO # :nodoc:
|
|
484
488
|
# also raise the same errors and block at the same times as those functions.
|
485
489
|
def pos
|
486
490
|
# Flush the internal write buffer for writable, non-duplexed objects.
|
487
|
-
|
488
|
-
|
491
|
+
__io_like__buffered_flush if writable? && ! duplexed?
|
492
|
+
__io_like__buffered_seek(0, IO::SEEK_CUR)
|
489
493
|
end
|
490
494
|
alias :tell :pos
|
491
495
|
|
@@ -616,7 +620,7 @@ class IO # :nodoc:
|
|
616
620
|
line = arg.nil? ?
|
617
621
|
'nil' :
|
618
622
|
arg.kind_of?(Array) ?
|
619
|
-
|
623
|
+
__io_like__array_join(arg, ors) :
|
620
624
|
arg.to_s
|
621
625
|
line += ors if line.index(ors, -ors.length).nil?
|
622
626
|
write(line)
|
@@ -633,8 +637,10 @@ class IO # :nodoc:
|
|
633
637
|
# left to fulfill the request. If the read starts at the end of data, +nil+
|
634
638
|
# is returned.
|
635
639
|
#
|
636
|
-
# If _length_ is unspecified or +nil+,
|
637
|
-
#
|
640
|
+
# If _length_ is unspecified or +nil+, an attempt to return all remaining
|
641
|
+
# data is made. Partial data will be returned if a low-level error is
|
642
|
+
# raised after some data is retrieved. If no data would be returned at all,
|
643
|
+
# an empty String is returned.
|
638
644
|
#
|
639
645
|
# If _buffer_ is specified, it will be converted to a String using its
|
640
646
|
# +to_str+ method if necessary and will be filled with the returned data if
|
@@ -657,15 +663,18 @@ class IO # :nodoc:
|
|
657
663
|
# Read and return everything.
|
658
664
|
begin
|
659
665
|
loop do
|
660
|
-
buffer <<
|
666
|
+
buffer << __io_like__buffered_read(4096)
|
661
667
|
end
|
662
668
|
rescue EOFError
|
663
669
|
# Ignore this.
|
670
|
+
rescue SystemCallError
|
671
|
+
# Reraise the error if there is nothing to return.
|
672
|
+
raise if buffer.empty?
|
664
673
|
end
|
665
674
|
else
|
666
675
|
# Read and return up to length bytes.
|
667
676
|
begin
|
668
|
-
buffer <<
|
677
|
+
buffer << __io_like__buffered_read(length)
|
669
678
|
rescue EOFError
|
670
679
|
# Return nil to the caller at end of file when requesting a specific
|
671
680
|
# amount of data.
|
@@ -706,7 +715,7 @@ class IO # :nodoc:
|
|
706
715
|
# provides the #unbuffered_read method but may not always be open in a
|
707
716
|
# readable mode.
|
708
717
|
def readable?
|
709
|
-
!
|
718
|
+
! __io_like__closed_read? && respond_to?(:unbuffered_read, true)
|
710
719
|
end
|
711
720
|
|
712
721
|
# call-seq:
|
@@ -751,7 +760,7 @@ class IO # :nodoc:
|
|
751
760
|
# exception, this method will also raise the same errors and block at the
|
752
761
|
# same times as #unbuffered_read.
|
753
762
|
def readchar
|
754
|
-
|
763
|
+
__io_like__buffered_read(1)[0]
|
755
764
|
rescue Errno::EAGAIN, Errno::EINTR
|
756
765
|
retry if read_ready?
|
757
766
|
end
|
@@ -760,14 +769,27 @@ class IO # :nodoc:
|
|
760
769
|
# ios.readline(sep_string = $/) -> string
|
761
770
|
#
|
762
771
|
# Returns the next line from the stream, where lines are separated by
|
763
|
-
# _sep_string_. Increments #lineno
|
772
|
+
# _sep_string_. Increments #lineno by <tt>1</tt> for each call regardless
|
773
|
+
# of the value of _sep_string_.
|
774
|
+
#
|
775
|
+
# If _sep_string_ is not +nil+ and not a String, it is first converted to a
|
776
|
+
# String using its +to_str+ method and processing continues as follows.
|
764
777
|
#
|
765
778
|
# If _sep_string_ is +nil+, a line is defined as the remaining contents of
|
766
|
-
# the stream.
|
767
|
-
#
|
768
|
-
#
|
769
|
-
#
|
770
|
-
#
|
779
|
+
# the stream. Partial data will be returned if a low-level error of any
|
780
|
+
# kind is raised after some data is retrieved. This is equivalent to
|
781
|
+
# calling #read without any arguments except that this method will raise an
|
782
|
+
# EOFError if called at the end of the stream.
|
783
|
+
#
|
784
|
+
# If _sep_string_ is an empty String, a paragraph is returned, where a
|
785
|
+
# paragraph is defined as data followed by 2 or more successive newline
|
786
|
+
# characters. A maximum of 2 newlines are returned at the end of the
|
787
|
+
# returned data. Fewer may be returned if the stream ends before at least 2
|
788
|
+
# successive newlines are seen.
|
789
|
+
#
|
790
|
+
# Any other value for _sep_string_ is used as a delimiter to mark the end of
|
791
|
+
# a line. The returned data includes this delimiter unless the stream ends
|
792
|
+
# before the delimiter is seen.
|
771
793
|
#
|
772
794
|
# In any case, the end of the stream terminates the current line.
|
773
795
|
#
|
@@ -777,8 +799,8 @@ class IO # :nodoc:
|
|
777
799
|
#
|
778
800
|
# <b>NOTE:</b> When _sep_string_ is not +nil+, this method ignores
|
779
801
|
# Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore,
|
780
|
-
# this method always
|
781
|
-
#
|
802
|
+
# this method will always block in that case. Aside from that exception,
|
803
|
+
# this method will raise the same errors and block at the same times as
|
782
804
|
# #unbuffered_read.
|
783
805
|
def readline(sep_string = $/)
|
784
806
|
# Ensure that sep_string is either nil or a String.
|
@@ -792,7 +814,7 @@ class IO # :nodoc:
|
|
792
814
|
# A nil line separator means that the user wants to capture all the
|
793
815
|
# remaining input.
|
794
816
|
loop do
|
795
|
-
buffer <<
|
817
|
+
buffer << __io_like__buffered_read(4096)
|
796
818
|
end
|
797
819
|
else
|
798
820
|
begin
|
@@ -806,7 +828,7 @@ class IO # :nodoc:
|
|
806
828
|
# Add each character from the input to the buffer until either the
|
807
829
|
# buffer has the right ending or the end of the input is reached.
|
808
830
|
while buffer.index(sep_string, -sep_string.length).nil? &&
|
809
|
-
(char =
|
831
|
+
(char = __io_like__buffered_read(1)) do
|
810
832
|
buffer << char
|
811
833
|
end
|
812
834
|
|
@@ -814,7 +836,7 @@ class IO # :nodoc:
|
|
814
836
|
# If the user requested paragraphs instead of lines, we need to
|
815
837
|
# consume and discard all newlines remaining at the front of the
|
816
838
|
# input.
|
817
|
-
while char == "\n" && (char =
|
839
|
+
while char == "\n" && (char = __io_like__buffered_read(1)) do
|
818
840
|
nil
|
819
841
|
end
|
820
842
|
# Put back the last character.
|
@@ -824,7 +846,8 @@ class IO # :nodoc:
|
|
824
846
|
retry if read_ready?
|
825
847
|
end
|
826
848
|
end
|
827
|
-
rescue EOFError
|
849
|
+
rescue EOFError, SystemCallError
|
850
|
+
# Reraise the error if there is nothing to return.
|
828
851
|
raise if buffer.empty?
|
829
852
|
end
|
830
853
|
# Increment the number of times this method has returned a "line".
|
@@ -889,9 +912,9 @@ class IO # :nodoc:
|
|
889
912
|
buffer.slice!(0..-1)
|
890
913
|
|
891
914
|
# Read and return up to length bytes.
|
892
|
-
if
|
915
|
+
if __io_like__internal_read_buffer.empty? then
|
893
916
|
begin
|
894
|
-
buffer <<
|
917
|
+
buffer << __io_like__buffered_read(length)
|
895
918
|
rescue Errno::EAGAIN, Errno::EINTR
|
896
919
|
retry if read_ready?
|
897
920
|
end
|
@@ -899,7 +922,7 @@ class IO # :nodoc:
|
|
899
922
|
raise IOError, 'closed stream' if closed?
|
900
923
|
raise IOError, 'not opened for reading' unless readable?
|
901
924
|
|
902
|
-
buffer <<
|
925
|
+
buffer << __io_like__internal_read_buffer.slice!(0, length)
|
903
926
|
end
|
904
927
|
buffer
|
905
928
|
end
|
@@ -909,7 +932,7 @@ class IO # :nodoc:
|
|
909
932
|
#
|
910
933
|
# Sets the position of the file pointer to the beginning of the stream and
|
911
934
|
# returns 0 when complete. The lineno attribute is reset to 0 if
|
912
|
-
# successful
|
935
|
+
# successful and the stream is readable according to #readable?.
|
913
936
|
#
|
914
937
|
# As a side effect, the internal read and write buffers are flushed.
|
915
938
|
#
|
@@ -921,7 +944,8 @@ class IO # :nodoc:
|
|
921
944
|
# also raise the same errors and block at the same times as those functions.
|
922
945
|
def rewind
|
923
946
|
seek(0, IO::SEEK_SET)
|
924
|
-
self.lineno = 0
|
947
|
+
self.lineno = 0 if readable?
|
948
|
+
0
|
925
949
|
end
|
926
950
|
|
927
951
|
# call-seq:
|
@@ -944,7 +968,7 @@ class IO # :nodoc:
|
|
944
968
|
# #unbuffered_write (when the internal write buffer is not empty), it will
|
945
969
|
# also raise the same errors and block at the same times as those functions.
|
946
970
|
def seek(offset, whence = IO::SEEK_SET)
|
947
|
-
|
971
|
+
__io_like__buffered_seek(offset, whence)
|
948
972
|
0
|
949
973
|
end
|
950
974
|
|
@@ -1009,12 +1033,12 @@ class IO # :nodoc:
|
|
1009
1033
|
|
1010
1034
|
raise IOError, 'closed stream' if closed?
|
1011
1035
|
raise IOError, 'not opened for reading' unless readable?
|
1012
|
-
unless
|
1036
|
+
unless __io_like__internal_read_buffer.empty? then
|
1013
1037
|
raise IOError, 'sysread on buffered IO'
|
1014
1038
|
end
|
1015
1039
|
|
1016
1040
|
# Flush the internal write buffer for writable, non-duplexed objects.
|
1017
|
-
|
1041
|
+
__io_like__buffered_flush if writable? && ! duplexed?
|
1018
1042
|
|
1019
1043
|
buffer << unbuffered_read(length)
|
1020
1044
|
end
|
@@ -1036,9 +1060,11 @@ class IO # :nodoc:
|
|
1036
1060
|
# raise the same errors and block at the same times as that function.
|
1037
1061
|
def sysseek(offset, whence = IO::SEEK_SET)
|
1038
1062
|
raise IOError, 'closed stream' if closed?
|
1039
|
-
raise Errno::ESPIPE
|
1040
|
-
|
1041
|
-
|
1063
|
+
raise Errno::ESPIPE unless seekable?
|
1064
|
+
unless __io_like__internal_read_buffer.empty? then
|
1065
|
+
raise IOError, 'sysseek on buffered IO'
|
1066
|
+
end
|
1067
|
+
unless __io_like__internal_write_buffer.empty? then
|
1042
1068
|
warn('warning: sysseek on buffered IO')
|
1043
1069
|
end
|
1044
1070
|
|
@@ -1062,15 +1088,15 @@ class IO # :nodoc:
|
|
1062
1088
|
def syswrite(string)
|
1063
1089
|
raise IOError, 'closed stream' if closed?
|
1064
1090
|
raise IOError, 'not opened for writing' unless writable?
|
1065
|
-
unless
|
1091
|
+
unless __io_like__internal_write_buffer.empty? then
|
1066
1092
|
warn('warning: syswrite on buffered IO')
|
1067
1093
|
end
|
1068
1094
|
|
1069
1095
|
# Flush the internal read buffer and set the unbuffered position to the
|
1070
1096
|
# buffered position when dealing with non-duplexed objects.
|
1071
|
-
unless duplexed? ||
|
1072
|
-
unbuffered_seek(-
|
1073
|
-
|
1097
|
+
unless duplexed? || __io_like__internal_read_buffer.empty? then
|
1098
|
+
unbuffered_seek(-__io_like__internal_read_buffer.length, IO::SEEK_CUR)
|
1099
|
+
__io_like__internal_read_buffer.slice!(0..-1)
|
1074
1100
|
end
|
1075
1101
|
|
1076
1102
|
unbuffered_write(string)
|
@@ -1107,7 +1133,7 @@ class IO # :nodoc:
|
|
1107
1133
|
def unread(string)
|
1108
1134
|
raise IOError, 'closed stream' if closed?
|
1109
1135
|
raise IOError, 'not opened for reading' unless readable?
|
1110
|
-
|
1136
|
+
__io_like__internal_read_buffer.insert(0, string.to_s)
|
1111
1137
|
nil
|
1112
1138
|
end
|
1113
1139
|
|
@@ -1142,7 +1168,7 @@ class IO # :nodoc:
|
|
1142
1168
|
# provides the #unbuffered_write method but may not always be open in a
|
1143
1169
|
# writable mode.
|
1144
1170
|
def writable?
|
1145
|
-
!
|
1171
|
+
! __io_like__closed_write? && respond_to?(:unbuffered_write, true)
|
1146
1172
|
end
|
1147
1173
|
|
1148
1174
|
# call-seq:
|
@@ -1168,7 +1194,8 @@ class IO # :nodoc:
|
|
1168
1194
|
bytes_written = 0
|
1169
1195
|
while bytes_written < string.length do
|
1170
1196
|
begin
|
1171
|
-
bytes_written +=
|
1197
|
+
bytes_written +=
|
1198
|
+
__io_like__buffered_write(string.to_s.slice(bytes_written..-1))
|
1172
1199
|
rescue Errno::EAGAIN, Errno::EINTR
|
1173
1200
|
retry if write_ready?
|
1174
1201
|
end
|
@@ -1179,7 +1206,7 @@ class IO # :nodoc:
|
|
1179
1206
|
private
|
1180
1207
|
|
1181
1208
|
# call-seq:
|
1182
|
-
# ios.
|
1209
|
+
# ios.__io_like__buffered_flush -> 0
|
1183
1210
|
#
|
1184
1211
|
# Attempts to completely flush the internal write buffer to the data stream.
|
1185
1212
|
#
|
@@ -1188,18 +1215,20 @@ class IO # :nodoc:
|
|
1188
1215
|
# <b>NOTE:</b> Because this method relies on #unbuffered_write, it raises
|
1189
1216
|
# all errors raised by #unbuffered_write and blocks when #unbuffered_write
|
1190
1217
|
# blocks.
|
1191
|
-
def
|
1218
|
+
def __io_like__buffered_flush
|
1192
1219
|
raise IOError, 'closed stream' if closed?
|
1193
1220
|
raise IOError, 'not opened for writing' unless writable?
|
1194
1221
|
|
1195
|
-
until
|
1196
|
-
|
1222
|
+
until __io_like__internal_write_buffer.empty? do
|
1223
|
+
__io_like__internal_write_buffer.slice!(
|
1224
|
+
0, unbuffered_write(__io_like__internal_write_buffer)
|
1225
|
+
)
|
1197
1226
|
end
|
1198
1227
|
0
|
1199
1228
|
end
|
1200
1229
|
|
1201
1230
|
# call-seq:
|
1202
|
-
# ios.
|
1231
|
+
# ios.__io_like__buffered_read(length) -> string
|
1203
1232
|
#
|
1204
1233
|
# Reads at most _length_ bytes first from an internal read buffer followed
|
1205
1234
|
# by the underlying stream if necessary and returns the resulting buffer.
|
@@ -1210,7 +1239,7 @@ class IO # :nodoc:
|
|
1210
1239
|
# <b>NOTE:</b> Because this method relies on #unbuffered_read, it raises all
|
1211
1240
|
# errors raised by #unbuffered_read and blocks when #unbuffered_read blocks
|
1212
1241
|
# whenever the internal read buffer is unable to fulfill the request.
|
1213
|
-
def
|
1242
|
+
def __io_like__buffered_read(length)
|
1214
1243
|
# Check the validity of the method arguments.
|
1215
1244
|
raise ArgumentError, "non-positive length #{length} given" if length < 0
|
1216
1245
|
|
@@ -1218,30 +1247,30 @@ class IO # :nodoc:
|
|
1218
1247
|
raise IOError, 'not opened for reading' unless readable?
|
1219
1248
|
|
1220
1249
|
# Flush the internal write buffer for writable, non-duplexed objects.
|
1221
|
-
|
1250
|
+
__io_like__buffered_flush if writable? && ! duplexed?
|
1222
1251
|
|
1223
1252
|
# Ensure that the internal read buffer has at least enough data to satisfy
|
1224
1253
|
# the request.
|
1225
|
-
if
|
1226
|
-
unbuffered_length = length -
|
1254
|
+
if __io_like__internal_read_buffer.length < length then
|
1255
|
+
unbuffered_length = length - __io_like__internal_read_buffer.length
|
1227
1256
|
unbuffered_length = fill_size if unbuffered_length < fill_size
|
1228
1257
|
|
1229
1258
|
begin
|
1230
|
-
|
1259
|
+
__io_like__internal_read_buffer << unbuffered_read(unbuffered_length)
|
1231
1260
|
rescue EOFError, SystemCallError
|
1232
1261
|
# Reraise the error if there is no data to return.
|
1233
|
-
raise if
|
1262
|
+
raise if __io_like__internal_read_buffer.empty?
|
1234
1263
|
end
|
1235
1264
|
end
|
1236
1265
|
|
1237
1266
|
# Read from the internal read buffer.
|
1238
|
-
buffer =
|
1267
|
+
buffer = __io_like__internal_read_buffer.slice!(0, length)
|
1239
1268
|
|
1240
1269
|
buffer
|
1241
1270
|
end
|
1242
1271
|
|
1243
1272
|
# call-seq:
|
1244
|
-
# ios.
|
1273
|
+
# ios.__io_like__buffered_seek(offset[, whence]) -> integer
|
1245
1274
|
#
|
1246
1275
|
# Sets the current data position to _offset_ based on the setting of
|
1247
1276
|
# _whence_. If _whence_ is unspecified or IO::SEEK_SET, _offset_ counts
|
@@ -1260,37 +1289,40 @@ class IO # :nodoc:
|
|
1260
1289
|
# <b>NOTE:</b> Because this method relies on #unbuffered_seek and
|
1261
1290
|
# #unbuffered_write (when the internal write buffer is not empty), it will
|
1262
1291
|
# raise the same errors and block at the same times as those functions.
|
1263
|
-
def
|
1292
|
+
def __io_like__buffered_seek(offset, whence = IO::SEEK_SET)
|
1264
1293
|
raise IOError, 'closed stream' if closed?
|
1265
|
-
raise Errno::ESPIPE
|
1294
|
+
raise Errno::ESPIPE unless seekable?
|
1266
1295
|
|
1267
1296
|
if whence == IO::SEEK_CUR && offset == 0 then
|
1268
1297
|
# The seek is only determining the current position, so return the
|
1269
1298
|
# buffered position based on the read buffer if it's not empty and the
|
1270
1299
|
# write buffer otherwise.
|
1271
|
-
|
1272
|
-
unbuffered_seek(0, IO::SEEK_CUR) +
|
1273
|
-
|
1300
|
+
__io_like__internal_read_buffer.empty? ?
|
1301
|
+
unbuffered_seek(0, IO::SEEK_CUR) +
|
1302
|
+
__io_like__internal_write_buffer.length :
|
1303
|
+
unbuffered_seek(0, IO::SEEK_CUR) -
|
1304
|
+
__io_like__internal_read_buffer.length
|
1274
1305
|
elsif whence == IO::SEEK_CUR && offset > 0 &&
|
1275
|
-
|
1276
|
-
offset <=
|
1306
|
+
__io_like__internal_write_buffer.empty? &&
|
1307
|
+
offset <= __io_like__internal_read_buffer.length then
|
1277
1308
|
# The seek is within the read buffer, so just discard a sufficient
|
1278
1309
|
# amount of the buffer and report the new buffered position.
|
1279
|
-
|
1280
|
-
unbuffered_seek(0, IO::SEEK_CUR) -
|
1310
|
+
__io_like__internal_read_buffer.slice!(0, offset)
|
1311
|
+
unbuffered_seek(0, IO::SEEK_CUR) -
|
1312
|
+
__io_like__internal_read_buffer.length
|
1281
1313
|
else
|
1282
1314
|
# The seek target is outside of the buffers, so flush the buffers and
|
1283
1315
|
# jump to the new position.
|
1284
1316
|
if whence == IO::SEEK_CUR then
|
1285
1317
|
# Adjust relative offsets based on the current buffered offset.
|
1286
|
-
offset +=
|
1287
|
-
|
1288
|
-
-
|
1318
|
+
offset += __io_like__internal_read_buffer.empty? ?
|
1319
|
+
__io_like__internal_write_buffer.length :
|
1320
|
+
-__io_like__internal_read_buffer.length
|
1289
1321
|
end
|
1290
1322
|
|
1291
1323
|
# Flush the internal buffers.
|
1292
|
-
|
1293
|
-
|
1324
|
+
__io_like__internal_read_buffer.slice!(0..-1)
|
1325
|
+
__io_like__buffered_flush if writable?
|
1294
1326
|
|
1295
1327
|
# Move the data stream's position as requested.
|
1296
1328
|
unbuffered_seek(offset, whence)
|
@@ -1298,7 +1330,7 @@ class IO # :nodoc:
|
|
1298
1330
|
end
|
1299
1331
|
|
1300
1332
|
# call-seq:
|
1301
|
-
# ios.
|
1333
|
+
# ios.__io_like__buffered_write(string) -> integer
|
1302
1334
|
#
|
1303
1335
|
# Writes _string_ to the internal write buffer and returns the number of
|
1304
1336
|
# bytes written. If the internal write buffer is overfilled by _string_, it
|
@@ -1311,51 +1343,72 @@ class IO # :nodoc:
|
|
1311
1343
|
# all errors raised by #unbuffered_write and blocks when #unbuffered_write
|
1312
1344
|
# blocks whenever the internal write buffer is unable to fulfill the
|
1313
1345
|
# request.
|
1314
|
-
def
|
1346
|
+
def __io_like__buffered_write(string)
|
1315
1347
|
raise IOError, 'closed stream' if closed?
|
1316
1348
|
raise IOError, 'not opened for writing' unless writable?
|
1317
1349
|
|
1318
1350
|
# Flush the internal read buffer and set the unbuffered position to the
|
1319
1351
|
# buffered position when dealing with non-duplexed objects.
|
1320
|
-
unless duplexed? ||
|
1321
|
-
unbuffered_seek(-
|
1322
|
-
|
1352
|
+
unless duplexed? || __io_like__internal_read_buffer.empty? then
|
1353
|
+
unbuffered_seek(-__io_like__internal_read_buffer.length, IO::SEEK_CUR)
|
1354
|
+
__io_like__internal_read_buffer.slice!(0..-1)
|
1323
1355
|
end
|
1324
1356
|
|
1325
1357
|
bytes_written = 0
|
1326
1358
|
if sync then
|
1327
1359
|
# Flush the internal write buffer and then bypass it when in synchronous
|
1328
1360
|
# mode.
|
1329
|
-
|
1361
|
+
__io_like__buffered_flush
|
1330
1362
|
bytes_written = unbuffered_write(string)
|
1331
1363
|
else
|
1332
|
-
if
|
1364
|
+
if __io_like__internal_write_buffer.length + string.length >= flush_size then
|
1333
1365
|
# The tipping point for the write buffer would be surpassed by this
|
1334
1366
|
# request, so flush everything.
|
1335
|
-
|
1367
|
+
__io_like__buffered_flush
|
1336
1368
|
bytes_written = unbuffered_write(string)
|
1337
1369
|
else
|
1338
1370
|
# The buffer can absorb the entire request.
|
1339
|
-
|
1371
|
+
__io_like__internal_write_buffer << string
|
1340
1372
|
bytes_written = string.length
|
1341
1373
|
end
|
1342
1374
|
end
|
1343
|
-
rescue SystemCallError
|
1344
|
-
raise if bytes_written == 0
|
1345
|
-
else
|
1346
1375
|
return bytes_written
|
1347
1376
|
end
|
1348
1377
|
|
1349
1378
|
# Returns a reference to the internal read buffer.
|
1350
|
-
def
|
1379
|
+
def __io_like__internal_read_buffer
|
1351
1380
|
@__io_like__read_buffer ||= ''
|
1352
1381
|
end
|
1353
1382
|
|
1354
1383
|
# Returns a reference to the internal write buffer.
|
1355
|
-
def
|
1384
|
+
def __io_like__internal_write_buffer
|
1356
1385
|
@__io_like__write_buffer ||= ''
|
1357
1386
|
end
|
1358
1387
|
|
1388
|
+
# Returns +true+ if this object has been closed for reading; otherwise,
|
1389
|
+
# returns +false+.
|
1390
|
+
def __io_like__closed_read?
|
1391
|
+
@__io_like__closed_read ||= false
|
1392
|
+
end
|
1393
|
+
|
1394
|
+
# Arranges for #__io_like__closed_read? to return +true+.
|
1395
|
+
def __io_like__close_read
|
1396
|
+
@__io_like__closed_read = true
|
1397
|
+
nil
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
# Returns +true+ if this object has been closed for writing; otherwise,
|
1401
|
+
# returns +false+.
|
1402
|
+
def __io_like__closed_write?
|
1403
|
+
@__io_like__closed_write ||= false
|
1404
|
+
end
|
1405
|
+
|
1406
|
+
# Arranges for #__io_like__closed_write? to return +true+.
|
1407
|
+
def __io_like__close_write
|
1408
|
+
@__io_like__closed_write = true
|
1409
|
+
nil
|
1410
|
+
end
|
1411
|
+
|
1359
1412
|
# This method joins the elements of _array_ together with _separator_
|
1360
1413
|
# between each element and returns the result. _seen_ is a list of object
|
1361
1414
|
# IDs representing arrays which have already started processing.
|
@@ -1375,21 +1428,18 @@ class IO # :nodoc:
|
|
1375
1428
|
#
|
1376
1429
|
# Things get progressively worse as the nesting and recursion become more
|
1377
1430
|
# convoluted.
|
1378
|
-
def
|
1379
|
-
first = true
|
1431
|
+
def __io_like__array_join(array, separator, seen = [])
|
1380
1432
|
seen.push(array.object_id)
|
1433
|
+
need_separator = false
|
1381
1434
|
result = array.inject('') do |memo, item|
|
1382
|
-
if
|
1383
|
-
|
1384
|
-
else
|
1385
|
-
memo << separator
|
1386
|
-
end
|
1435
|
+
memo << separator if need_separator
|
1436
|
+
need_separator = true
|
1387
1437
|
|
1388
1438
|
memo << if item.kind_of?(Array) then
|
1389
1439
|
if seen.include?(item.object_id) then
|
1390
1440
|
'[...]'
|
1391
1441
|
else
|
1392
|
-
|
1442
|
+
__io_like__array_join(item, separator, seen)
|
1393
1443
|
end
|
1394
1444
|
else
|
1395
1445
|
item.to_s
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io-like
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Bopp
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-04-29 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|