io-like 0.1.0 → 0.2.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.
@@ -6,6 +6,8 @@
6
6
 
7
7
  = Bug Fixes
8
8
 
9
+ * Jarred Holman <jarred.holman at gmail dot com>
10
+
9
11
 
10
12
  = Testers
11
13
 
data/HACKING CHANGED
@@ -17,8 +17,8 @@ some cases, but such cases will be rare.
17
17
  === Build
18
18
 
19
19
  * rubygems 0.9.0 or greater
20
- * rake 0.8.1
21
- * rubyforge 1.0.0 (optional - used for publishing releases)
20
+ * rake 0.8.3 or greater
21
+ * mspec 1.5.9 (optional - used for testing)
22
22
  * allison 2.0.3 (optional - used for documentation only, if available)
23
23
  * rsync (optional - used for publishing documentation)
24
24
 
data/LEGAL CHANGED
@@ -5,4 +5,52 @@
5
5
  The following file(s) are provided under a license or licenses separate from
6
6
  this project.
7
7
 
8
- None at present
8
+ See LICENSE.rubyspec for terms of use for the following:
9
+ spec/binmode_spec.rb
10
+ spec/close_read_spec.rb
11
+ spec/close_spec.rb
12
+ spec/close_write_spec.rb
13
+ spec/closed_spec.rb
14
+ spec/each_byte_spec.rb
15
+ spec/each_line_spec.rb
16
+ spec/each_spec.rb
17
+ spec/eof_spec.rb
18
+ spec/fixtures/classes.rb
19
+ spec/fixtures/gets.txt
20
+ spec/fixtures/numbered_lines.txt
21
+ spec/fixtures/one_byte.txt
22
+ spec/fixtures/paragraphs.txt
23
+ spec/fixtures/readlines.txt
24
+ spec/flush_spec.rb
25
+ spec/getc_spec.rb
26
+ spec/gets_spec.rb
27
+ spec/isatty_spec.rb
28
+ spec/lineno_spec.rb
29
+ spec/output_spec.rb
30
+ spec/pos_spec.rb
31
+ spec/print_spec.rb
32
+ spec/printf_spec.rb
33
+ spec/putc_spec.rb
34
+ spec/puts_spec.rb
35
+ spec/read_spec.rb
36
+ spec/readchar_spec.rb
37
+ spec/readline_spec.rb
38
+ spec/readlines_spec.rb
39
+ spec/readpartial_spec.rb
40
+ spec/rewind_spec.rb
41
+ spec/seek_spec.rb
42
+ spec/shared/each.rb
43
+ spec/shared/eof.rb
44
+ spec/shared/pos.rb
45
+ spec/shared/tty.rb
46
+ spec/shared/write.rb
47
+ spec/sync_spec.rb
48
+ spec/sysread_spec.rb
49
+ spec/sysseek_spec.rb
50
+ spec/syswrite_spec.rb
51
+ spec/tell_spec.rb
52
+ spec/to_io_spec.rb
53
+ spec/tty_spec.rb
54
+ spec/ungetc_spec.rb
55
+ spec/write_spec.rb
56
+ spec_helper.rb
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2008 Engine Yard, Inc. All rights reserved.
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/MANIFEST CHANGED
@@ -3,8 +3,8 @@ GPL
3
3
  HACKING
4
4
  LEGAL
5
5
  LICENSE
6
+ LICENSE.rubyspec
6
7
  MANIFEST
7
8
  NEWS
8
9
  README
9
10
  lib/io/like.rb
10
- test/lib/likestringio.rb
data/NEWS CHANGED
@@ -6,6 +6,13 @@ 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.2.0 (2009/03/11)
10
+
11
+ * Added mspec tests borrowed from the rubyspec project
12
+ * Fixed many, many defects related to IO compatibility (Mostly obscure corner
13
+ cases)
14
+
15
+
9
16
  == v0.1.0 (2008/07/03)
10
17
 
11
18
  * Initial release
data/README CHANGED
@@ -12,11 +12,14 @@ methods.
12
12
 
13
13
  == License
14
14
 
15
- Copyright © 2008 Jeremy Bopp <jeremy at bopp dot net>
15
+ Copyright © 2008,2009 Jeremy Bopp <jeremy at bopp dot net>
16
16
 
17
17
  Licensed under the same terms as Ruby -- See the included LICENSE file for
18
18
  details
19
19
 
20
+ Some parts licensed under the same terms as the rubyspec project -- See the
21
+ included LEGAL and LICENSE.rubyspec files for details
22
+
20
23
 
21
24
  == Installation/Removal
22
25
 
@@ -125,8 +128,6 @@ A simple ROT13 codec:
125
128
  collected. Define a class open method in the manner of File.open which
126
129
  guarantees that an appropriate close method will be called after executing a
127
130
  block. Other than that, be diligent about calling the close methods.
128
- 3. Testcases needed. Maybe use some of rubyspec along with some test classes
129
- act like the important parts of IO, File, and/or StringIO.
130
131
 
131
132
 
132
133
  == Contributing
@@ -100,77 +100,65 @@ class IO # :nodoc:
100
100
  # returns +true+ and then sets a flag so that #closed? will return +true+.
101
101
  def close
102
102
  raise IOError, 'closed stream' if closed?
103
- if duplexed? then
104
- close_read unless closed_read?
105
- close_write unless closed_write?
106
- else
107
- flush if writable?
108
- @__io_like__closed = true
109
- end
103
+ @__io_like__closed_read = true
104
+ flush if writable?
105
+ @__io_like__closed_write = true
110
106
  nil
111
107
  end
112
108
 
113
109
  # call-seq:
114
110
  # ios.close_read -> nil
115
111
  #
116
- # For duplexed objects, arranges for #closed_read? to return +true+.
112
+ # Closes the read end of a duplexed object or the whole object if the object
113
+ # is read-only.
117
114
  #
118
- # Raises IOError if #duplexed returns +false+. Raises IOError if
119
- # #closed_read? returns +true+.
115
+ # Raises IOError if #closed? returns +true+. Raises IOError for duplexed
116
+ # objects if called more than once. Raises IOError for non-duplexed objects
117
+ # if #writable? returns +true+.
120
118
  def close_read
121
- raise IOError, 'closed stream' if closed_read?
122
- raise IOError, 'closing non-duplex IO for reading' unless duplexed?
123
- @__io_like__closed_read = true
119
+ raise IOError, 'closed stream' if closed?
120
+ if @__io_like__closed_read || ! duplexed? && writable? then
121
+ raise IOError, 'closing non-duplex IO for reading'
122
+ end
123
+ if duplexed? then
124
+ @__io_like__closed_read = true
125
+ else
126
+ close
127
+ end
124
128
  nil
125
129
  end
126
130
 
127
131
  # call-seq:
128
132
  # ios.close_write -> nil
129
133
  #
130
- # For duplexed objects, calls #flush and arranges for #closed_write? to
131
- # return +true+.
134
+ # Closes the write end of a duplexed object or the whole object if the
135
+ # object is write-only.
132
136
  #
133
- # Raises IOError if #duplexed? returns +false+. Raises IOError if
134
- # #closed_write? returns +true+.
137
+ # Raises IOError if #closed? returns +true+. Raises IOError for duplexed
138
+ # objects if called more than once. Raises IOError for non-duplexed objects
139
+ # if #readable? returns +true+.
135
140
  def close_write
136
- raise IOError, 'closed stream' if closed_write?
137
- raise IOError, 'closing non-duplex IO for writing' unless duplexed?
138
- flush
139
- @__io_like__closed_write = true
141
+ raise IOError, 'closed stream' if closed?
142
+ if @__io_like__closed_write || ! duplexed? && readable? then
143
+ raise IOError, 'closing non-duplex IO for reading'
144
+ end
145
+ if duplexed? then
146
+ flush
147
+ @__io_like__closed_write = true
148
+ else
149
+ close
150
+ end
140
151
  nil
141
152
  end
142
153
 
143
154
  # call-seq:
144
155
  # ios.closed? -> true or false
145
156
  #
146
- # For non-duplexed objects, returns +true+ if #close was called, +false+
147
- # otherwise. For duplexed objects, returns +true+ if both #closed_read?
148
- # and #closed_write? return true.
157
+ # Returns +true+ if this object is closed or otherwise unusable for read and
158
+ # write operations.
149
159
  def closed?
150
- return closed_read? && closed_write? if duplexed?
151
- @__io_like__closed || false
152
- end
153
-
154
- # call-seq:
155
- # ios.closed_read? -> true or false
156
- #
157
- # Returns the result of calling #closed? for non-duplexed objects. For
158
- # duplexed objects, returns +true+ if close_read was called, +false+
159
- # otherwise.
160
- def closed_read?
161
- return closed? unless duplexed?
162
- @__io_like__closed_read || false
163
- end
164
-
165
- # call-seq:
166
- # ios.closed_write? -> true or false
167
- #
168
- # Returns the result of calling #closed? for non-duplexed objects. For
169
- # duplexed objects, returns +true+ if close_write was called, +false+
170
- # otherwise.
171
- def closed_write?
172
- return closed? unless duplexed?
173
- @__io_like__closed_read || false
160
+ (@__io_like__closed_read || ! readable?) &&
161
+ (@__io_like__closed_write || ! writable?)
174
162
  end
175
163
 
176
164
  # call-seq:
@@ -183,12 +171,12 @@ class IO # :nodoc:
183
171
  end
184
172
 
185
173
  # call-seq:
186
- # ios.each_byte {|byte| block} -> ios
174
+ # ios.each_byte { |byte| block } -> ios
187
175
  #
188
176
  # Reads each byte (0..255) from the stream using #getc and calls the given
189
177
  # block once for each byte, passing the byte as an argument.
190
178
  #
191
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
179
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
192
180
  # #unbuffered_read. Therefore, this method always blocks. Aside from that
193
181
  # exception and the conversion of EOFError results into +nil+ results, this
194
182
  # method will also raise the same errors and block at the same times as
@@ -201,17 +189,17 @@ class IO # :nodoc:
201
189
  end
202
190
 
203
191
  # call-seq:
204
- # ios.each_line(sep_string = $/) {|line| block } -> ios
205
- # ios.each(sep_string = $/) {|line| block } -> ios
192
+ # ios.each_line(sep_string = $/) { |line| block } -> ios
193
+ # ios.each(sep_string = $/) { |line| block } -> ios
206
194
  #
207
195
  # Reads each line from the stream using #gets and calls the given block once
208
196
  # for each line, passing the line as an argument.
209
197
  #
210
- # NOTE: When _sep_string_ is not +nil+, this method ignores Errno::EAGAIN
211
- # and Errno::EINTR raised by #unbuffered_read. Therefore, this method
212
- # always blocks. Aside from that exception and the conversion of EOFError
213
- # results into +nil+ results, this method will also raise the same errors
214
- # and block at the same times as #unbuffered_read.
198
+ # <b>NOTE:</b> When _sep_string_ is not +nil+, this method ignores
199
+ # Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore,
200
+ # this method always blocks. Aside from that exception and the conversion
201
+ # of EOFError results into +nil+ results, this method will also raise the
202
+ # same errors and block at the same times as #unbuffered_read.
215
203
  def each_line(sep_string = $/)
216
204
  while (line = gets(sep_string)) do
217
205
  yield(line)
@@ -230,7 +218,7 @@ class IO # :nodoc:
230
218
  # put the character back if one was fetched. It may be a good idea to
231
219
  # replace this implementation in derivative classes.
232
220
  #
233
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
221
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
234
222
  # #unbuffered_read. Therefore, this method always blocks. Aside from that
235
223
  # exception and the conversion of EOFError results into +nil+ results, this
236
224
  # method will also raise the same errors and block at the same times as
@@ -247,7 +235,7 @@ class IO # :nodoc:
247
235
  # call-seq:
248
236
  # ios.fcntl
249
237
  #
250
- # Raises NotImplementedError
238
+ # Raises NotImplementedError.
251
239
  def fcntl(*args)
252
240
  raise NotImplementedError, 'not implemented'
253
241
  end
@@ -267,10 +255,10 @@ class IO # :nodoc:
267
255
  # buffer needs to be refilled. Unless set explicitly via #fill_size=, this
268
256
  # defaults to 4096.
269
257
  #
270
- # Raises IOError if #closed_read? returns +true+. Raises IOError if the
258
+ # Raises IOError if #closed? returns +true+. Raises IOError if the
271
259
  # stream is not opened for reading.
272
260
  def fill_size
273
- raise IOError, 'closed stream' if closed_read?
261
+ raise IOError, 'closed stream' if closed?
274
262
  raise IOError, 'not opened for reading' unless readable?
275
263
 
276
264
  @__io_like__fill_size ||= 4096
@@ -283,10 +271,10 @@ class IO # :nodoc:
283
271
  # buffer needs to be refilled. The new value must be a number greater than
284
272
  # or equal to 0. Setting this to 0 effectively disables buffering.
285
273
  #
286
- # Raises IOError if #closed_read? returns +true+. Raises IOError if the
274
+ # Raises IOError if #closed? returns +true+. Raises IOError if the
287
275
  # stream is not opened for reading.
288
276
  def fill_size=(fill_size)
289
- raise IOError, 'closed stream' if closed_read?
277
+ raise IOError, 'closed stream' if closed?
290
278
  raise IOError, 'not opened for reading' unless readable?
291
279
 
292
280
  unless fill_size >= 0 then
@@ -304,17 +292,15 @@ class IO # :nodoc:
304
292
  # during writing, this method will block until either all the data is
305
293
  # flushed or until an error is raised.
306
294
  #
307
- # Raises IOError if #closed_write? returns +true+. Raises IOError unless
295
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
308
296
  # #writable? returns +true+.
309
297
  #
310
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
298
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
311
299
  # #unbuffered_write. Therefore, this method always blocks if unable to
312
300
  # flush the internal write buffer. Aside from that exception, this
313
301
  # method will also raise the same errors and block at the same times as
314
302
  # #unbuffered_write.
315
303
  def flush
316
- raise IOError, 'closed stream' if closed_write?
317
-
318
304
  begin
319
305
  buffered_flush
320
306
  rescue Errno::EAGAIN, Errno::EINTR
@@ -330,10 +316,10 @@ class IO # :nodoc:
330
316
  # automatically to the data stream. Unless set explicitly via #flush_size=,
331
317
  # this defaults to 4096.
332
318
  #
333
- # Raises IOError if #closed_write? returns +true+. Raises IOError unless
319
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
334
320
  # #writable? returns +true+.
335
321
  def flush_size
336
- raise IOError, 'closed stream' if closed_write?
322
+ raise IOError, 'closed stream' if closed?
337
323
  raise IOError, 'not opened for writing' unless writable?
338
324
 
339
325
  @__io_like__flush_size ||= 4096
@@ -346,10 +332,10 @@ class IO # :nodoc:
346
332
  # automatically to the data stream. The new value must be a number greater
347
333
  # than or equal to 0. Setting this to 0 effectively disables buffering.
348
334
  #
349
- # Raises IOError if #closed_write? returns +true+. Raises IOError unless
335
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
350
336
  # #writable? returns +true+.
351
337
  def flush_size=(flush_size)
352
- raise IOError, 'closed stream' if closed_write?
338
+ raise IOError, 'closed stream' if closed?
353
339
  raise IOError, 'not opened for writing' unless writable?
354
340
 
355
341
  unless flush_size >= 0 then
@@ -364,11 +350,11 @@ class IO # :nodoc:
364
350
  # Calls #readchar and either returns the result or +nil+ if #readchar raises
365
351
  # EOFError.
366
352
  #
367
- # Raises IOError if #closed_read? returns +true+. Raises IOError unless
353
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
368
354
  # #readable? returns +true+. Raises all errors raised by #unbuffered_read
369
355
  # except for EOFError.
370
356
  #
371
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
357
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
372
358
  # #unbuffered_read. Therefore, this method always blocks. Aside from that
373
359
  # exception and the conversion of EOFError results into +nil+ results, this
374
360
  # method will also raise the same errors and block at the same times as
@@ -387,15 +373,15 @@ class IO # :nodoc:
387
373
  # data, the returned data is assigned to <tt>$_</tt> and <tt>$.</tt> is set
388
374
  # to the value of #lineno.
389
375
  #
390
- # Raises IOError if #closed_read? returns +true+. Raises IOError unless
376
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
391
377
  # #readable? returns +true+. Raises all errors raised by #unbuffered_read
392
378
  # except for EOFError.
393
379
  #
394
- # NOTE: When _sep_string_ is not +nil+, this method ignores Errno::EAGAIN
395
- # and Errno::EINTR raised by #unbuffered_read. Therefore, this method
396
- # always blocks. Aside from that exception and the conversion of EOFError
397
- # results into +nil+ results, this method will also raise the same errors
398
- # and block at the same times as #unbuffered_read.
380
+ # <b>NOTE:</b> When _sep_string_ is not +nil+, this method ignores
381
+ # Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore,
382
+ # this method always blocks. Aside from that exception and the conversion
383
+ # of EOFError results into +nil+ results, this method will also raise the
384
+ # same errors and block at the same times as #unbuffered_read.
399
385
  def gets(sep_string = $/)
400
386
  # Set the last read line in the global.
401
387
  $_ = readline(sep_string)
@@ -411,7 +397,10 @@ class IO # :nodoc:
411
397
  # ios.isatty -> false
412
398
  #
413
399
  # Returns +false+. Just for compatibility with IO.
400
+ #
401
+ # Raises IOError if #closed? returns +true+.
414
402
  def isatty
403
+ raise IOError, 'closed stream' if closed?
415
404
  false
416
405
  end
417
406
  alias :tty? :isatty
@@ -424,10 +413,10 @@ class IO # :nodoc:
424
413
  # the other line-based reading methods with a non-default value for
425
414
  # _sep_string_ or after changing <tt>$/</tt> will affect this.
426
415
  #
427
- # Raises IOError if #closed_read? returns +true+. Raises IOError unless
416
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
428
417
  # #readable? returns +true+.
429
418
  def lineno
430
- raise IOError, 'closed stream' if closed_read?
419
+ raise IOError, 'closed stream' if closed?
431
420
  raise IOError, 'not opened for reading' unless readable?
432
421
  @__io_like__lineno ||= 0
433
422
  end
@@ -436,14 +425,20 @@ class IO # :nodoc:
436
425
  # ios.lineno = lineno -> lineno
437
426
  #
438
427
  # Sets the current line number to the given value. <tt>$.</tt> is updated
439
- # by the _next_ call to #gets.
428
+ # by the _next_ call to #gets. If the object given is not an integer, it is
429
+ # converted to one using its to_int method.
440
430
  #
441
- # Raises IOError if #closed_read? returns +true+. Raises IOError unless
431
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
442
432
  # #readable? returns +true+.
443
433
  def lineno=(integer)
444
- raise IOError, 'closed stream' if closed_read?
434
+ raise IOError, 'closed stream' if closed?
445
435
  raise IOError, 'not opened for reading' unless readable?
446
- @__io_like__lineno = integer
436
+ if integer.nil? then
437
+ raise TypeError, 'no implicit conversion from nil to integer'
438
+ elsif ! integer.respond_to?(:to_int) then
439
+ raise TypeError, "can't convert #{integer.class} into Integer"
440
+ end
441
+ @__io_like__lineno = integer.to_int
447
442
  end
448
443
 
449
444
  # call-seq:
@@ -464,14 +459,36 @@ class IO # :nodoc:
464
459
  # Raises IOError if #closed? returns +true+. Raises Errno::ESPIPE unless
465
460
  # #seekable? returns +true+.
466
461
  #
467
- # NOTE: Because this method relies on #unbuffered_seek and #unbuffered_write
468
- # (when the internal write buffer is not empty), it will also raise the same
469
- # errors and block at the same times as those functions.
462
+ # <b>NOTE:</b> Because this method relies on #unbuffered_seek and
463
+ # #unbuffered_write (when the internal write buffer is not empty), it will
464
+ # also raise the same errors and block at the same times as those functions.
470
465
  def pos=(position)
471
466
  seek(position, IO::SEEK_SET)
472
467
  position
473
468
  end
474
469
 
470
+ # call-seq:
471
+ # ios.pos -> integer
472
+ #
473
+ # Returns the current offest of ios.
474
+ #
475
+ # Raises IOError if #closed? returns +true+. Raises Errno::ESPIPE unless
476
+ # #seekable? returns +true+.
477
+ #
478
+ # As a side effect, the internal write buffer is flushed unless this is
479
+ # a writable, non-duplexed object. This is for compatibility with the
480
+ # behavior of IO#pos.
481
+ #
482
+ # <b>NOTE:</b> Because this method relies on #unbuffered_seek and
483
+ # #unbuffered_write (when the internal write buffer is not empty), it will
484
+ # also raise the same errors and block at the same times as those functions.
485
+ def pos
486
+ # Flush the internal write buffer for writable, non-duplexed objects.
487
+ buffered_flush if writable? && ! duplexed?
488
+ buffered_seek(0, IO::SEEK_CUR)
489
+ end
490
+ alias :tell :pos
491
+
475
492
  # call-seq:
476
493
  # ios.print([obj, ...]) -> nil
477
494
  #
@@ -482,10 +499,10 @@ class IO # :nodoc:
482
499
  # record separator (<tt>$\\</tt>) is written after all other data if it is
483
500
  # not nil.
484
501
  #
485
- # Raises IOError if #closed_write? returns +true+. Raises IOError unless
502
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
486
503
  # #writable? returns +true+.
487
504
  #
488
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
505
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
489
506
  # #unbuffered_write. Therefore, this method always blocks if unable to
490
507
  # immediately write +[obj, ...]+ completely. Aside from that exception,
491
508
  # this method will also raise the same errors and block at the same times as
@@ -522,10 +539,10 @@ class IO # :nodoc:
522
539
  # Writes the String returned by calling Kernel.sprintf using the given
523
540
  # arguments.
524
541
  #
525
- # Raises IOError if #closed_write? returns +true+. Raises IOError unless
542
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
526
543
  # #writable? returns +true+.
527
544
  #
528
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
545
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
529
546
  # #unbuffered_write. Therefore, this method always blocks if unable to
530
547
  # immediately write its arguments completely. Aside from that exception,
531
548
  # this method will also raise the same errors and block at the same times as
@@ -538,23 +555,23 @@ class IO # :nodoc:
538
555
  # call-seq:
539
556
  # ios.putc(obj) -> obj
540
557
  #
541
- # If _obj_ is Numeric, write the result of <tt>obj.chr</tt>; otherwise,
542
- # write the first character of <tt>obj.to_s</tt>.
558
+ # If _obj_ is a String, write the first byte; otherwise, convert _obj_ to a
559
+ # integer using its _to_int_ method and write the low order byte.
543
560
  #
544
- # Raises IOError if #closed_write? returns +true+. Raises IOError unless
561
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
545
562
  # #writable? returns +true+.
546
563
  #
547
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
564
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
548
565
  # #unbuffered_write. Therefore, this method always blocks if unable to
549
566
  # immediately write _obj_ completely. Aside from that exception, this
550
567
  # method will also raise the same errors and block at the same times as
551
568
  # #unbuffered_write.
552
569
  def putc(obj)
553
570
  char = case obj
554
- when Numeric
555
- obj.chr
571
+ when String
572
+ obj[0].chr
556
573
  else
557
- obj.to_s[0].chr
574
+ [obj.to_int].pack('V')[0].chr
558
575
  end
559
576
  write(char)
560
577
  obj
@@ -569,18 +586,18 @@ class IO # :nodoc:
569
586
  # is written after each object which does not end with the record separator
570
587
  # already. If no objects are given, a single record separator is written.
571
588
  #
572
- # Raises IOError if #closed_write? returns +true+. Raises IOError unless
589
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
573
590
  # #writable? returns +true+.
574
591
  #
575
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
592
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
576
593
  # #unbuffered_write. Therefore, this method always blocks if unable to
577
594
  # immediately write +[obj, ...]+ completely. Aside from that exception,
578
595
  # this method will also raise the same errors and block at the same times as
579
596
  # #unbuffered_write.
580
597
  #
581
- # NOTE: In order to be compatible with IO#puts, the record separator is
582
- # currently hardcoded to be a single newline (<tt>"\n"</tt>) even though the
583
- # documentation implies that the output record separator (<tt>$\\</tt>)
598
+ # <b>NOTE:</b> In order to be compatible with IO#puts, the record separator
599
+ # is currently hardcoded to be a single newline (<tt>"\n"</tt>) even though
600
+ # the documentation implies that the output record separator (<tt>$\\</tt>)
584
601
  # should be used.
585
602
  def puts(*args)
586
603
  # Set the output record separator such that this method is compatible with
@@ -596,13 +613,13 @@ class IO # :nodoc:
596
613
  # Write each argument followed by the record separator. Recursively
597
614
  # process arguments which are Array instances.
598
615
  args.each do |arg|
599
- if arg.kind_of?(Array) then
600
- puts(*arg)
601
- else
602
- line = arg.nil? ? 'nil' : arg.to_s
603
- line += ors if line.index(ors, -ors.length).nil?
604
- write(line)
605
- end
616
+ line = arg.nil? ?
617
+ 'nil' :
618
+ arg.kind_of?(Array) ?
619
+ array_join(arg, ors) :
620
+ arg.to_s
621
+ line += ors if line.index(ors, -ors.length).nil?
622
+ write(line)
606
623
  end
607
624
 
608
625
  nil
@@ -619,22 +636,22 @@ class IO # :nodoc:
619
636
  # If _length_ is unspecified or +nil+, all remaining data is returned. If
620
637
  # no data would be returned at all, an empty String is returned.
621
638
  #
622
- # If _buffer_ is specified, it is assumed to be a String and will be filled
623
- # with the returned data if any.
639
+ # If _buffer_ is specified, it will be converted to a String using its
640
+ # +to_str+ method if necessary and will be filled with the returned data if
641
+ # any.
624
642
  #
625
- # Raises IOError if #closed_read? returns +true+. Raises IOError unless
643
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
626
644
  # #readable? returns +true+.
627
645
  #
628
- # NOTE: Because this method relies on #unbuffered_read, it will also raise
629
- # the same errors and block at the same times as that function.
646
+ # <b>NOTE:</b> Because this method relies on #unbuffered_read, it will also
647
+ # raise the same errors and block at the same times as that function.
630
648
  def read(length = nil, buffer = nil)
631
649
  # Check the validity of the method arguments.
632
650
  unless length.nil? || length >= 0 then
633
651
  raise ArgumentError, "negative length #{length} given"
634
652
  end
635
- buffer = '' if buffer.nil?
636
- # Flush the buffer.
637
- buffer.slice!(0..-1)
653
+ buffer = buffer.nil? ? '' : buffer.to_str
654
+ buffer.slice!(0..-1) unless buffer.empty?
638
655
 
639
656
  if length.nil? then
640
657
  # Read and return everything.
@@ -667,8 +684,8 @@ class IO # :nodoc:
667
684
  # This default implementation of #read_ready? is a hack which should be able
668
685
  # to work for both real IO objects and IO-like objects; however, it is
669
686
  # inefficient since it merely sleeps for 1 second and then returns +true+ as
670
- # long as #closed_read? returns +false+. IO.select should be used for real
671
- # IO objects to wait for a readable condition on platforms with support for
687
+ # long as #closed? returns +false+. IO.select should be used for real IO
688
+ # objects to wait for a readable condition on platforms with support for
672
689
  # IO.select. Other solutions should be found as necessary to improve this
673
690
  # implementation on a case by case basis.
674
691
  #
@@ -684,12 +701,12 @@ class IO # :nodoc:
684
701
  #
685
702
  # Returns +true+ if the stream is both open and readable, +false+ otherwise.
686
703
  #
687
- # This implementation calls #closed_read? and checks to see if
688
- # #unbuffered_read is defined in order to make its determination. Override
689
- # this if the implementing class always provides the #unbuffered_read method
690
- # but may not always be open in a readable mode.
704
+ # This implementation checks to see if #unbuffered_read is defined in order
705
+ # to make its determination. Override this if the implementing class always
706
+ # provides the #unbuffered_read method but may not always be open in a
707
+ # readable mode.
691
708
  def readable?
692
- ! closed_read? && respond_to?(:unbuffered_read, true)
709
+ ! @__io_like__closed_read && respond_to?(:unbuffered_read, true)
693
710
  end
694
711
 
695
712
  # call-seq:
@@ -698,17 +715,17 @@ class IO # :nodoc:
698
715
  # Reads and returns _length_ bytes from the data stream.
699
716
  #
700
717
  # Raises EOFError if reading begins at the end of the stream. Raises
701
- # IOError if #closed_read? returns +true+. Raises IOError unless
702
- # #readable? returns +true+. Raises TruncatedDataError if insufficient
703
- # data is immediately available to satisfy the request.
718
+ # IOError if #closed? returns +true+. Raises IOError unless #readable?
719
+ # returns +true+. Raises TruncatedDataError if insufficient data is
720
+ # immediately available to satisfy the request.
704
721
  #
705
722
  # In the case of TruncatedDataError being raised, the retrieved data can be
706
723
  # fetched from the _data_ attribute of the exception.
707
724
  #
708
725
  # This method is basically copied from IO#readbytes.
709
726
  #
710
- # NOTE: Because this method relies on #unbuffered_read, it will also raise
711
- # the same errors and block at the same times as that function.
727
+ # <b>NOTE:</b> Because this method relies on #unbuffered_read, it will also
728
+ # raise the same errors and block at the same times as that function.
712
729
  def readbytes(length)
713
730
  buffer = read(length)
714
731
  if buffer.nil? then
@@ -726,15 +743,14 @@ class IO # :nodoc:
726
743
  # Returns the next 8-bit byte (0..255) from the stream.
727
744
  #
728
745
  # Raises EOFError when there is no more data in the stream. Raises IOError
729
- # if #closed_read? returns +true+. Raises IOError unless #readable? returns
746
+ # if #closed? returns +true+. Raises IOError unless #readable? returns
730
747
  # +true+.
731
748
  #
732
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
749
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
733
750
  # #unbuffered_read. Therefore, this method always blocks. Aside from that
734
751
  # exception, this method will also raise the same errors and block at the
735
752
  # same times as #unbuffered_read.
736
753
  def readchar
737
- raise IOError, 'closed stream' if closed_read?
738
754
  buffered_read(1)[0]
739
755
  rescue Errno::EAGAIN, Errno::EINTR
740
756
  retry if read_ready?
@@ -747,22 +763,28 @@ class IO # :nodoc:
747
763
  # _sep_string_. Increments #lineno.
748
764
  #
749
765
  # If _sep_string_ is +nil+, a line is defined as the remaining contents of
750
- # the stream. If _sep_string_ is empty, a paragraph is returned, where a
751
- # paragraph is defined as data followed by 2 or more successive newline
752
- # characters (only 2 newlines are returned at the end of the returned data).
766
+ # the stream. If _sep_string_ is not a String, it is converted to one using
767
+ # its +to_str+ method. If _sep_string_ is empty, a paragraph is returned,
768
+ # where a paragraph is defined as data followed by 2 or more successive
769
+ # newline characters (only 2 newlines are returned at the end of the
770
+ # returned data).
753
771
  #
754
772
  # In any case, the end of the stream terminates the current line.
755
773
  #
756
774
  # Raises EOFError when there is no more data in the stream. Raises IOError
757
- # if #closed_read? returns +true+. Raises IOError unless #readable? returns
775
+ # if #closed? returns +true+. Raises IOError unless #readable? returns
758
776
  # +true+.
759
777
  #
760
- # NOTE: When _sep_string_ is not +nil+, this method ignores Errno::EAGAIN
761
- # and Errno::EINTR raised by #unbuffered_read. Therefore, this method
762
- # always blocks. Aside from that exception, this method will also raise the
763
- # same errors and block at the same times as #unbuffered_read.
778
+ # <b>NOTE:</b> When _sep_string_ is not +nil+, this method ignores
779
+ # Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore,
780
+ # this method always blocks. Aside from that exception, this method will
781
+ # also raise the same errors and block at the same times as
782
+ # #unbuffered_read.
764
783
  def readline(sep_string = $/)
765
- raise IOError, 'closed stream' if closed_read?
784
+ # Ensure that sep_string is either nil or a String.
785
+ unless sep_string.nil? || sep_string.kind_of?(String) then
786
+ sep_string = sep_string.to_str
787
+ end
766
788
 
767
789
  buffer = ''
768
790
  begin
@@ -777,14 +799,14 @@ class IO # :nodoc:
777
799
  # Record if the user requested paragraphs rather than lines.
778
800
  paragraph_requested = sep_string.empty?
779
801
  # An empty line separator string indicates that the user wants to
780
- # return paragraphs. A pair of newlines in the stream is used to mark
781
- # this.
802
+ # return paragraphs. A pair of newlines in the stream is used to
803
+ # mark this.
782
804
  sep_string = "\n\n" if paragraph_requested
783
805
 
784
806
  # Add each character from the input to the buffer until either the
785
807
  # buffer has the right ending or the end of the input is reached.
786
808
  while buffer.index(sep_string, -sep_string.length).nil? &&
787
- (char = readchar) do
809
+ (char = buffered_read(1)) do
788
810
  buffer << char
789
811
  end
790
812
 
@@ -792,7 +814,9 @@ class IO # :nodoc:
792
814
  # If the user requested paragraphs instead of lines, we need to
793
815
  # consume and discard all newlines remaining at the front of the
794
816
  # input.
795
- while (char = readchar) && char == "\n" do; end
817
+ while char == "\n" && (char = buffered_read(1)) do
818
+ nil
819
+ end
796
820
  # Put back the last character.
797
821
  ungetc(char[0])
798
822
  end
@@ -814,20 +838,23 @@ class IO # :nodoc:
814
838
  # Returns an Array containing the lines in the stream using #each_line.
815
839
  #
816
840
  # If _sep_string_ is +nil+, a line is defined as the remaining contents of
817
- # the stream. If _sep_string_ is empty, a paragraph is returned, where a
818
- # paragraph is defined as data followed by 2 or more successive newline
819
- # characters (only 2 newlines are returned at the end of the returned data).
841
+ # the stream. If _sep_string_ is not a String, it is converted to one using
842
+ # its +to_str+ method. If _sep_string_ is empty, a paragraph is returned,
843
+ # where a paragraph is defined as data followed by 2 or more successive
844
+ # newline characters (only 2 newlines are returned at the end of the
845
+ # returned data).
820
846
  #
821
847
  # In any case, the end of the stream terminates the current line.
822
848
  #
823
849
  # Raises EOFError when there is no more data in the stream. Raises IOError
824
- # if #closed_read? returns +true+. Raises IOError unless #readable? returns
850
+ # if #closed? returns +true+. Raises IOError unless #readable? returns
825
851
  # +true+.
826
852
  #
827
- # NOTE: When _sep_string_ is not +nil+, this method ignores Errno::EAGAIN
828
- # and Errno::EINTR raised by #unbuffered_read. Therefore, this method
829
- # always blocks. Aside from that exception, this method will also raise the
830
- # same errors and block at the same times as #unbuffered_read.
853
+ # <b>NOTE:</b> When _sep_string_ is not +nil+, this method ignores
854
+ # Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore,
855
+ # this method always blocks. Aside from that exception, this method will
856
+ # also raise the same errors and block at the same times as
857
+ # #unbuffered_read.
831
858
  def readlines(sep_string = $/)
832
859
  lines = []
833
860
  each_line(sep_string) { |line| lines << line }
@@ -844,10 +871,10 @@ class IO # :nodoc:
844
871
  # whether or not the data stream would block.
845
872
  #
846
873
  # Raises EOFError when there is no more data in the stream. Raises IOError
847
- # if #closed_read? returns +true+. Raises IOError unless #readable? returns
874
+ # if #closed? returns +true+. Raises IOError unless #readable? returns
848
875
  # +true+.
849
876
  #
850
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
877
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
851
878
  # #unbuffered_read. Therefore, this method always blocks if unable to
852
879
  # immediately return _length_ bytes. Aside from that exception, this method
853
880
  # will also raise the same errors and block at the same times as
@@ -861,9 +888,6 @@ class IO # :nodoc:
861
888
  # Flush the buffer.
862
889
  buffer.slice!(0..-1)
863
890
 
864
- raise IOError, 'closed stream' if closed_read?
865
- raise IOError, 'not opened for reading' unless readable?
866
-
867
891
  # Read and return up to length bytes.
868
892
  if internal_read_buffer.empty? then
869
893
  begin
@@ -872,6 +896,9 @@ class IO # :nodoc:
872
896
  retry if read_ready?
873
897
  end
874
898
  else
899
+ raise IOError, 'closed stream' if closed?
900
+ raise IOError, 'not opened for reading' unless readable?
901
+
875
902
  buffer << internal_read_buffer.slice!(0, length)
876
903
  end
877
904
  buffer
@@ -889,9 +916,9 @@ class IO # :nodoc:
889
916
  # Raises IOError if #closed? returns +true+. Raises Errno::ESPIPE unless
890
917
  # #seekable? returns +true+.
891
918
  #
892
- # NOTE: Because this method relies on #unbuffered_seek and #unbuffered_write
893
- # (when the internal write buffer is not empty), it will also raise the same
894
- # errors and block at the same times as those functions.
919
+ # <b>NOTE:</b> Because this method relies on #unbuffered_seek and
920
+ # #unbuffered_write (when the internal write buffer is not empty), it will
921
+ # also raise the same errors and block at the same times as those functions.
895
922
  def rewind
896
923
  seek(0, IO::SEEK_SET)
897
924
  self.lineno = 0
@@ -906,17 +933,17 @@ class IO # :nodoc:
906
933
  # counts from the end of the data (_offset_ should be negative here). If
907
934
  # _whence_ is IO::SEEK_CUR, _offset_ is relative to the current position.
908
935
  #
909
- # As a side effect, the internal read and write buffers are flushed.
936
+ # As a side effect, the internal read and write buffers are flushed except
937
+ # when seeking relative to the current position (whence is IO::SEEK_CUR) to
938
+ # a location within the internal read buffer.
910
939
  #
911
940
  # Raises IOError if #closed? returns +true+. Raises Errno::ESPIPE unless
912
941
  # #seekable? returns +true+.
913
942
  #
914
- # NOTE: Because this method relies on #unbuffered_seek and #unbuffered_write
915
- # (when the internal write buffer is not empty), it will also raise the same
916
- # errors and block at the same times as those functions.
943
+ # <b>NOTE:</b> Because this method relies on #unbuffered_seek and
944
+ # #unbuffered_write (when the internal write buffer is not empty), it will
945
+ # also raise the same errors and block at the same times as those functions.
917
946
  def seek(offset, whence = IO::SEEK_SET)
918
- raise IOError, 'closed stream' if closed?
919
-
920
947
  buffered_seek(offset, whence)
921
948
  0
922
949
  end
@@ -924,14 +951,14 @@ class IO # :nodoc:
924
951
  # call-seq:
925
952
  # ios.seekable? -> true or false
926
953
  #
927
- # Returns +true+ if the stream is both open and seekable, +false+ otherwise.
954
+ # Returns +true+ if the stream is seekable, +false+ otherwise.
928
955
  #
929
- # This implementation calls #closed? and checks to see if #unbuffered_seek
930
- # is defined in order to make its determination. Override this if the
931
- # implementing class always provides the #unbuffered_seek method but may not
932
- # always be seekable.
956
+ # This implementation always returns +false+ for duplexed objects and
957
+ # checks to see if #unbuffered_seek is defined in order to make its
958
+ # determination otherwise. Override this if the implementing class always
959
+ # provides the #unbuffered_seek method but may not always be seekable.
933
960
  def seekable?
934
- ! closed? && respond_to?(:unbuffered_seek, true)
961
+ ! duplexed? && respond_to?(:unbuffered_seek, true)
935
962
  end
936
963
 
937
964
  # call-seq:
@@ -940,9 +967,9 @@ class IO # :nodoc:
940
967
  # Returns true if the internal write buffer is currently being bypassed,
941
968
  # false otherwise.
942
969
  #
943
- # Raises IOError if #closed_write? returns +true+.
970
+ # Raises IOError if #closed? returns +true+.
944
971
  def sync
945
- raise IOError, 'closed stream' if closed_write?
972
+ raise IOError, 'closed stream' if closed?
946
973
  @__io_like__sync ||= false
947
974
  end
948
975
 
@@ -954,10 +981,10 @@ class IO # :nodoc:
954
981
  # operation. When set to +false+, the internal write buffer will be
955
982
  # enabled.
956
983
  #
957
- # Raises IOError if #closed_write? returns +true+.
984
+ # Raises IOError if #closed? returns +true+.
958
985
  def sync=(sync)
959
- raise IOError, 'closed stream' if closed_write?
960
- @__io_like__sync = sync
986
+ raise IOError, 'closed stream' if closed?
987
+ @__io_like__sync = sync ? true : false
961
988
  end
962
989
 
963
990
  # call-seq:
@@ -971,38 +998,42 @@ class IO # :nodoc:
971
998
  #
972
999
  # Raises EOFError if reading begins at the end of the stream. Raises
973
1000
  # IOError if the internal read buffer is not empty. Raises IOError if
974
- # #closed_read? returns +true+.
1001
+ # #closed? returns +true+.
975
1002
  #
976
- # NOTE: Because this method relies on #unbuffered_read, it will also raise
977
- # the same errors and block at the same times as that function.
1003
+ # <b>NOTE:</b> Because this method relies on #unbuffered_read, it will also
1004
+ # raise the same errors and block at the same times as that function.
978
1005
  def sysread(length, buffer = nil)
979
- buffer = '' if buffer.nil?
980
- buffer.slice!(0..-1)
1006
+ buffer = buffer.nil? ? '' : buffer.to_str
1007
+ buffer.slice!(0..-1) unless buffer.empty?
981
1008
  return buffer if length == 0
982
1009
 
983
- raise IOError, 'closed stream' if closed_read?
1010
+ raise IOError, 'closed stream' if closed?
984
1011
  raise IOError, 'not opened for reading' unless readable?
985
1012
  unless internal_read_buffer.empty? then
986
1013
  raise IOError, 'sysread on buffered IO'
987
1014
  end
988
1015
 
1016
+ # Flush the internal write buffer for writable, non-duplexed objects.
1017
+ buffered_flush if writable? && ! duplexed?
1018
+
989
1019
  buffer << unbuffered_read(length)
990
1020
  end
991
1021
 
992
1022
  # call-seq:
993
- # ios.sysseek(offset, whence) -> integer
1023
+ # ios.sysseek(offset[, whence]) -> integer
994
1024
  #
995
- # Sets the data pointer of the data stream to the position requested by
996
- # _offset_ and _whence_ and returns the new position.
1025
+ # Sets the current data position to _offset_ based on the setting of
1026
+ # _whence_. If _whence_ is unspecified or IO::SEEK_SET, _offset_ counts
1027
+ # from the beginning of the data. If _whence_ is IO::SEEK_END, _offset_
1028
+ # counts from the end of the data (_offset_ should be negative here). If
1029
+ # _whence_ is IO::SEEK_CUR, _offset_ is relative to the current position.
997
1030
  #
998
1031
  # Raises IOError if the internal read buffer is not empty. Raises IOError
999
- # if #closed? returns +true+.
1032
+ # if #closed? returns +true+. Raises Errno::ESPIPE unless #seekable?
1033
+ # returns +true+.
1000
1034
  #
1001
- # See the description of the operation of #unbuffered_seek for information
1002
- # concerning how to interpret _offset_ and _whence_.
1003
- #
1004
- # NOTE: Because this method relies on #unbuffered_seek, it will also raise
1005
- # the same errors and block at the same times as that function.
1035
+ # <b>NOTE:</b> Because this method relies on #unbuffered_seek, it will also
1036
+ # raise the same errors and block at the same times as that function.
1006
1037
  def sysseek(offset, whence = IO::SEEK_SET)
1007
1038
  raise IOError, 'closed stream' if closed?
1008
1039
  raise Errno::ESPIPE, 'Illegal seek' unless seekable?
@@ -1010,6 +1041,7 @@ class IO # :nodoc:
1010
1041
  unless internal_write_buffer.empty? then
1011
1042
  warn('warning: sysseek on buffered IO')
1012
1043
  end
1044
+
1013
1045
  unbuffered_seek(offset, whence)
1014
1046
  end
1015
1047
 
@@ -1022,46 +1054,27 @@ class IO # :nodoc:
1022
1054
  # As a side effect for non-duplex objects, the internal read buffer is
1023
1055
  # flushed.
1024
1056
  #
1025
- # Raises IOError if #closed_write? returns +true+. Raises IOError unless
1057
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
1026
1058
  # #writable? returns +true+.
1027
1059
  #
1028
- # NOTE: Because this method relies on #unbuffered_write, it will also raise
1029
- # the same errors and block at the same times as that function.
1060
+ # <b>NOTE:</b> Because this method relies on #unbuffered_write, it will also
1061
+ # raise the same errors and block at the same times as that function.
1030
1062
  def syswrite(string)
1031
- raise IOError, 'closed stream' if closed_write?
1063
+ raise IOError, 'closed stream' if closed?
1032
1064
  raise IOError, 'not opened for writing' unless writable?
1033
- unless duplexed? || internal_read_buffer.empty? then
1034
- internal_read_buffer.slice(0..-1)
1035
- end
1036
1065
  unless internal_write_buffer.empty? then
1037
1066
  warn('warning: syswrite on buffered IO')
1038
1067
  end
1039
1068
 
1040
- unbuffered_write(string)
1041
- end
1042
-
1043
- # call-seq:
1044
- # ios.tell -> integer
1045
- #
1046
- # Returns the current offest of ios.
1047
- #
1048
- # Raises IOError if #closed? returns +true+. Raises Errno::ESPIPE unless
1049
- # #seekable? returns +true+.
1050
- #
1051
- # As a side effect, the internal write buffer is flushed unless this is
1052
- # a duplexed object. This is for compatibility with the behavior of
1053
- # IO#tell.
1054
- #
1055
- # NOTE: Because this method relies on #unbuffered_seek and #unbuffered_write
1056
- # (when the internal write buffer is not empty), it will also raise the same
1057
- # errors and block at the same times as those functions.
1058
- def tell
1059
- raise IOError, 'closed stream' if closed?
1069
+ # Flush the internal read buffer and set the unbuffered position to the
1070
+ # buffered position when dealing with non-duplexed objects.
1071
+ unless duplexed? || internal_read_buffer.empty? then
1072
+ unbuffered_seek(-internal_read_buffer.length, IO::SEEK_CUR)
1073
+ internal_read_buffer.slice!(0..-1)
1074
+ end
1060
1075
 
1061
- buffered_flush unless internal_write_buffer.empty?
1062
- buffered_tell
1076
+ unbuffered_write(string)
1063
1077
  end
1064
- alias :pos :tell
1065
1078
 
1066
1079
  # call-seq:
1067
1080
  # ios.to_io -> ios
@@ -1076,7 +1089,7 @@ class IO # :nodoc:
1076
1089
  #
1077
1090
  # Calls #unread with <tt>integer.chr</tt> as an argument.
1078
1091
  #
1079
- # Raises IOError if #closed_read? returns +true+. Raises IOError unless
1092
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
1080
1093
  # #readable? returns +true+.
1081
1094
  def ungetc(integer)
1082
1095
  unread(integer.chr)
@@ -1089,12 +1102,12 @@ class IO # :nodoc:
1089
1102
  # returns +nil+. If _string_ is not a String, it is converted to one using
1090
1103
  # its +to_s+ method.
1091
1104
  #
1092
- # Raises IOError if #closed_read? returns +true+. Raises IOError unless
1105
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
1093
1106
  # #readable? returns +true+.
1094
1107
  def unread(string)
1095
- raise IOError, 'closed stream' if closed_read?
1108
+ raise IOError, 'closed stream' if closed?
1096
1109
  raise IOError, 'not opened for reading' unless readable?
1097
- internal_read_buffer.insert(0, data.to_s)
1110
+ internal_read_buffer.insert(0, string.to_s)
1098
1111
  nil
1099
1112
  end
1100
1113
 
@@ -1107,7 +1120,7 @@ class IO # :nodoc:
1107
1120
  # This default implementation of #write_ready? is a hack which should be
1108
1121
  # able to work for both real IO objects and IO-like objects; however, it is
1109
1122
  # inefficient since it merely sleeps for 1 second and then returns +true+ as
1110
- # long as #closed_write? returns +false+. IO.select should be used for real
1123
+ # long as #closed? returns +false+. IO.select should be used for real
1111
1124
  # IO objects to wait for a writeable condition on platforms with support for
1112
1125
  # IO.select. Other solutions should be found as necessary to improve this
1113
1126
  # implementation on a case by case basis.
@@ -1124,12 +1137,12 @@ class IO # :nodoc:
1124
1137
  #
1125
1138
  # Returns +true+ if the stream is both open and writable, +false+ otherwise.
1126
1139
  #
1127
- # This implementation calls #closed_write? and checks to see if
1128
- # #unbuffered_write is defined in order to make its determination. Override
1129
- # this if the implementing class always provides the #unbuffered_write
1130
- # method but may not always be open in a writable mode.
1140
+ # This implementation checks to see if #unbuffered_write is defined in order
1141
+ # to make its determination. Override this if the implementing class always
1142
+ # provides the #unbuffered_write method but may not always be open in a
1143
+ # writable mode.
1131
1144
  def writable?
1132
- ! closed_write? && respond_to?(:unbuffered_write, true)
1145
+ ! @__io_like__closed_write && respond_to?(:unbuffered_write, true)
1133
1146
  end
1134
1147
 
1135
1148
  # call-seq:
@@ -1140,18 +1153,18 @@ class IO # :nodoc:
1140
1153
  # convert it into one. The entire contents of _string_ are written,
1141
1154
  # blocking as necessary even if the data stream does not block.
1142
1155
  #
1143
- # Raises IOError if #closed_write? returns +true+. Raises IOError unless
1156
+ # Raises IOError if #closed? returns +true+. Raises IOError unless
1144
1157
  # #writable? returns +true+.
1145
1158
  #
1146
- # NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by
1159
+ # <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
1147
1160
  # #unbuffered_write. Therefore, this method always blocks if unable to
1148
1161
  # immediately write _string_ completely. Aside from that exception, this
1149
1162
  # method will also raise the same errors and block at the same times as
1150
1163
  # #unbuffered_write.
1151
1164
  def write(string)
1152
- raise IOError, 'closed stream' if closed_write?
1153
-
1154
1165
  string = string.to_s
1166
+ return 0 if string.empty?
1167
+
1155
1168
  bytes_written = 0
1156
1169
  while bytes_written < string.length do
1157
1170
  begin
@@ -1172,10 +1185,11 @@ class IO # :nodoc:
1172
1185
  #
1173
1186
  # Raises IOError unless #writable? returns +true+.
1174
1187
  #
1175
- # NOTE: Because this method relies on #unbuffered_write, it raises all
1176
- # errors raised by #unbuffered_write and blocks when #unbuffered_write
1188
+ # <b>NOTE:</b> Because this method relies on #unbuffered_write, it raises
1189
+ # all errors raised by #unbuffered_write and blocks when #unbuffered_write
1177
1190
  # blocks.
1178
- def buffered_flush # :nodoc:
1191
+ def buffered_flush
1192
+ raise IOError, 'closed stream' if closed?
1179
1193
  raise IOError, 'not opened for writing' unless writable?
1180
1194
 
1181
1195
  until internal_write_buffer.empty? do
@@ -1193,17 +1207,18 @@ class IO # :nodoc:
1193
1207
  # Raises EOFError if the internal read buffer is empty and reading begins at
1194
1208
  # the end of the stream. Raises IOError unless #readable? returns +true+.
1195
1209
  #
1196
- # NOTE: Because this method relies on #unbuffered_read, it raises all errors
1197
- # raised by #unbuffered_read and blocks when #unbuffered_read blocks
1210
+ # <b>NOTE:</b> Because this method relies on #unbuffered_read, it raises all
1211
+ # errors raised by #unbuffered_read and blocks when #unbuffered_read blocks
1198
1212
  # whenever the internal read buffer is unable to fulfill the request.
1199
- def buffered_read(length) # :nodoc:
1213
+ def buffered_read(length)
1200
1214
  # Check the validity of the method arguments.
1201
1215
  raise ArgumentError, "non-positive length #{length} given" if length < 0
1202
1216
 
1217
+ raise IOError, 'closed stream' if closed?
1203
1218
  raise IOError, 'not opened for reading' unless readable?
1204
1219
 
1205
- # Flush the internal write buffer for non-duplexed objects.
1206
- buffered_flush unless internal_write_buffer.empty? || duplexed?
1220
+ # Flush the internal write buffer for writable, non-duplexed objects.
1221
+ buffered_flush if writable? && ! duplexed?
1207
1222
 
1208
1223
  # Ensure that the internal read buffer has at least enough data to satisfy
1209
1224
  # the request.
@@ -1228,41 +1243,57 @@ class IO # :nodoc:
1228
1243
  # call-seq:
1229
1244
  # ios.buffered_seek(offset[, whence]) -> integer
1230
1245
  #
1231
- # Sets the new position for read or write operations using _offset_ and
1232
- # _whence_ to computer the position. Returns the new position.
1246
+ # Sets the current data position to _offset_ based on the setting of
1247
+ # _whence_. If _whence_ is unspecified or IO::SEEK_SET, _offset_ counts
1248
+ # from the beginning of the data. If _whence_ is IO::SEEK_END, _offset_
1249
+ # counts from the end of the data (_offset_ should be negative here). If
1250
+ # _whence_ is IO::SEEK_CUR, _offset_ is relative to the current position.
1233
1251
  #
1234
- # As a side effect, the internal read and write buffers are flushed.
1252
+ # As a side effect, the internal read and write buffers are flushed except
1253
+ # when seeking relative to the current position (whence is IO::SEEK_CUR) to
1254
+ # a location within the internal read buffer.
1235
1255
  #
1236
1256
  # Raises Errno::ESPIPE unless #seekable? returns +true+.
1237
1257
  #
1238
1258
  # See #seek for the usage of _offset_ and _whence_.
1239
1259
  #
1240
- # NOTE: Because this method relies on #unbuffered_seek and #unbuffered_write
1241
- # (when the internal write buffer is not empty), it will raise the same
1242
- # errors and block at the same times as those functions.
1243
- def buffered_seek(offset, whence = IO::SEEK_SET) # :nodoc:
1244
- raise Errno::ESPIPE, 'Illegal seek' unless seekable?
1245
-
1246
- # Flush the internal buffers.
1247
- internal_read_buffer.slice!(0..-1)
1248
- buffered_flush unless internal_write_buffer.empty?
1249
- # Move the data stream's position as requested.
1250
- unbuffered_seek(offset, whence)
1251
- end
1252
-
1253
- # call-seq:
1254
- # ios.buffered_tell
1255
- #
1256
- # Returns the current position in the stream.
1257
- #
1258
- # Raises Errno::ESPIPE unless #seekable? returns +true+.
1259
- def buffered_tell # :nodoc:
1260
+ # <b>NOTE:</b> Because this method relies on #unbuffered_seek and
1261
+ # #unbuffered_write (when the internal write buffer is not empty), it will
1262
+ # raise the same errors and block at the same times as those functions.
1263
+ def buffered_seek(offset, whence = IO::SEEK_SET)
1264
+ raise IOError, 'closed stream' if closed?
1260
1265
  raise Errno::ESPIPE, 'Illegal seek' unless seekable?
1261
1266
 
1262
- unless internal_read_buffer.empty? then
1267
+ if whence == IO::SEEK_CUR && offset == 0 then
1268
+ # The seek is only determining the current position, so return the
1269
+ # buffered position based on the read buffer if it's not empty and the
1270
+ # write buffer otherwise.
1271
+ internal_read_buffer.empty? ?
1272
+ unbuffered_seek(0, IO::SEEK_CUR) + internal_write_buffer.length :
1273
+ unbuffered_seek(0, IO::SEEK_CUR) - internal_read_buffer.length
1274
+ elsif whence == IO::SEEK_CUR && offset > 0 &&
1275
+ internal_write_buffer.empty? &&
1276
+ offset <= internal_read_buffer.length then
1277
+ # The seek is within the read buffer, so just discard a sufficient
1278
+ # amount of the buffer and report the new buffered position.
1279
+ internal_read_buffer.slice!(0, offset)
1263
1280
  unbuffered_seek(0, IO::SEEK_CUR) - internal_read_buffer.length
1264
1281
  else
1265
- unbuffered_seek(0, IO::SEEK_CUR) + internal_write_buffer.length
1282
+ # The seek target is outside of the buffers, so flush the buffers and
1283
+ # jump to the new position.
1284
+ if whence == IO::SEEK_CUR then
1285
+ # Adjust relative offsets based on the current buffered offset.
1286
+ offset += internal_read_buffer.empty? ?
1287
+ internal_write_buffer.length :
1288
+ -internal_read_buffer.length
1289
+ end
1290
+
1291
+ # Flush the internal buffers.
1292
+ internal_read_buffer.slice!(0..-1)
1293
+ buffered_flush if writable?
1294
+
1295
+ # Move the data stream's position as requested.
1296
+ unbuffered_seek(offset, whence)
1266
1297
  end
1267
1298
  end
1268
1299
 
@@ -1276,16 +1307,17 @@ class IO # :nodoc:
1276
1307
  # the internal write buffer cannot be immediately flushed due to the
1277
1308
  # underlying stream not blocking when unable to accept more data.
1278
1309
  #
1279
- # NOTE: Because this method relies on #unbuffered_write, it raises all
1280
- # errors raised by #unbuffered_write and blocks when #unbuffered_write
1310
+ # <b>NOTE:</b> Because this method relies on #unbuffered_write, it raises
1311
+ # all errors raised by #unbuffered_write and blocks when #unbuffered_write
1281
1312
  # blocks whenever the internal write buffer is unable to fulfill the
1282
1313
  # request.
1283
- def buffered_write(string) # :nodoc:
1314
+ def buffered_write(string)
1315
+ raise IOError, 'closed stream' if closed?
1284
1316
  raise IOError, 'not opened for writing' unless writable?
1285
1317
 
1286
1318
  # Flush the internal read buffer and set the unbuffered position to the
1287
1319
  # buffered position when dealing with non-duplexed objects.
1288
- if ! (duplexed? || internal_read_buffer.empty?) then
1320
+ unless duplexed? || internal_read_buffer.empty? then
1289
1321
  unbuffered_seek(-internal_read_buffer.length, IO::SEEK_CUR)
1290
1322
  internal_read_buffer.slice!(0..-1)
1291
1323
  end
@@ -1315,14 +1347,58 @@ class IO # :nodoc:
1315
1347
  end
1316
1348
 
1317
1349
  # Returns a reference to the internal read buffer.
1318
- def internal_read_buffer # :nodoc:
1350
+ def internal_read_buffer
1319
1351
  @__io_like__read_buffer ||= ''
1320
1352
  end
1321
1353
 
1322
1354
  # Returns a reference to the internal write buffer.
1323
- def internal_write_buffer # :nodoc:
1355
+ def internal_write_buffer
1324
1356
  @__io_like__write_buffer ||= ''
1325
1357
  end
1358
+
1359
+ # This method joins the elements of _array_ together with _separator_
1360
+ # between each element and returns the result. _seen_ is a list of object
1361
+ # IDs representing arrays which have already started processing.
1362
+ #
1363
+ # This method exists only because Array#join apparently behaves in an
1364
+ # implementation dependent manner when joining recursive arrays and so does
1365
+ # not always produce the expected results. Specifically, MRI 1.8.6 and
1366
+ # 1.8.7 behave as follows:
1367
+ #
1368
+ # x = []
1369
+ # x << 1 << x << 2
1370
+ # x.join(', ') => "1, 1, [...], 2, 2"
1371
+ #
1372
+ # The expected and necessary result for use with #puts is:
1373
+ #
1374
+ # "1, [...], 2"
1375
+ #
1376
+ # Things get progressively worse as the nesting and recursion become more
1377
+ # convoluted.
1378
+ def array_join(array, separator, seen = [])
1379
+ first = true
1380
+ seen.push(array.object_id)
1381
+ result = array.inject('') do |memo, item|
1382
+ if first then
1383
+ first = false
1384
+ else
1385
+ memo << separator
1386
+ end
1387
+
1388
+ memo << if item.kind_of?(Array) then
1389
+ if seen.include?(item.object_id) then
1390
+ '[...]'
1391
+ else
1392
+ array_join(item, separator, seen)
1393
+ end
1394
+ else
1395
+ item.to_s
1396
+ end
1397
+ end
1398
+ seen.pop
1399
+
1400
+ result
1401
+ end
1326
1402
  end
1327
1403
  end
1328
1404