io-like 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|