io-like 0.3.1 → 0.4.0.pre1
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.
- checksums.yaml +7 -0
- data/LICENSE +1 -1
- data/NEWS.md +14 -1
- data/README.md +75 -94
- data/lib/io/like.rb +1916 -1314
- data/lib/io/like_helpers/abstract_io.rb +512 -0
- data/lib/io/like_helpers/blocking_io.rb +86 -0
- data/lib/io/like_helpers/buffered_io.rb +555 -0
- data/lib/io/like_helpers/character_io/basic_reader.rb +122 -0
- data/lib/io/like_helpers/character_io/converter_reader.rb +252 -0
- data/lib/io/like_helpers/character_io.rb +529 -0
- data/lib/io/like_helpers/delegated_io.rb +250 -0
- data/lib/io/like_helpers/duplexed_io.rb +259 -0
- data/lib/io/like_helpers/io.rb +21 -0
- data/lib/io/like_helpers/io_wrapper.rb +290 -0
- data/lib/io/like_helpers/pipeline.rb +77 -0
- data/lib/io/like_helpers/ruby_facts.rb +33 -0
- data/lib/io/like_helpers.rb +14 -0
- metadata +107 -224
- data/.yardopts +0 -1
- data/Rakefile +0 -228
- data/ruby.1.8.mspec +0 -7
- data/spec/binmode_spec.rb +0 -29
- data/spec/close_read_spec.rb +0 -64
- data/spec/close_spec.rb +0 -36
- data/spec/close_write_spec.rb +0 -61
- data/spec/closed_spec.rb +0 -16
- data/spec/each_byte_spec.rb +0 -38
- data/spec/each_line_spec.rb +0 -11
- data/spec/each_spec.rb +0 -11
- data/spec/eof_spec.rb +0 -11
- data/spec/fixtures/classes.rb +0 -96
- data/spec/fixtures/gets.txt +0 -9
- data/spec/fixtures/numbered_lines.txt +0 -5
- data/spec/fixtures/one_byte.txt +0 -1
- data/spec/fixtures/paragraphs.txt +0 -7
- data/spec/fixtures/readlines.txt +0 -6
- data/spec/flush_spec.rb +0 -8
- data/spec/getc_spec.rb +0 -44
- data/spec/gets_spec.rb +0 -212
- data/spec/isatty_spec.rb +0 -6
- data/spec/lineno_spec.rb +0 -84
- data/spec/output_spec.rb +0 -47
- data/spec/pos_spec.rb +0 -53
- data/spec/print_spec.rb +0 -97
- data/spec/printf_spec.rb +0 -24
- data/spec/putc_spec.rb +0 -57
- data/spec/puts_spec.rb +0 -99
- data/spec/read_spec.rb +0 -162
- data/spec/readchar_spec.rb +0 -49
- data/spec/readline_spec.rb +0 -60
- data/spec/readlines_spec.rb +0 -140
- data/spec/readpartial_spec.rb +0 -92
- data/spec/rewind_spec.rb +0 -56
- data/spec/seek_spec.rb +0 -72
- data/spec/shared/each.rb +0 -204
- data/spec/shared/eof.rb +0 -116
- data/spec/shared/pos.rb +0 -39
- data/spec/shared/tty.rb +0 -12
- data/spec/shared/write.rb +0 -53
- data/spec/sync_spec.rb +0 -56
- data/spec/sysread_spec.rb +0 -87
- data/spec/sysseek_spec.rb +0 -68
- data/spec/syswrite_spec.rb +0 -60
- data/spec/tell_spec.rb +0 -7
- data/spec/to_io_spec.rb +0 -19
- data/spec/tty_spec.rb +0 -6
- data/spec/ungetc_spec.rb +0 -118
- data/spec/write_spec.rb +0 -61
- data/spec_helper.rb +0 -49
- /data/{LICENSE-rubyspec → rubyspec/LICENSE} +0 -0
data/lib/io/like.rb
CHANGED
@@ -1,1455 +1,2057 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
# In order to create a duplexed stream where writing and reading happen
|
65
|
-
# independently of each other, override the #duplexed? method to return
|
66
|
-
# +true+ and then provide the _unbuffered_read_ and _unbuffered_write_
|
67
|
-
# methods. Do *NOT* provide an _unbuffered_seek_ method or the contents of
|
68
|
-
# the internal read and write buffers may be lost unexpectedly.
|
69
|
-
# ---
|
70
|
-
# <b>NOTE:</b> Due to limitations of Ruby's finalizer, IO::Like#close is not
|
71
|
-
# automatically called when the object is garbage collected, so it must be
|
72
|
-
# explicitly called when the object is no longer needed or risk losing
|
73
|
-
# whatever data remains in the internal write buffer.
|
74
|
-
module Like
|
75
|
-
include Enumerable
|
76
|
-
|
77
|
-
# call-seq:
|
78
|
-
# ios << obj -> ios
|
79
|
-
#
|
80
|
-
# Writes _obj_ to the stream using #write and returns _ios_. _obj_ is
|
81
|
-
# converted to a String using _to_s_.
|
82
|
-
def <<(obj)
|
83
|
-
write(obj)
|
84
|
-
self
|
85
|
-
end
|
86
|
-
|
87
|
-
# call-seq:
|
88
|
-
# ios.binmode -> ios
|
89
|
-
#
|
90
|
-
# Returns +self+. Just for compatibility with IO.
|
91
|
-
def binmode
|
92
|
-
self
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'io/like_helpers/duplexed_io'
|
4
|
+
require 'io/like_helpers/io'
|
5
|
+
require 'io/like_helpers/io_wrapper'
|
6
|
+
require 'io/like_helpers/pipeline'
|
7
|
+
require 'io/like_helpers/ruby_facts'
|
8
|
+
|
9
|
+
##
|
10
|
+
# All the goodies for this library go in this namespace. It's probably a bad
|
11
|
+
# idea.
|
12
|
+
class IO
|
13
|
+
|
14
|
+
##
|
15
|
+
# This is a wrapper class that provides the same instance methods as the IO
|
16
|
+
# class for simpler delegates given to it.
|
17
|
+
class Like < LikeHelpers::DuplexedIO
|
18
|
+
include LikeHelpers::RubyFacts
|
19
|
+
include Enumerable
|
20
|
+
|
21
|
+
##
|
22
|
+
# This is used by #puts as the separator between all arguments.
|
23
|
+
ORS = "\n"
|
24
|
+
|
25
|
+
##
|
26
|
+
# Creates a new instance of this class.
|
27
|
+
#
|
28
|
+
# @param delegate_r [LikeHelpers::AbstractIO] delegate for read operations
|
29
|
+
# @param delegate_w [LikeHelpers::AbstractIO] delegate for write operations
|
30
|
+
# @param autoclose [Boolean] when `true` close the delegate(s) when this
|
31
|
+
# stream is closed
|
32
|
+
# @param binmode [Boolean] when `true` suppresses EOL <-> CRLF conversion on
|
33
|
+
# Windows and sets external encoding to ASCII-8BIT unless explicitly
|
34
|
+
# specified
|
35
|
+
# @param encoding [Encoding, String] the external encoding or both the
|
36
|
+
# external and internal encoding if specified as `"ext_enc:int_enc"`
|
37
|
+
# @param encoding_opts [Hash] options to be passed to String#encode
|
38
|
+
# @param external_encoding [Encoding, String] the external encoding
|
39
|
+
# @param internal_encoding [Encoding, String] the internal encoding
|
40
|
+
# @param sync [Boolean] when `true` causes write operations to bypass internal
|
41
|
+
# buffering
|
42
|
+
# @param pid [Integer] the return value for {#pid}
|
43
|
+
def initialize(
|
44
|
+
delegate_r,
|
45
|
+
delegate_w = delegate_r,
|
46
|
+
autoclose: true,
|
47
|
+
binmode: false,
|
48
|
+
encoding: nil,
|
49
|
+
encoding_opts: {},
|
50
|
+
external_encoding: nil,
|
51
|
+
internal_encoding: nil,
|
52
|
+
sync: false,
|
53
|
+
pid: nil,
|
54
|
+
pipeline_class: LikeHelpers::Pipeline
|
55
|
+
)
|
56
|
+
if encoding
|
57
|
+
if external_encoding
|
58
|
+
warn("Ignoring encoding parameter '#{encoding}': external_encoding is used")
|
59
|
+
encoding = nil
|
60
|
+
elsif internal_encoding
|
61
|
+
warn("Ignoring encoding parameter '#{encoding}': internal_encoding is used")
|
62
|
+
encoding = nil
|
63
|
+
end
|
93
64
|
end
|
94
65
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
# already returns +true+. For duplexed objects, calls #close_read and
|
100
|
-
# #close_write. For non-duplexed objects, calls #flush if #writable?
|
101
|
-
# returns +true+ and then sets a flag so that #closed? will return +true+.
|
102
|
-
def close
|
103
|
-
raise IOError, 'closed stream' if closed?
|
104
|
-
__io_like__close_read
|
105
|
-
flush if writable?
|
106
|
-
__io_like__close_write
|
107
|
-
nil
|
66
|
+
if external_encoding
|
67
|
+
external_encoding = Encoding.find(external_encoding)
|
68
|
+
elsif internal_encoding
|
69
|
+
external_encoding = Encoding.default_external
|
108
70
|
end
|
109
71
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
#
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
72
|
+
@pipeline_class = pipeline_class
|
73
|
+
pipeline_r = @pipeline_class.new(delegate_r, autoclose: autoclose)
|
74
|
+
pipeline_w = delegate_r == delegate_w ?
|
75
|
+
pipeline_r :
|
76
|
+
@pipeline_class.new(delegate_w, autoclose: autoclose)
|
77
|
+
|
78
|
+
super(pipeline_r, pipeline_w)
|
79
|
+
|
80
|
+
# NOTE:
|
81
|
+
# Binary mode must be set before the encoding in order to allow any
|
82
|
+
# explicitly set external encoding to override the implicit ASCII-8BIT
|
83
|
+
# encoding when binmode is set.
|
84
|
+
@binmode = false
|
85
|
+
self.binmode if binmode
|
86
|
+
if ! binmode || encoding || external_encoding || internal_encoding
|
87
|
+
if encoding && ! (Encoding === encoding) && encoding =~ /^bom\|/i
|
88
|
+
if ! set_encoding_by_bom
|
89
|
+
set_encoding(encoding.to_s[4..-1], **encoding_opts)
|
90
|
+
end
|
126
91
|
else
|
127
|
-
|
92
|
+
set_encoding(
|
93
|
+
encoding || external_encoding, internal_encoding, **encoding_opts
|
94
|
+
)
|
128
95
|
end
|
129
|
-
nil
|
130
96
|
end
|
131
97
|
|
132
|
-
|
133
|
-
# ios.close_write -> nil
|
134
|
-
#
|
135
|
-
# Closes the write end of a duplexed object or the whole object if the
|
136
|
-
# object is write-only.
|
137
|
-
#
|
138
|
-
# Raises IOError if #closed? returns +true+. Raises IOError for duplexed
|
139
|
-
# objects if called more than once. Raises IOError for non-duplexed objects
|
140
|
-
# if #readable? returns +true+.
|
141
|
-
def close_write
|
142
|
-
raise IOError, 'closed stream' if closed?
|
143
|
-
if __io_like__closed_write? || ! duplexed? && readable? then
|
144
|
-
raise IOError, 'closing non-duplex IO for reading'
|
145
|
-
end
|
146
|
-
if duplexed? then
|
147
|
-
flush
|
148
|
-
__io_like__close_write
|
149
|
-
else
|
150
|
-
close
|
151
|
-
end
|
152
|
-
nil
|
153
|
-
end
|
98
|
+
@pid = nil == pid ? pid : ensure_integer(pid)
|
154
99
|
|
155
|
-
|
156
|
-
# ios.closed? -> true or false
|
157
|
-
#
|
158
|
-
# Returns +true+ if this object is closed or otherwise unusable for read and
|
159
|
-
# write operations.
|
160
|
-
def closed?
|
161
|
-
(__io_like__closed_read? || ! readable?) &&
|
162
|
-
(__io_like__closed_write? || ! writable?)
|
163
|
-
end
|
100
|
+
self.sync = sync
|
164
101
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
# Returns +false+. Override this to return +true+ when creating duplexed
|
169
|
-
# IO objects.
|
170
|
-
def duplexed?
|
171
|
-
false
|
172
|
-
end
|
102
|
+
@skip_duplexed_check = false
|
103
|
+
@readable = @writable = nil
|
104
|
+
end
|
173
105
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
106
|
+
##
|
107
|
+
# Writes `obj` to the stream using {#write}.
|
108
|
+
#
|
109
|
+
# @param obj converted to a String using its #to_s method
|
110
|
+
#
|
111
|
+
# @return [self]
|
112
|
+
def <<(obj)
|
113
|
+
write(obj)
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Puts the stream into binary mode.
|
119
|
+
#
|
120
|
+
# Once a stream is in binary mode, it cannot be reset to nonbinary mode.
|
121
|
+
# * Newline conversion disabled
|
122
|
+
# * Encoding conversion disabled
|
123
|
+
# * Content is treated as ASCII-8BIT
|
124
|
+
#
|
125
|
+
# @return [self]
|
126
|
+
#
|
127
|
+
# @raise [IOError] if the stream is closed
|
128
|
+
def binmode
|
129
|
+
assert_open
|
130
|
+
@binmode = true
|
131
|
+
set_encoding(Encoding::BINARY)
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Returns `true` if the stream is in binary mode and `false` otherwise.
|
137
|
+
#
|
138
|
+
# @return [Boolean]
|
139
|
+
#
|
140
|
+
# @raise [IOError] if the stream is closed
|
141
|
+
def binmode?
|
142
|
+
assert_open
|
143
|
+
@binmode
|
144
|
+
end
|
145
|
+
|
146
|
+
if RBVER_LT_3_0
|
147
|
+
##
|
148
|
+
# @deprecated Use {#each_byte} instead.
|
149
|
+
#
|
150
|
+
# @version < Ruby 3.0
|
151
|
+
def bytes(&block)
|
152
|
+
warn('warning: IO#bytes is deprecated; use #each_byte instead')
|
153
|
+
each_byte(&block)
|
154
|
+
end
|
155
|
+
|
156
|
+
##
|
157
|
+
# @deprecated Use {#each_char} instead.
|
158
|
+
#
|
159
|
+
# @version < Ruby 3.0
|
160
|
+
def chars(&block)
|
161
|
+
warn('warning: IO#chars is deprecated; use #each_char instead')
|
162
|
+
each_char(&block)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Closes the stream, flushing any buffered data first.
|
168
|
+
#
|
169
|
+
# This always blocks when buffered data needs to be written, even when the
|
170
|
+
# stream is in nonblocking mode.
|
171
|
+
#
|
172
|
+
# @return [nil]
|
173
|
+
def close
|
174
|
+
@skip_duplexed_check = true
|
175
|
+
super
|
176
|
+
|
177
|
+
nil
|
178
|
+
ensure
|
179
|
+
@skip_duplexed_check = false
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# Closes the read side of duplexed streams and closes the entire stream for
|
184
|
+
# read-only, non-duplexed streams.
|
185
|
+
#
|
186
|
+
# @return [nil]
|
187
|
+
#
|
188
|
+
# @raise [IOError] if the stream is non-duplexed and writable
|
189
|
+
def close_read
|
190
|
+
return if closed_read?
|
191
|
+
|
192
|
+
if ! @skip_duplexed_check && ! duplexed? && writable?
|
193
|
+
raise IOError, 'closing non-duplex IO for reading'
|
190
194
|
end
|
191
195
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
196
|
+
super
|
197
|
+
|
198
|
+
nil
|
199
|
+
end
|
200
|
+
|
201
|
+
##
|
202
|
+
# Closes the write side of duplexed streams and closes the entire stream for
|
203
|
+
# write-only, non-duplexed streams.
|
204
|
+
#
|
205
|
+
# @return [nil]
|
206
|
+
#
|
207
|
+
# @raise [IOError] if the stream is non-duplexed and readable
|
208
|
+
def close_write
|
209
|
+
return if closed_write?
|
210
|
+
|
211
|
+
if ! @skip_duplexed_check && ! duplexed? && readable?
|
212
|
+
raise IOError, 'closing non-duplex IO for writing'
|
209
213
|
end
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
214
|
+
|
215
|
+
flush if writable?
|
216
|
+
super
|
217
|
+
|
218
|
+
nil
|
219
|
+
end
|
220
|
+
|
221
|
+
if RBVER_LT_3_0
|
222
|
+
##
|
223
|
+
# @deprecated Use {#each_codepoint} instead.
|
224
|
+
#
|
225
|
+
# @version < Ruby 3.0
|
226
|
+
def codepoints(&block)
|
227
|
+
warn('warning: IO#codepoints is deprecated; use #each_codepoint instead')
|
228
|
+
each_codepoint(&block)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# @overload each_byte
|
234
|
+
# @return [Enumerator] an enumerator that iterates over each byte in the
|
235
|
+
# stream
|
236
|
+
#
|
237
|
+
# @overload each_byte
|
238
|
+
# Iterates over each byte in the stream, yielding each byte to the given
|
239
|
+
# block.
|
240
|
+
#
|
241
|
+
# @yieldparam byte [Integer] the next byte from the stream
|
242
|
+
#
|
243
|
+
# @return [self]
|
244
|
+
#
|
245
|
+
# @raise [IOError] if the stream is not open for reading
|
246
|
+
def each_byte
|
247
|
+
return to_enum(:each_byte) unless block_given?
|
248
|
+
|
249
|
+
while (byte = getbyte) do
|
250
|
+
yield(byte)
|
233
251
|
end
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
252
|
+
self
|
253
|
+
end
|
254
|
+
|
255
|
+
##
|
256
|
+
# @overload each_char
|
257
|
+
# @return [Enumerator] an enumerator that iterates over each character in
|
258
|
+
# the stream
|
259
|
+
#
|
260
|
+
# @overload each_char
|
261
|
+
# Iterates over each character in the stream, yielding each character to the
|
262
|
+
# given block.
|
263
|
+
#
|
264
|
+
# @yieldparam char [String] the next character from the stream
|
265
|
+
#
|
266
|
+
# @return [self]
|
267
|
+
#
|
268
|
+
# @raise [IOError] if the stream is not open for reading
|
269
|
+
def each_char
|
270
|
+
return to_enum(:each_char) unless block_given?
|
271
|
+
|
272
|
+
while char = getc do
|
273
|
+
yield(char)
|
242
274
|
end
|
275
|
+
self
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# @overload each_codepoint
|
280
|
+
# @return [Enumerator] an enumerator that iterates over each Integer ordinal
|
281
|
+
# of each character in the stream
|
282
|
+
#
|
283
|
+
# @overload each_codepoint
|
284
|
+
# Iterates over each Integer ordinal of each character in the stream,
|
285
|
+
# yielding each ordinal to the given block.
|
286
|
+
#
|
287
|
+
# @yieldparam codepoint [Integer] the Integer ordinal of the next character
|
288
|
+
# from the stream
|
289
|
+
#
|
290
|
+
# @return [self]
|
291
|
+
#
|
292
|
+
# @raise [IOError] if the stream is not open for reading
|
293
|
+
def each_codepoint
|
294
|
+
return to_enum(:each_codepoint) unless block_given?
|
295
|
+
|
296
|
+
each_char { |c| yield(c.codepoints[0]) }
|
297
|
+
self
|
298
|
+
end
|
243
299
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
300
|
+
##
|
301
|
+
# @overload each_line(separator = $/, limit = nil, chomp: false)
|
302
|
+
# @param separator [String, nil] a non-empty String that separates each
|
303
|
+
# line, an empty String that equates to 2 or more successive newlines as
|
304
|
+
# the separator, or `nil` to indicate reading all remaining data
|
305
|
+
# @param limit [Integer, nil] an Integer limiting the number of bytes
|
306
|
+
# returned in each line or `nil` to indicate no limit
|
307
|
+
# @param chomp [Boolean] when `true` trailing newlines and carriage returns
|
308
|
+
# will be removed from each line
|
309
|
+
#
|
310
|
+
# @return [Enumerator] an enumerator that iterates over each line in the
|
311
|
+
# stream
|
312
|
+
#
|
313
|
+
# @overload each_line(limit, chomp: false)
|
314
|
+
# @param limit [Integer] an Integer limiting the number of bytes returned in
|
315
|
+
# each line or `nil` to indicate no limit
|
316
|
+
# @param chomp [Boolean] when `true` trailing newlines and carriage returns
|
317
|
+
# will be removed from each line
|
318
|
+
#
|
319
|
+
# @return [Enumerator] an enumerator that iterates over each line in the
|
320
|
+
# stream where each line is separated by `$/`
|
321
|
+
#
|
322
|
+
# @overload each_line(separator = $/, limit = nil, chomp: false)
|
323
|
+
# Iterates over each line in the stream, yielding each line to the given
|
324
|
+
# block.
|
325
|
+
#
|
326
|
+
# @param separator [String, nil] a non-empty String that separates each
|
327
|
+
# line, an empty String that equates to 2 or more successive newlines as
|
328
|
+
# the separator, or `nil` to indicate reading all remaining data
|
329
|
+
# @param limit [Integer, nil] an Integer limiting the number of bytes
|
330
|
+
# returned in each line or `nil` to indicate no limit
|
331
|
+
# @param chomp [Boolean] when `true` trailing newlines and carriage returns
|
332
|
+
# will be removed from each line
|
333
|
+
#
|
334
|
+
# @yieldparam line [String] a line from the stream
|
335
|
+
#
|
336
|
+
# @return [self]
|
337
|
+
#
|
338
|
+
# @overload each_line(limit, chomp: false)
|
339
|
+
# Iterates over each line in the stream, where each line is separated by
|
340
|
+
# `$/`, yielding each line to the given block.
|
341
|
+
#
|
342
|
+
# @param limit [Integer] an Integer limiting the number of bytes returned in
|
343
|
+
# each line or `nil` to indicate no limit
|
344
|
+
# @param chomp [Boolean] when `true` trailing newlines and carriage returns
|
345
|
+
# will be removed from each line
|
346
|
+
#
|
347
|
+
# @yieldparam line [String] a line from the stream
|
348
|
+
#
|
349
|
+
# @return [self]
|
350
|
+
#
|
351
|
+
# @raise [IOError] if the stream is not open for reading
|
352
|
+
def each_line(*args, **opts)
|
353
|
+
unless block_given?
|
354
|
+
return to_enum(:each_line, *args, **opts)
|
250
355
|
end
|
251
356
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
# defaults to 4096.
|
258
|
-
#
|
259
|
-
# Raises IOError if #closed? returns +true+. Raises IOError if the
|
260
|
-
# stream is not opened for reading.
|
261
|
-
def fill_size
|
262
|
-
raise IOError, 'closed stream' if closed?
|
263
|
-
raise IOError, 'not opened for reading' unless readable?
|
264
|
-
|
265
|
-
@__io_like__fill_size ||= 4096
|
357
|
+
sep_string, limit = parse_readline_args(*args)
|
358
|
+
raise ArgumentError, 'invalid limit: 0 for each_line' if limit == 0
|
359
|
+
|
360
|
+
while (line = gets(sep_string, limit, **opts)) do
|
361
|
+
yield(line)
|
266
362
|
end
|
363
|
+
self
|
364
|
+
end
|
365
|
+
alias_method :each, :each_line
|
267
366
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
end
|
284
|
-
@__io_like__fill_size = fill_size
|
367
|
+
##
|
368
|
+
# Returns `true` if the end of the stream has been reached and `false`
|
369
|
+
# otherwise.
|
370
|
+
#
|
371
|
+
# @note This method will block if reading the stream blocks.
|
372
|
+
# @note This method relies on buffered operations, so using it in conjuction
|
373
|
+
# with {#sysread} will be complicated at best.
|
374
|
+
#
|
375
|
+
# @return [Boolean]
|
376
|
+
#
|
377
|
+
# @raise [IOError] if the stream is not open for reading
|
378
|
+
def eof?
|
379
|
+
if byte = getbyte
|
380
|
+
ungetbyte(byte)
|
381
|
+
return false
|
285
382
|
end
|
383
|
+
true
|
384
|
+
end
|
385
|
+
alias_method :eof, :eof?
|
286
386
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
387
|
+
##
|
388
|
+
# Returns the external encoding of the stream, if any.
|
389
|
+
#
|
390
|
+
# @return [Encoding] the Encoding object that represents the encoding of the
|
391
|
+
# stream
|
392
|
+
# @return [nil] if the stream is writable and no encoding is specified
|
393
|
+
#
|
394
|
+
# @raise [IOError] if the stream is closed and Ruby version is less than 3.1
|
395
|
+
def external_encoding
|
396
|
+
assert_open if RBVER_LT_3_1
|
397
|
+
|
398
|
+
encoding = delegate.character_io.external_encoding
|
399
|
+
return encoding if encoding || writable?
|
400
|
+
|
401
|
+
Encoding::default_external
|
402
|
+
end
|
403
|
+
|
404
|
+
##
|
405
|
+
# Flushes the internal write buffer to the underlying stream.
|
406
|
+
#
|
407
|
+
# Regardless of the blocking status of the stream or interruptions during
|
408
|
+
# writing, this method will block until either all the data is flushed or
|
409
|
+
# until an error is raised.
|
410
|
+
#
|
411
|
+
# @return [self]
|
412
|
+
#
|
413
|
+
# @raise [IOError] if the stream is not open for writing
|
414
|
+
def flush
|
415
|
+
assert_open
|
416
|
+
|
417
|
+
delegate_w.buffered_io.flush
|
418
|
+
|
419
|
+
self
|
420
|
+
end
|
421
|
+
|
422
|
+
##
|
423
|
+
# Returns the next byte from the stream.
|
424
|
+
#
|
425
|
+
# @return [Integer] the next byte from the stream
|
426
|
+
# @return [nil] if the end of the stream has been reached
|
427
|
+
#
|
428
|
+
# @raise [IOError] if the stream is not open for reading
|
429
|
+
def getbyte
|
430
|
+
readbyte
|
431
|
+
rescue EOFError
|
432
|
+
return nil
|
433
|
+
end
|
434
|
+
|
435
|
+
##
|
436
|
+
# Returns the next character from the stream.
|
437
|
+
#
|
438
|
+
# @return [String] the next character from the stream
|
439
|
+
# @return [nil] if the end of the stream has been reached
|
440
|
+
#
|
441
|
+
# @raise [IOError] if the stream is not open for reading
|
442
|
+
def getc
|
443
|
+
readchar
|
444
|
+
rescue EOFError
|
445
|
+
nil
|
446
|
+
end
|
447
|
+
|
448
|
+
##
|
449
|
+
# Returns the next line from the stream.
|
450
|
+
#
|
451
|
+
# @overload gets(separator = $/, limit = nil, chomp: false)
|
452
|
+
#
|
453
|
+
# @param separator [String, nil] a non-empty String that separates each
|
454
|
+
# line, an empty String that equates to 2 or more successive newlines as
|
455
|
+
# the separator, or `nil` to indicate reading all remaining data
|
456
|
+
# @param limit [Integer, nil] an Integer limiting the number of bytes
|
457
|
+
# returned in each line or `nil` to indicate no limit
|
458
|
+
# @param chomp [Boolean] when `true` trailing newlines and carriage returns
|
459
|
+
# will be removed from each line
|
460
|
+
#
|
461
|
+
# @return [String] the next line in the stream
|
462
|
+
# @return [nil] if the end of the stream has been reached
|
463
|
+
#
|
464
|
+
# @overload gets(limit, chomp: false)
|
465
|
+
#
|
466
|
+
# @param limit [Integer] an Integer limiting the number of bytes returned in
|
467
|
+
# each line or `nil` to indicate no limit
|
468
|
+
# @param chomp [Boolean] when `true` trailing newlines and carriage returns
|
469
|
+
# will be removed from each line
|
470
|
+
#
|
471
|
+
# @return [String] the next line in the stream where the separator is `$/`
|
472
|
+
# @return [nil] if the end of the stream has been reached
|
473
|
+
#
|
474
|
+
# @raise [IOError] if the stream is not open for reading
|
475
|
+
def gets(*args, **opts)
|
476
|
+
readline(*args, **opts)
|
477
|
+
rescue EOFError
|
478
|
+
# NOTE:
|
479
|
+
# Through Ruby 3.3, assigning to $_ has no effect outside of a method that
|
480
|
+
# does it. This assignment is kept in case that ever changes.
|
481
|
+
$_ = nil
|
482
|
+
nil
|
483
|
+
end
|
484
|
+
|
485
|
+
##
|
486
|
+
# Returns the internal encoding of the stream, if any.
|
487
|
+
#
|
488
|
+
# @return [Encoding] the Encoding object that represents the encoding of the
|
489
|
+
# internal string conversion
|
490
|
+
# @return [nil] if no encoding is specified
|
491
|
+
#
|
492
|
+
# @raise [IOError] if the stream is closed and Ruby version is less than 3.1
|
493
|
+
def internal_encoding
|
494
|
+
assert_open if RBVER_LT_3_1
|
495
|
+
delegate.character_io.internal_encoding
|
496
|
+
end
|
497
|
+
|
498
|
+
##
|
499
|
+
# For compatibility with `IO`.
|
500
|
+
alias_method :isatty, :tty?
|
501
|
+
|
502
|
+
##
|
503
|
+
# Returns the current line number of the stream.
|
504
|
+
#
|
505
|
+
# More accurately the number of times {#gets} is called on the stream and
|
506
|
+
# returns a non-`nil` result, either explicitly or implicitly via methods such
|
507
|
+
# as {#each_line}, {#readline}, {#readlines}, etc. is returned. This may
|
508
|
+
# differ from the number of lines if `$/` is changed from the default or if
|
509
|
+
# {#gets} is called with a different separator.
|
510
|
+
#
|
511
|
+
# @return [Integer] the current line number of the stream
|
512
|
+
#
|
513
|
+
# @raise [IOError] if the stream is not open for reading
|
514
|
+
def lineno
|
515
|
+
assert_readable
|
516
|
+
|
517
|
+
@lineno ||= 0
|
518
|
+
end
|
519
|
+
|
520
|
+
##
|
521
|
+
# Sets the current line number of the stream to the given value. `$.` is
|
522
|
+
# updated by the _next_ call to {#gets}. If the object given is not an
|
523
|
+
# Integer, it is converted to one using the `Integer` method.
|
524
|
+
#
|
525
|
+
# @return [Integer] the current line number of the stream
|
526
|
+
#
|
527
|
+
# @raise [IOError] if the stream is not open for reading
|
528
|
+
def lineno=(integer)
|
529
|
+
assert_readable
|
530
|
+
|
531
|
+
@lineno = ensure_integer(integer)
|
532
|
+
end
|
533
|
+
|
534
|
+
if RBVER_LT_3_0
|
535
|
+
##
|
536
|
+
# @deprecated Use {#each_line} instead.
|
537
|
+
#
|
538
|
+
# @version < Ruby 3.0
|
539
|
+
def lines(*args, &block)
|
540
|
+
warn('warning: IO#lines is deprecated; use #each_line instead')
|
541
|
+
each_line(*args, &block)
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
##
|
546
|
+
# @return [Integer] the number of bytes that can be read without blocking or
|
547
|
+
# `0` if unknown
|
548
|
+
#
|
549
|
+
# @raise [IOError] if the stream is not open for reading
|
550
|
+
def nread
|
551
|
+
assert_readable
|
552
|
+
|
553
|
+
unless delegate_r.character_io.buffer_empty?
|
554
|
+
raise IOError, 'byte oriented read for character buffered IO'
|
311
555
|
end
|
556
|
+
delegate_r.nread
|
557
|
+
end
|
558
|
+
|
559
|
+
##
|
560
|
+
# Returns the process ID of a child process associated with this stream, if
|
561
|
+
# any.
|
562
|
+
#
|
563
|
+
# @return [Integer] a process ID
|
564
|
+
# @return [nil] if there is no associated child process
|
565
|
+
#
|
566
|
+
# @raise [IOError] if the stream is closed
|
567
|
+
def pid
|
568
|
+
assert_open
|
569
|
+
return @pid unless nil == @pid
|
570
|
+
super
|
571
|
+
end
|
572
|
+
|
573
|
+
##
|
574
|
+
# @note This method will block if writing the stream blocks and there is data
|
575
|
+
# in the write buffer.
|
576
|
+
#
|
577
|
+
# @return [Integer] the current byte offset of the stream
|
578
|
+
#
|
579
|
+
# @raise [IOError] if the stream is closed
|
580
|
+
# @raise [Errno::ESPIPE] if the stream is not seekable
|
581
|
+
def pos
|
582
|
+
assert_open
|
583
|
+
|
584
|
+
flush
|
585
|
+
delegate.seek(0, IO::SEEK_CUR)
|
586
|
+
end
|
587
|
+
alias_method :tell, :pos
|
588
|
+
|
589
|
+
##
|
590
|
+
# Sets the position of the stream to the given byte offset.
|
591
|
+
#
|
592
|
+
# @param position [Integer] the byte offset to which the stream will be set
|
593
|
+
#
|
594
|
+
# @return [Integer] the given byte offset
|
595
|
+
#
|
596
|
+
# @raise [IOError] if the stream is closed
|
597
|
+
# @raise [Errno::ESPIPE] if the stream is not seekable
|
598
|
+
def pos=(position)
|
599
|
+
seek(position, IO::SEEK_SET)
|
600
|
+
position
|
601
|
+
end
|
602
|
+
|
603
|
+
##
|
604
|
+
# Reads at most `maxlen` bytes from the stream starting at `offset` without
|
605
|
+
# modifying the read position in the stream.
|
606
|
+
#
|
607
|
+
# @param maxlen [Integer] the maximum number of bytes to read
|
608
|
+
# @param offset [Integer] the offset from the beginning of the stream at which
|
609
|
+
# to begin reading
|
610
|
+
# @param buffer [String] if provided, a buffer into which the bytes should be
|
611
|
+
# placed
|
612
|
+
#
|
613
|
+
# @return [String] a new String containing the bytes read if `buffer` is `nil`
|
614
|
+
# or `buffer` if provided
|
615
|
+
#
|
616
|
+
# @raise [EOFError] when reading at the end of the stream
|
617
|
+
# @raise [IOError] if the stream is not readable
|
618
|
+
def pread(maxlen, offset, buffer = nil)
|
619
|
+
maxlen = ensure_integer(maxlen)
|
620
|
+
raise ArgumentError, 'negative string size (or size too big)' if maxlen < 0
|
621
|
+
buffer = nil == buffer ? ''.b : ensure_string(buffer)
|
622
|
+
|
623
|
+
return buffer if maxlen == 0
|
312
624
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
# Raises IOError if #closed? returns +true+. Raises IOError unless
|
321
|
-
# #writable? returns +true+.
|
322
|
-
def flush_size
|
323
|
-
raise IOError, 'closed stream' if closed?
|
324
|
-
raise IOError, 'not opened for writing' unless writable?
|
325
|
-
|
326
|
-
@__io_like__flush_size ||= 4096
|
625
|
+
offset = ensure_integer(offset)
|
626
|
+
raise Errno::EINVAL if offset < 0
|
627
|
+
|
628
|
+
assert_readable
|
629
|
+
|
630
|
+
if maxlen > buffer.bytesize
|
631
|
+
buffer << "\0" * (maxlen - buffer.bytesize)
|
327
632
|
end
|
633
|
+
bytes_read = delegate_r.pread(maxlen, offset, buffer: buffer)
|
634
|
+
buffer.slice!(bytes_read..-1)
|
635
|
+
|
636
|
+
buffer
|
637
|
+
end
|
328
638
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
639
|
+
##
|
640
|
+
# Writes the given object(s), if any, to the stream using {#write}.
|
641
|
+
#
|
642
|
+
# If no objects are given, `$_` is written. The field separator (`$,`) is
|
643
|
+
# written between successive objects if it is not `nil`. The output record
|
644
|
+
# separator (`$\`) is written after all other data if it is not `nil`.
|
645
|
+
#
|
646
|
+
# @param args [Array<Object>] zero or more objects to write to the stream
|
647
|
+
#
|
648
|
+
# @return [nil]
|
649
|
+
#
|
650
|
+
# @raise [IOError] if the stream is not open for writing
|
651
|
+
def print(*args)
|
652
|
+
# NOTE:
|
653
|
+
# Through Ruby 3.1, $_ is always nil on entry to a Ruby method. This
|
654
|
+
# assignment is kept in case that ever changes.
|
655
|
+
args << $_ if args.empty?
|
656
|
+
first_arg = true
|
657
|
+
args.each do |arg|
|
658
|
+
# Write a field separator before writing each argument after the first
|
659
|
+
# one unless no field separator is specified.
|
660
|
+
if first_arg
|
661
|
+
first_arg = false
|
662
|
+
else
|
663
|
+
write($,)
|
344
664
|
end
|
345
|
-
@__io_like__flush_size = flush_size
|
346
|
-
end
|
347
665
|
|
348
|
-
|
349
|
-
# ios.getc -> nil or integer
|
350
|
-
#
|
351
|
-
# Calls #readchar and either returns the result or +nil+ if #readchar raises
|
352
|
-
# EOFError.
|
353
|
-
#
|
354
|
-
# Raises IOError if #closed? returns +true+. Raises IOError unless
|
355
|
-
# #readable? returns +true+. Raises all errors raised by #unbuffered_read
|
356
|
-
# except for EOFError.
|
357
|
-
#
|
358
|
-
# <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
|
359
|
-
# #unbuffered_read. Therefore, this method always blocks. Aside from that
|
360
|
-
# exception and the conversion of EOFError results into +nil+ results, this
|
361
|
-
# method will also raise the same errors and block at the same times as
|
362
|
-
# #unbuffered_read.
|
363
|
-
def getc
|
364
|
-
readchar
|
365
|
-
rescue EOFError
|
366
|
-
nil
|
666
|
+
write(arg)
|
367
667
|
end
|
368
668
|
|
369
|
-
#
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
669
|
+
# Write the output record separator if one is specified.
|
670
|
+
write($\) if $\
|
671
|
+
nil
|
672
|
+
end
|
673
|
+
|
674
|
+
##
|
675
|
+
# Writes the String returned by calling `Kernel.sprintf` using the given
|
676
|
+
# arguments.
|
677
|
+
#
|
678
|
+
# @param args [Array] arguments to pass to `Kernel.sprintf`
|
679
|
+
#
|
680
|
+
# @return [nil]
|
681
|
+
#
|
682
|
+
# @raise [IOError] if the stream is not open for writing
|
683
|
+
def printf(*args)
|
684
|
+
write(sprintf(*args))
|
685
|
+
nil
|
686
|
+
end
|
687
|
+
|
688
|
+
##
|
689
|
+
# If `obj` is a String, write the first character; otherwise, convert `obj` to
|
690
|
+
# an Integer using the `Integer` method and write the low order byte.
|
691
|
+
#
|
692
|
+
# @param obj [String, Numeric] the character to be written
|
693
|
+
#
|
694
|
+
# @return [obj] the given parameter
|
695
|
+
#
|
696
|
+
# @raise [TypeError] if `obj` is not a String nor convertable to a Numeric
|
697
|
+
# type
|
698
|
+
# @raise [IOError] if the stream is not open for writing
|
699
|
+
def putc(obj)
|
700
|
+
char = case obj
|
701
|
+
when String
|
702
|
+
obj[0]
|
703
|
+
else
|
704
|
+
[ensure_integer(obj)].pack('V')[0]
|
705
|
+
end
|
706
|
+
write(char)
|
707
|
+
obj
|
708
|
+
end
|
709
|
+
|
710
|
+
##
|
711
|
+
# Writes the given object(s), if any, to the stream.
|
712
|
+
#
|
713
|
+
# Uses {#write} after converting objects to strings using their `to_s`
|
714
|
+
# methods. Unlike {#print}, Array instances are recursively processed. The
|
715
|
+
# record separator character (`$\`) is written after each object which does
|
716
|
+
# not end with the record separator already.
|
717
|
+
#
|
718
|
+
# If no objects are given, a single record separator is written.
|
719
|
+
#
|
720
|
+
# @param args [Array<Object>] zero or more objects to write to the stream
|
721
|
+
#
|
722
|
+
# @return [nil]
|
723
|
+
#
|
724
|
+
# @raise [IOError] if the stream is not open for writing
|
725
|
+
def puts(*args)
|
726
|
+
# Write only the record separator if no arguments are given.
|
727
|
+
if args.length == 0
|
728
|
+
write(ORS)
|
729
|
+
return
|
398
730
|
end
|
399
731
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
732
|
+
flatten_puts(args)
|
733
|
+
nil
|
734
|
+
end
|
735
|
+
|
736
|
+
##
|
737
|
+
# Writes at most `string.to_s.length` bytes to the stream starting at `offset`
|
738
|
+
# without modifying the write position in the stream.
|
739
|
+
#
|
740
|
+
# @param string [String] the bytes to write (encoding assumed to be binary)
|
741
|
+
# @param offset [Integer] the offset from the beginning of the stream at which
|
742
|
+
# to begin writing
|
743
|
+
#
|
744
|
+
# @return [Integer] the number of bytes written
|
745
|
+
#
|
746
|
+
# @raise [IOError] if the stream is not writable
|
747
|
+
def pwrite(string, offset)
|
748
|
+
string = string.to_s
|
749
|
+
|
750
|
+
offset = ensure_integer(offset)
|
751
|
+
raise Errno::EINVAL if offset < 0
|
752
|
+
|
753
|
+
assert_writable
|
754
|
+
|
755
|
+
delegate_w.pwrite(string, offset)
|
756
|
+
end
|
757
|
+
|
758
|
+
##
|
759
|
+
# Reads data from the stream.
|
760
|
+
#
|
761
|
+
# If `length` is specified as a positive integer, at most `length` bytes are
|
762
|
+
# returned. Truncated data will occur if there is insufficient data left to
|
763
|
+
# fulfill the request. If the read starts at the end of data, `nil` is
|
764
|
+
# returned.
|
765
|
+
#
|
766
|
+
# If `length` is unspecified or `nil`, an attempt to return all remaining data
|
767
|
+
# is made. Partial data will be returned if a low-level error is raised after
|
768
|
+
# some data is retrieved. If no data would be returned at all, an empty
|
769
|
+
# String is returned.
|
770
|
+
#
|
771
|
+
# If `buffer` is specified, it will be converted to a String using its
|
772
|
+
# `to_str` method if necessary and will be filled with the returned data if
|
773
|
+
# any.
|
774
|
+
#
|
775
|
+
# @param length [Integer] the number of bytes to read
|
776
|
+
# @param buffer [String] the location into which data will be stored
|
777
|
+
#
|
778
|
+
# @return [String] the data read from the stream
|
779
|
+
# @return [nil] if `length` is non-zero but no data is left in the stream
|
780
|
+
#
|
781
|
+
# @raise [ArgumentError] if `length` is less than 0
|
782
|
+
# @raise [IOError] if the stream is not open for reading
|
783
|
+
def read(length = nil, buffer = nil)
|
784
|
+
length = ensure_integer(length) if nil != length
|
785
|
+
if nil != length && length < 0
|
786
|
+
raise ArgumentError, "negative length #{length} given"
|
409
787
|
end
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
788
|
+
buffer = ensure_string(buffer) unless nil == buffer
|
789
|
+
|
790
|
+
assert_readable
|
791
|
+
|
792
|
+
unless length
|
793
|
+
content = begin
|
794
|
+
delegate_r.character_io.read_all
|
795
|
+
rescue EOFError
|
796
|
+
''.encode(
|
797
|
+
internal_encoding ||
|
798
|
+
external_encoding ||
|
799
|
+
Encoding.default_external
|
800
|
+
)
|
801
|
+
end
|
802
|
+
return content unless buffer
|
803
|
+
return buffer.replace(content)
|
426
804
|
end
|
427
805
|
|
428
|
-
|
429
|
-
|
430
|
-
#
|
431
|
-
# Sets the current line number to the given value. <tt>$.</tt> is updated
|
432
|
-
# by the _next_ call to #gets. If the object given is not an integer, it is
|
433
|
-
# converted to one using its to_int method.
|
434
|
-
#
|
435
|
-
# Raises IOError if #closed? returns +true+. Raises IOError unless
|
436
|
-
# #readable? returns +true+.
|
437
|
-
def lineno=(integer)
|
438
|
-
raise IOError, 'closed stream' if closed?
|
439
|
-
raise IOError, 'not opened for reading' unless readable?
|
440
|
-
if integer.nil? then
|
441
|
-
raise TypeError, 'no implicit conversion from nil to integer'
|
442
|
-
elsif ! integer.respond_to?(:to_int) then
|
443
|
-
raise TypeError, "can't convert #{integer.class} into Integer"
|
444
|
-
end
|
445
|
-
@__io_like__lineno = integer.to_int
|
806
|
+
unless delegate_r.character_io.buffer_empty?
|
807
|
+
raise IOError, 'byte oriented read for character buffered IO'
|
446
808
|
end
|
447
809
|
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
810
|
+
content = read_bytes(length)
|
811
|
+
if buffer
|
812
|
+
orig_encoding = buffer.encoding
|
813
|
+
buffer.replace(content)
|
814
|
+
buffer.force_encoding(orig_encoding)
|
815
|
+
content = buffer
|
454
816
|
end
|
455
817
|
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
818
|
+
return nil if content.empty? && length > 0
|
819
|
+
return content
|
820
|
+
end
|
821
|
+
|
822
|
+
##
|
823
|
+
# Reads and returns at most `length` bytes from the stream.
|
824
|
+
#
|
825
|
+
# If the internal read buffer is **not** empty, only the buffer is used, even
|
826
|
+
# if less than `length` bytes are available. If the internal buffer **is**
|
827
|
+
# empty, sets non-blocking mode via {#nonblock=} and then reads from the
|
828
|
+
# underlying stream.
|
829
|
+
#
|
830
|
+
# @param length [Integer] the number of bytes to read
|
831
|
+
# @param buffer [String] the location in which to store the data
|
832
|
+
# @param exception [Boolean] when `true` causes this method to raise
|
833
|
+
# exceptions when no data is available; otherwise, symbols are returned
|
834
|
+
#
|
835
|
+
# @return [String] the data read from the stream
|
836
|
+
# @return [:wait_readable, :wait_writable] if `exception` is `false` and no
|
837
|
+
# data is available
|
838
|
+
# @return [nil] if `exception` is `false` and reading begins at the end of the
|
839
|
+
# stream
|
840
|
+
#
|
841
|
+
# @raise [EOFError] if reading begins at the end of the stream
|
842
|
+
# @raise [IOError] if the stream is not open for reading
|
843
|
+
# @raise [IO::EWOULDBLOCKWaitReadable, IO::EWOULDBLOCKWaitWritable] if
|
844
|
+
# `exception` is `true` and no data is available
|
845
|
+
# @raise [Errno::EBADF] if non-blocking mode is not supported
|
846
|
+
# @raise [SystemCallError] if there are low level errors
|
847
|
+
def read_nonblock(length, buffer = nil, exception: true)
|
848
|
+
length = ensure_integer(length)
|
849
|
+
raise ArgumentError, 'length must be at least 0' if length < 0
|
850
|
+
buffer = ensure_string(buffer) if nil != buffer
|
851
|
+
|
852
|
+
assert_readable
|
853
|
+
|
854
|
+
if RBVER_LT_3_0_4 && length == 0
|
855
|
+
return (buffer || ''.b)
|
472
856
|
end
|
473
857
|
|
474
|
-
|
475
|
-
|
476
|
-
#
|
477
|
-
# Returns the current offest of ios.
|
478
|
-
#
|
479
|
-
# Raises IOError if #closed? returns +true+. Raises Errno::ESPIPE unless
|
480
|
-
# #seekable? returns +true+.
|
481
|
-
#
|
482
|
-
# As a side effect, the internal write buffer is flushed unless this is
|
483
|
-
# a writable, non-duplexed object. This is for compatibility with the
|
484
|
-
# behavior of IO#pos.
|
485
|
-
#
|
486
|
-
# <b>NOTE:</b> Because this method relies on #unbuffered_seek and
|
487
|
-
# #unbuffered_write (when the internal write buffer is not empty), it will
|
488
|
-
# also raise the same errors and block at the same times as those functions.
|
489
|
-
def pos
|
490
|
-
# Flush the internal write buffer for writable, non-duplexed objects.
|
491
|
-
__io_like__buffered_flush if writable? && ! duplexed?
|
492
|
-
__io_like__buffered_seek(0, IO::SEEK_CUR)
|
858
|
+
unless delegate_r.character_io.buffer_empty?
|
859
|
+
raise IOError, 'byte oriented read for character buffered IO'
|
493
860
|
end
|
494
|
-
alias :tell :pos
|
495
|
-
|
496
|
-
# call-seq:
|
497
|
-
# ios.print([obj, ...]) -> nil
|
498
|
-
#
|
499
|
-
# Writes the given object(s), if any, to the stream using #write after
|
500
|
-
# converting them to strings by calling their _to_s_ methods. If no
|
501
|
-
# objects are given, <tt>$_</tt> is used. The field separator (<tt>$,</tt>)
|
502
|
-
# is written between successive objects if it is not +nil+. The output
|
503
|
-
# record separator (<tt>$\\</tt>) is written after all other data if it is
|
504
|
-
# not nil.
|
505
|
-
#
|
506
|
-
# Raises IOError if #closed? returns +true+. Raises IOError unless
|
507
|
-
# #writable? returns +true+.
|
508
|
-
#
|
509
|
-
# <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
|
510
|
-
# #unbuffered_write. Therefore, this method always blocks if unable to
|
511
|
-
# immediately write +[obj, ...]+ completely. Aside from that exception,
|
512
|
-
# this method will also raise the same errors and block at the same times as
|
513
|
-
# #unbuffered_write.
|
514
|
-
def print(*args)
|
515
|
-
args << $_ if args.empty?
|
516
|
-
first_arg = true
|
517
|
-
args.each do |arg|
|
518
|
-
# Write a field separator before writing each argument after the first
|
519
|
-
# one unless no field separator is specified.
|
520
|
-
if first_arg then
|
521
|
-
first_arg = false
|
522
|
-
elsif ! $,.nil? then
|
523
|
-
write($,)
|
524
|
-
end
|
525
861
|
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
write('nil')
|
530
|
-
else
|
531
|
-
write(arg)
|
532
|
-
end
|
862
|
+
result = ensure_buffer(length, buffer) do |binary_buffer|
|
863
|
+
unless delegate_r.buffered_io.read_buffer_empty?
|
864
|
+
next delegate_r.read(length, buffer: binary_buffer)
|
533
865
|
end
|
534
866
|
|
535
|
-
|
536
|
-
|
537
|
-
nil
|
867
|
+
self.nonblock = true
|
868
|
+
delegate_r.concrete_io.read(length, buffer: binary_buffer)
|
538
869
|
end
|
539
870
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
# immediately write its arguments completely. Aside from that exception,
|
552
|
-
# this method will also raise the same errors and block at the same times as
|
553
|
-
# #unbuffered_write.
|
554
|
-
def printf(*args)
|
555
|
-
write(sprintf(*args))
|
556
|
-
nil
|
871
|
+
case result
|
872
|
+
when String
|
873
|
+
# This means that a buffer was not given and that the delegate returned a
|
874
|
+
# buffer with the content.
|
875
|
+
return result
|
876
|
+
when Integer
|
877
|
+
# This means that a buffer was given and that the content is in the
|
878
|
+
# buffer.
|
879
|
+
return buffer
|
880
|
+
else
|
881
|
+
return nonblock_response(result, exception)
|
557
882
|
end
|
883
|
+
rescue EOFError
|
884
|
+
raise if exception
|
885
|
+
return nil
|
886
|
+
end
|
558
887
|
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
# #writable? returns +true+.
|
567
|
-
#
|
568
|
-
# <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
|
569
|
-
# #unbuffered_write. Therefore, this method always blocks if unable to
|
570
|
-
# immediately write _obj_ completely. Aside from that exception, this
|
571
|
-
# method will also raise the same errors and block at the same times as
|
572
|
-
# #unbuffered_write.
|
573
|
-
def putc(obj)
|
574
|
-
char = case obj
|
575
|
-
when String
|
576
|
-
obj[0].chr
|
577
|
-
else
|
578
|
-
[obj.to_int].pack('V')[0].chr
|
579
|
-
end
|
580
|
-
write(char)
|
581
|
-
obj
|
582
|
-
end
|
888
|
+
##
|
889
|
+
# @return [Integer] the next 8-bit byte (0..255) from the stream
|
890
|
+
#
|
891
|
+
# @raise [EOFError] if reading begins at the end of the stream
|
892
|
+
# @raise [IOError] if the stream is not open for reading
|
893
|
+
def readbyte
|
894
|
+
assert_readable
|
583
895
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
# is written after each object which does not end with the record separator
|
591
|
-
# already. If no objects are given, a single record separator is written.
|
592
|
-
#
|
593
|
-
# Raises IOError if #closed? returns +true+. Raises IOError unless
|
594
|
-
# #writable? returns +true+.
|
595
|
-
#
|
596
|
-
# <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
|
597
|
-
# #unbuffered_write. Therefore, this method always blocks if unable to
|
598
|
-
# immediately write +[obj, ...]+ completely. Aside from that exception,
|
599
|
-
# this method will also raise the same errors and block at the same times as
|
600
|
-
# #unbuffered_write.
|
601
|
-
#
|
602
|
-
# <b>NOTE:</b> In order to be compatible with IO#puts, the record separator
|
603
|
-
# is currently hardcoded to be a single newline (<tt>"\n"</tt>) even though
|
604
|
-
# the documentation implies that the output record separator (<tt>$\\</tt>)
|
605
|
-
# should be used.
|
606
|
-
def puts(*args)
|
607
|
-
# Set the output record separator such that this method is compatible with
|
608
|
-
# IO#puts.
|
609
|
-
ors = "\n"
|
610
|
-
|
611
|
-
# Write only the record separator if no arguments are given.
|
612
|
-
if args.length == 0 then
|
613
|
-
write(ors)
|
614
|
-
return
|
615
|
-
end
|
896
|
+
unless delegate_r.character_io.buffer_empty?
|
897
|
+
raise IOError, 'byte oriented read for character buffered IO'
|
898
|
+
end
|
899
|
+
byte = delegate_r.read(1)
|
900
|
+
byte[0].ord
|
901
|
+
end
|
616
902
|
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
arg.to_s
|
625
|
-
line += ors if line.index(ors, -ors.length).nil?
|
626
|
-
write(line)
|
627
|
-
end
|
903
|
+
##
|
904
|
+
# @return [String] the next character from the stream
|
905
|
+
#
|
906
|
+
# @raise [EOFError] if reading begins at the end of the stream
|
907
|
+
# @raise [IOError] if the stream is not open for reading
|
908
|
+
def readchar
|
909
|
+
assert_readable
|
628
910
|
|
629
|
-
|
630
|
-
|
911
|
+
delegate_r.character_io.read_char
|
912
|
+
end
|
631
913
|
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
914
|
+
##
|
915
|
+
# Returns the next line from the stream.
|
916
|
+
#
|
917
|
+
# @overload readline(separator = $/, limit = nil, chomp: false)
|
918
|
+
#
|
919
|
+
# @param separator [String, nil] a non-empty String that separates each
|
920
|
+
# line, an empty String that equates to 2 or more successive newlines as
|
921
|
+
# the separator, or `nil` to indicate reading all remaining data
|
922
|
+
# @param limit [Integer, nil] an Integer limiting the number of bytes
|
923
|
+
# returned in each line or `nil` to indicate no limit
|
924
|
+
# @param chomp [Boolean] when `true` trailing newlines and carriage returns
|
925
|
+
# will be removed from each line
|
926
|
+
#
|
927
|
+
# @return [String] the next line in the stream
|
928
|
+
#
|
929
|
+
# @overload readline(limit, chomp: false)
|
930
|
+
#
|
931
|
+
# @param limit [Integer] an Integer limiting the number of bytes returned in
|
932
|
+
# each line or `nil` to indicate no limit
|
933
|
+
# @param chomp [Boolean] when `true` trailing newlines and carriage returns
|
934
|
+
# will be removed from each line
|
935
|
+
#
|
936
|
+
# @return [String] the next line in the stream where the separator is `$/`
|
937
|
+
#
|
938
|
+
# @raise [EOFError] if reading begins at the end of the stream
|
939
|
+
# @raise [IOError] if the stream is not open for reading
|
940
|
+
def readline(*args, **opts)
|
941
|
+
separator, limit = parse_readline_args(*args)
|
942
|
+
chomp = opts.fetch(:chomp, false)
|
943
|
+
|
944
|
+
assert_readable
|
945
|
+
|
946
|
+
discard_newlines = false
|
947
|
+
encoding =
|
948
|
+
internal_encoding || external_encoding || Encoding.default_external
|
949
|
+
|
950
|
+
if separator
|
951
|
+
# Reading with a record separator is performed using bytes rather than
|
952
|
+
# characters, so ensure that the separator is correctly encoded to make
|
953
|
+
# this possible.
|
954
|
+
if separator.empty?
|
955
|
+
# Read by paragraph is requested. The separator is 2 newline characters
|
956
|
+
# in the encoding of the character reader.
|
957
|
+
discard_newlines = true
|
958
|
+
separator = "\n\n"
|
959
|
+
separator = separator.b if RBVER_LT_3_4
|
960
|
+
elsif $/.equal?(separator)
|
961
|
+
# When using the default record separator character, convert it into the
|
962
|
+
# encoding of the character reader.
|
963
|
+
separator = separator.encode(encoding)
|
964
|
+
elsif ! (separator.encoding == encoding ||
|
965
|
+
(separator.ascii_only? && encoding.ascii_compatible?))
|
966
|
+
# Raise an error when the separator encoding doesn't match the reader
|
967
|
+
# encoding and ASCII compatibility is not available.
|
968
|
+
#
|
969
|
+
# NOTE:
|
970
|
+
# We should probably attempt to convert the encoding of the separator
|
971
|
+
# into the encoding of the reader before raising this error, but MRI
|
972
|
+
# doesn't appear to do that.
|
973
|
+
raise ArgumentError,
|
974
|
+
'encoding mismatch: %s IO with %s RS' % [encoding, separator.encoding]
|
683
975
|
end
|
684
|
-
buffer
|
685
976
|
end
|
686
977
|
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
#
|
695
|
-
|
696
|
-
#
|
697
|
-
|
698
|
-
#
|
699
|
-
#
|
700
|
-
#
|
701
|
-
#
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
978
|
+
buffer = delegate_r.character_io.read_line(
|
979
|
+
separator: separator,
|
980
|
+
limit: limit,
|
981
|
+
chomp: chomp,
|
982
|
+
discard_newlines: discard_newlines
|
983
|
+
)
|
984
|
+
|
985
|
+
# Increment the number of times this method has returned a "line".
|
986
|
+
self.lineno += 1
|
987
|
+
# Set the last line number in the global.
|
988
|
+
$. = lineno
|
989
|
+
# Set the last read line in the global and return it.
|
990
|
+
# NOTE:
|
991
|
+
# Through Ruby 3.3, assigning to $_ has no effect outside of a method that
|
992
|
+
# does it. This assignment is kept in case that ever changes.
|
993
|
+
$_ = buffer
|
994
|
+
end
|
995
|
+
|
996
|
+
##
|
997
|
+
# @overload readlines(separator = $/, limit = nil, chomp: false)
|
998
|
+
#
|
999
|
+
# @param separator [String, nil] a non-empty String that separates each
|
1000
|
+
# line, an empty String that equates to 2 or more successive newlines as
|
1001
|
+
# the separator, or `nil` to indicate reading all remaining data
|
1002
|
+
# @param limit [Integer, nil] an Integer limiting the number of bytes
|
1003
|
+
# returned in each line or `nil` to indicate no limit
|
1004
|
+
# @param chomp [Boolean] when `true` trailing newlines and carriage returns
|
1005
|
+
# will be removed from each line
|
1006
|
+
#
|
1007
|
+
# @return [Array<String>] the remaining lines in the stream
|
1008
|
+
#
|
1009
|
+
# @overload readlines(limit, chomp: false)
|
1010
|
+
#
|
1011
|
+
# @param limit [Integer] an Integer limiting the number of bytes returned in
|
1012
|
+
# each line or `nil` to indicate no limit
|
1013
|
+
# @param chomp [Boolean] when `true` trailing newlines and carriage returns
|
1014
|
+
# will be removed from each line
|
1015
|
+
#
|
1016
|
+
# @return [Array<String>] the remaining lines in the stream where the
|
1017
|
+
# separator is `$/`
|
1018
|
+
#
|
1019
|
+
# @raise [IOError] if the stream is not open for reading
|
1020
|
+
def readlines(*args, **opts)
|
1021
|
+
each_line(*args, **opts).to_a
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
##
|
1025
|
+
# Reads and returns at most `length` bytes from the stream.
|
1026
|
+
#
|
1027
|
+
# If the internal read buffer is **not** empty, only the buffer is used, even
|
1028
|
+
# if less than `length` bytes are available. If the internal buffer **is**
|
1029
|
+
# empty, reads from the underlying stream.
|
1030
|
+
#
|
1031
|
+
# @param length [Integer] the number of bytes to read
|
1032
|
+
# @param buffer [String] the location in which to store the data
|
1033
|
+
#
|
1034
|
+
# @return [String] the data read from the stream
|
1035
|
+
#
|
1036
|
+
# @raise [EOFError] if reading begins at the end of the stream
|
1037
|
+
# @raise [IOError] if the stream is not open for reading
|
1038
|
+
def readpartial(length, buffer = nil)
|
1039
|
+
length = ensure_integer(length)
|
1040
|
+
raise ArgumentError, 'length must be at least 0' if length < 0
|
1041
|
+
buffer = ensure_string(buffer) if nil != buffer
|
1042
|
+
|
1043
|
+
assert_readable
|
1044
|
+
|
1045
|
+
if RBVER_LT_3_0_4 && length == 0
|
1046
|
+
return (buffer || ''.b)
|
706
1047
|
end
|
707
1048
|
|
708
|
-
|
709
|
-
|
710
|
-
#
|
711
|
-
# Returns +true+ if the stream is both open and readable, +false+ otherwise.
|
712
|
-
#
|
713
|
-
# This implementation checks to see if #unbuffered_read is defined in order
|
714
|
-
# to make its determination. Override this if the implementing class always
|
715
|
-
# provides the #unbuffered_read method but may not always be open in a
|
716
|
-
# readable mode.
|
717
|
-
def readable?
|
718
|
-
! __io_like__closed_read? && respond_to?(:unbuffered_read, true)
|
1049
|
+
unless delegate_r.character_io.buffer_empty?
|
1050
|
+
raise IOError, 'byte oriented read for character buffered IO'
|
719
1051
|
end
|
720
1052
|
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
# Reads and returns _length_ bytes from the data stream.
|
725
|
-
#
|
726
|
-
# Raises EOFError if reading begins at the end of the stream. Raises
|
727
|
-
# IOError if #closed? returns +true+. Raises IOError unless #readable?
|
728
|
-
# returns +true+. Raises TruncatedDataError if insufficient data is
|
729
|
-
# immediately available to satisfy the request.
|
730
|
-
#
|
731
|
-
# In the case of TruncatedDataError being raised, the retrieved data can be
|
732
|
-
# fetched from the _data_ attribute of the exception.
|
733
|
-
#
|
734
|
-
# This method is basically copied from IO#readbytes.
|
735
|
-
#
|
736
|
-
# <b>NOTE:</b> Because this method relies on #unbuffered_read, it will also
|
737
|
-
# raise the same errors and block at the same times as that function.
|
738
|
-
def readbytes(length)
|
739
|
-
buffer = read(length)
|
740
|
-
if buffer.nil? then
|
741
|
-
raise EOFError, "end of file reached"
|
1053
|
+
result = ensure_buffer(length, buffer) do |binary_buffer|
|
1054
|
+
unless delegate_r.buffered_io.read_buffer_empty?
|
1055
|
+
next delegate_r.read(length, buffer: binary_buffer)
|
742
1056
|
end
|
743
|
-
if buffer.length < length then
|
744
|
-
raise TruncatedDataError.new("data truncated", buffer)
|
745
|
-
end
|
746
|
-
buffer
|
747
|
-
end
|
748
1057
|
|
749
|
-
|
750
|
-
# ios.readchar -> integer
|
751
|
-
#
|
752
|
-
# Returns the next 8-bit byte (0..255) from the stream.
|
753
|
-
#
|
754
|
-
# Raises EOFError when there is no more data in the stream. Raises IOError
|
755
|
-
# if #closed? returns +true+. Raises IOError unless #readable? returns
|
756
|
-
# +true+.
|
757
|
-
#
|
758
|
-
# <b>NOTE:</b> This method ignores Errno::EAGAIN and Errno::EINTR raised by
|
759
|
-
# #unbuffered_read. Therefore, this method always blocks. Aside from that
|
760
|
-
# exception, this method will also raise the same errors and block at the
|
761
|
-
# same times as #unbuffered_read.
|
762
|
-
def readchar
|
763
|
-
__io_like__buffered_read(1)[0]
|
764
|
-
rescue Errno::EAGAIN, Errno::EINTR
|
765
|
-
retry if read_ready?
|
1058
|
+
delegate_r.blocking_io.read(length, buffer: binary_buffer)
|
766
1059
|
end
|
767
1060
|
|
768
|
-
#
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
# this method will raise the same errors and block at the same times as
|
804
|
-
# #unbuffered_read.
|
805
|
-
def readline(sep_string = $/)
|
806
|
-
# Ensure that sep_string is either nil or a String.
|
807
|
-
unless sep_string.nil? || sep_string.kind_of?(String) then
|
808
|
-
sep_string = sep_string.to_str
|
809
|
-
end
|
1061
|
+
# The delegate returns the read content unless a buffer is given.
|
1062
|
+
return nil == buffer ? result : buffer
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
##
|
1066
|
+
# @overload reopen(other)
|
1067
|
+
# @param other [Like] another IO::Like instance whose delegate(s) will be
|
1068
|
+
# dup'd and used as this stream's delegate(s)
|
1069
|
+
#
|
1070
|
+
# @raise [IOError] if this instance is closed
|
1071
|
+
#
|
1072
|
+
# @overload reopen(io)
|
1073
|
+
# @param io [IO, #to_io] an IO instance that will be dup'd and used as this
|
1074
|
+
# stream's delegate
|
1075
|
+
#
|
1076
|
+
# @raise [IOError] if this instance or `io` are closed
|
1077
|
+
#
|
1078
|
+
# @overload reopen(path, mode, **opt)
|
1079
|
+
# @param path [String] path to a file to open and use as a delegate for this
|
1080
|
+
# stream
|
1081
|
+
# @param mode [String] file open mode as used by `File.open`, defaults to a
|
1082
|
+
# mode equivalent to this stream's current read/writ-ability
|
1083
|
+
# @param opts [Hash] options hash as used by `File.open`
|
1084
|
+
#
|
1085
|
+
# @raise all errors raised by `File.open`
|
1086
|
+
#
|
1087
|
+
# Replaces the delegate(s) of this stream with another instance's delegate(s)
|
1088
|
+
# or an IO instance.
|
1089
|
+
#
|
1090
|
+
# @return [self]
|
1091
|
+
def reopen(*args, **opts)
|
1092
|
+
unless args.size == 1 || args.size == 2
|
1093
|
+
raise ArgumentError,
|
1094
|
+
"wrong number of arguments (given #{args.size}, expected 1..2)"
|
1095
|
+
end
|
810
1096
|
|
811
|
-
|
1097
|
+
if args.size == 1
|
812
1098
|
begin
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
# consume and discard all newlines remaining at the front of the
|
838
|
-
# input.
|
839
|
-
while char == "\n" && (char = __io_like__buffered_read(1)) do
|
840
|
-
nil
|
841
|
-
end
|
842
|
-
# Put back the last character.
|
843
|
-
ungetc(char[0])
|
844
|
-
end
|
845
|
-
rescue Errno::EAGAIN, Errno::EINTR
|
846
|
-
retry if read_ready?
|
847
|
-
end
|
1099
|
+
io = args[0]
|
1100
|
+
io = args[0].to_io unless IO::Like === io
|
1101
|
+
|
1102
|
+
if IO::Like === io
|
1103
|
+
assert_open
|
1104
|
+
new_delegate_r = io.delegate_r.concrete_io.dup
|
1105
|
+
new_delegate_w = io.duplexed? ? io.delegate_w.concrete_io.dup : new_delegate_r
|
1106
|
+
close
|
1107
|
+
initialize(
|
1108
|
+
new_delegate_r,
|
1109
|
+
new_delegate_w,
|
1110
|
+
binmode: io.binmode?,
|
1111
|
+
internal_encoding: delegate_r.character_io.internal_encoding,
|
1112
|
+
external_encoding: delegate_r.character_io.external_encoding,
|
1113
|
+
sync: io.sync,
|
1114
|
+
pid: io.pid,
|
1115
|
+
pipeline_class: @pipeline_class
|
1116
|
+
)
|
1117
|
+
return self
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
unless IO === io
|
1121
|
+
raise TypeError,
|
1122
|
+
"can't convert #{args[0].class} to IO (#{args[0].class}#to_io gives #{io.class})"
|
848
1123
|
end
|
849
|
-
|
850
|
-
|
851
|
-
|
1124
|
+
|
1125
|
+
assert_open
|
1126
|
+
io = io.dup
|
1127
|
+
rescue NoMethodError
|
1128
|
+
mode = (readable? ? 'r' : 'w').dup
|
1129
|
+
mode << '+' if readable? && writable?
|
1130
|
+
mode << 'b'
|
1131
|
+
io = File.open(args[0], mode)
|
852
1132
|
end
|
853
|
-
|
854
|
-
|
855
|
-
buffer
|
1133
|
+
else
|
1134
|
+
io = File.open(*args, **opts)
|
856
1135
|
end
|
857
1136
|
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
#
|
872
|
-
# Raises EOFError when there is no more data in the stream. Raises IOError
|
873
|
-
# if #closed? returns +true+. Raises IOError unless #readable? returns
|
874
|
-
# +true+.
|
875
|
-
#
|
876
|
-
# <b>NOTE:</b> When _sep_string_ is not +nil+, this method ignores
|
877
|
-
# Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore,
|
878
|
-
# this method always blocks. Aside from that exception, this method will
|
879
|
-
# also raise the same errors and block at the same times as
|
880
|
-
# #unbuffered_read.
|
881
|
-
def readlines(sep_string = $/)
|
882
|
-
lines = []
|
883
|
-
each_line(sep_string) { |line| lines << line }
|
884
|
-
lines
|
885
|
-
end
|
1137
|
+
close
|
1138
|
+
initialize(
|
1139
|
+
IO::LikeHelpers::IOWrapper.new(io),
|
1140
|
+
binmode: io.binmode?,
|
1141
|
+
internal_encoding: delegate_r.character_io.internal_encoding,
|
1142
|
+
external_encoding: delegate_r.character_io.external_encoding,
|
1143
|
+
sync: io.sync,
|
1144
|
+
pid: io.pid,
|
1145
|
+
pipeline_class: @pipeline_class
|
1146
|
+
)
|
1147
|
+
|
1148
|
+
self
|
1149
|
+
end
|
886
1150
|
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
# immediately return _length_ bytes. Aside from that exception, this method
|
903
|
-
# will also raise the same errors and block at the same times as
|
904
|
-
# #unbuffered_read.
|
905
|
-
def readpartial(length, buffer = nil)
|
906
|
-
# Check the validity of the method arguments.
|
907
|
-
unless length >= 0 then
|
908
|
-
raise ArgumentError, "negative length #{length} given"
|
909
|
-
end
|
910
|
-
buffer = '' if buffer.nil?
|
911
|
-
# Flush the buffer.
|
912
|
-
buffer.slice!(0..-1)
|
913
|
-
|
914
|
-
# Read and return up to length bytes.
|
915
|
-
if __io_like__internal_read_buffer.empty? then
|
916
|
-
begin
|
917
|
-
buffer << __io_like__buffered_read(length)
|
918
|
-
rescue Errno::EAGAIN, Errno::EINTR
|
919
|
-
retry if read_ready?
|
920
|
-
end
|
921
|
-
else
|
922
|
-
raise IOError, 'closed stream' if closed?
|
923
|
-
raise IOError, 'not opened for reading' unless readable?
|
1151
|
+
##
|
1152
|
+
# Sets the position of the file pointer to the beginning of the stream.
|
1153
|
+
#
|
1154
|
+
# The `lineno` attribute is reset to `0` if successful and the stream is
|
1155
|
+
# readable.
|
1156
|
+
#
|
1157
|
+
# @return [0]
|
1158
|
+
#
|
1159
|
+
# @raise [IOError] if the stream is closed
|
1160
|
+
# @raise [Errno::ESPIPE] if the stream is not seekable
|
1161
|
+
def rewind
|
1162
|
+
seek(0, IO::SEEK_SET)
|
1163
|
+
self.lineno = 0 if readable?
|
1164
|
+
0
|
1165
|
+
end
|
924
1166
|
|
925
|
-
|
926
|
-
|
927
|
-
|
1167
|
+
##
|
1168
|
+
# Sets the current stream position to `amount` based on the setting of
|
1169
|
+
# `whence`.
|
1170
|
+
#
|
1171
|
+
# | `whence` | `amount` Interpretation |
|
1172
|
+
# | -------- | ----------------------- |
|
1173
|
+
# | `:CUR` or `IO::SEEK_CUR` | `amount` added to current stream position |
|
1174
|
+
# | `:END` or `IO::SEEK_END` | `amount` added to end of stream position (`amount` will usually be negative here) |
|
1175
|
+
# | `:SET` or `IO::SEEK_SET` | `amount` used as absolute position |
|
1176
|
+
#
|
1177
|
+
# @param amount [Integer] the amount to move the position in bytes
|
1178
|
+
# @param whence [Integer, Symbol] the position alias from which to consider
|
1179
|
+
# `amount`
|
1180
|
+
#
|
1181
|
+
# @return [0]
|
1182
|
+
#
|
1183
|
+
# @raise [IOError] if the stream is closed
|
1184
|
+
# @raise [Errno::ESPIPE] if the stream is not seekable
|
1185
|
+
def seek(amount, whence = IO::SEEK_SET)
|
1186
|
+
super
|
1187
|
+
# This also clears the byte oriented read buffer, so calling
|
1188
|
+
# delegate_r.buffered_io.flush would be redundant.
|
1189
|
+
delegate_r.character_io.clear
|
1190
|
+
0
|
1191
|
+
end
|
1192
|
+
|
1193
|
+
##
|
1194
|
+
# @overload set_encoding(encoding, **opts)
|
1195
|
+
# @param encoding [Encoding, String, nil] the external encoding or both the
|
1196
|
+
# external and internal encoding if specified as `"ext_enc:int_enc"`
|
1197
|
+
# @param opts [Hash] encoding conversion options used character or newline
|
1198
|
+
# conversion is performed
|
1199
|
+
#
|
1200
|
+
# @overload set_encoding(external, internal, **opts)
|
1201
|
+
# @param external [Encoding, String, nil] the external encoding
|
1202
|
+
# @param internal [Encoding, String, nil] the internal encoding
|
1203
|
+
# @param opts [Hash] encoding conversion options used character or newline
|
1204
|
+
# conversion is performed
|
1205
|
+
#
|
1206
|
+
# Sets the external and internal encodings of the stream.
|
1207
|
+
#
|
1208
|
+
# When the given external encoding is not `nil` or `Encoding::BINARY` or an
|
1209
|
+
# equivalent and the internal encoding is either not given or `nil`, the
|
1210
|
+
# current value of `Encoding.default_internal` is used for the internal
|
1211
|
+
# encoding.
|
1212
|
+
#
|
1213
|
+
# When the given external encoding is `nil` and the internal encoding is either
|
1214
|
+
# not given or `nil`, the current values of `Encoding.default_external` and
|
1215
|
+
# `Encoding.default_internal` are used, respectively, unless
|
1216
|
+
# `Encoding.default_external` is `Encoding::BINARY` or an equivalent **or**
|
1217
|
+
# `Encoding.default_internal` is `nil`, in which case `nil` is used for both.
|
1218
|
+
#
|
1219
|
+
# Setting the given internal encoding to `"-"` indicates no character
|
1220
|
+
# conversion should be performed. The internal encoding of the stream will be
|
1221
|
+
# set to `nil`. This is needed in cases where `Encoding.default_internal` is
|
1222
|
+
# not `nil` but character conversion is not desired.
|
1223
|
+
#
|
1224
|
+
# @return [self]
|
1225
|
+
#
|
1226
|
+
# @raise [TypeError] if the given external encoding is `nil` and the internal
|
1227
|
+
# encoding is given and **not** `nil`
|
1228
|
+
# @raise [ArgumentError] if an encoding given as a string is invalid
|
1229
|
+
def set_encoding(ext_enc, int_enc = nil, **opts)
|
1230
|
+
assert_open
|
1231
|
+
|
1232
|
+
# Check that any given newline option is valid.
|
1233
|
+
if opts.key?(:newline) &&
|
1234
|
+
! %i{cr lf crlf universal}.include?(opts[:newline])
|
1235
|
+
message = 'unexpected value for newline option'
|
1236
|
+
message += ": #{opts[:newline]}" if Symbol === opts[:newline]
|
1237
|
+
raise ArgumentError, message
|
928
1238
|
end
|
929
1239
|
|
930
|
-
#
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
#
|
937
|
-
# As a side effect, the internal read and write buffers are flushed.
|
938
|
-
#
|
939
|
-
# Raises IOError if #closed? returns +true+. Raises Errno::ESPIPE unless
|
940
|
-
# #seekable? returns +true+.
|
941
|
-
#
|
942
|
-
# <b>NOTE:</b> Because this method relies on #unbuffered_seek and
|
943
|
-
# #unbuffered_write (when the internal write buffer is not empty), it will
|
944
|
-
# also raise the same errors and block at the same times as those functions.
|
945
|
-
def rewind
|
946
|
-
seek(0, IO::SEEK_SET)
|
947
|
-
self.lineno = 0 if readable?
|
948
|
-
0
|
1240
|
+
# Newline handling is not allowed in binary mode.
|
1241
|
+
if binmode? &&
|
1242
|
+
(opts.key?(:newline) ||
|
1243
|
+
opts[:cr_newline] || opts[:crlf_newline] || opts[:lf_newline] ||
|
1244
|
+
opts[:universal_newline])
|
1245
|
+
raise ArgumentError, 'newline decorator with binary mode'
|
949
1246
|
end
|
950
1247
|
|
951
|
-
#
|
952
|
-
#
|
953
|
-
#
|
954
|
-
|
955
|
-
#
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
# <b>NOTE:</b> Because this method relies on #unbuffered_seek and
|
968
|
-
# #unbuffered_write (when the internal write buffer is not empty), it will
|
969
|
-
# also raise the same errors and block at the same times as those functions.
|
970
|
-
def seek(offset, whence = IO::SEEK_SET)
|
971
|
-
__io_like__buffered_seek(offset, whence)
|
972
|
-
0
|
1248
|
+
# Ruby 3.2 and below have a bug (#18899) handling the internal encoding
|
1249
|
+
# correctly when the external encoding is binary that only happens when they
|
1250
|
+
# are supplied individually to this method.
|
1251
|
+
bug_18899_compatibility = RBVER_LT_3_3
|
1252
|
+
# Convert the argument(s) into Encoding objects.
|
1253
|
+
if ! (nil == ext_enc || Encoding === ext_enc) && nil == int_enc
|
1254
|
+
string_arg = ensure_string(ext_enc)
|
1255
|
+
begin
|
1256
|
+
e, _, i = string_arg.rpartition(':')
|
1257
|
+
# Bug #18899 compatibility is unnecessary when the encodings are passed
|
1258
|
+
# together as a colon speparated string.
|
1259
|
+
ext_enc, int_enc, bug_18899_compatibility = e, i, false unless e.empty?
|
1260
|
+
rescue Encoding::CompatibilityError
|
1261
|
+
# This is caused by failure to split on colon when the string argument
|
1262
|
+
# is not ASCII compatible. Ignore it and use the argument as is.
|
1263
|
+
end
|
973
1264
|
end
|
974
1265
|
|
975
|
-
#
|
976
|
-
#
|
977
|
-
#
|
978
|
-
#
|
979
|
-
#
|
980
|
-
#
|
981
|
-
#
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
1266
|
+
# Potential values:
|
1267
|
+
# ext_enc int_enc
|
1268
|
+
# ======================
|
1269
|
+
# nil Object => error
|
1270
|
+
# nil nil => maybe copy default encodings
|
1271
|
+
# Object Object => use given encodings
|
1272
|
+
# Object nil => maybe copy default internal encoding
|
1273
|
+
if nil == ext_enc && nil == int_enc
|
1274
|
+
unless Encoding::BINARY == Encoding.default_external ||
|
1275
|
+
nil == Encoding.default_internal
|
1276
|
+
ext_enc = Encoding.default_external
|
1277
|
+
int_enc = Encoding.default_internal
|
1278
|
+
end
|
1279
|
+
else
|
1280
|
+
ext_enc = Encoding.find(ext_enc)
|
1281
|
+
int_enc = case int_enc
|
1282
|
+
when nil
|
1283
|
+
RBVER_LT_3_3 ? nil : Encoding.default_internal
|
1284
|
+
when '-'
|
1285
|
+
# Allows explicit request of no conversion when
|
1286
|
+
# Encoding.default_internal is set.
|
1287
|
+
nil
|
1288
|
+
else
|
1289
|
+
Encoding.find(int_enc)
|
1290
|
+
end
|
986
1291
|
end
|
987
1292
|
|
988
|
-
#
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
# false otherwise.
|
993
|
-
#
|
994
|
-
# Raises IOError if #closed? returns +true+.
|
995
|
-
def sync
|
996
|
-
raise IOError, 'closed stream' if closed?
|
997
|
-
@__io_like__sync ||= false
|
1293
|
+
# Ignore the chosen internal encoding when no conversion will be performed.
|
1294
|
+
if int_enc == ext_enc ||
|
1295
|
+
Encoding::BINARY == ext_enc && ! bug_18899_compatibility
|
1296
|
+
int_enc = nil
|
998
1297
|
end
|
999
1298
|
|
1000
|
-
#
|
1001
|
-
#
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
# operation. When set to +false+, the internal write buffer will be
|
1006
|
-
# enabled.
|
1007
|
-
#
|
1008
|
-
# Raises IOError if #closed? returns +true+.
|
1009
|
-
def sync=(sync)
|
1010
|
-
raise IOError, 'closed stream' if closed?
|
1011
|
-
@__io_like__sync = sync ? true : false
|
1299
|
+
# ASCII incompatible external encoding without conversion when reading
|
1300
|
+
# requires binmode.
|
1301
|
+
if ! binmode? && readable? && nil == int_enc &&
|
1302
|
+
! (ext_enc || Encoding.default_external).ascii_compatible?
|
1303
|
+
raise ArgumentError, 'ASCII incompatible encoding needs binmode'
|
1012
1304
|
end
|
1013
1305
|
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
# bypassing the internal read buffer.
|
1019
|
-
#
|
1020
|
-
# Returns <tt>""</tt> if _length_ is 0 regardless of the status of the data
|
1021
|
-
# stream. This is for compatibility with IO#sysread.
|
1022
|
-
#
|
1023
|
-
# Raises EOFError if reading begins at the end of the stream. Raises
|
1024
|
-
# IOError if the internal read buffer is not empty. Raises IOError if
|
1025
|
-
# #closed? returns +true+.
|
1026
|
-
#
|
1027
|
-
# <b>NOTE:</b> Because this method relies on #unbuffered_read, it will also
|
1028
|
-
# raise the same errors and block at the same times as that function.
|
1029
|
-
def sysread(length, buffer = nil)
|
1030
|
-
buffer = buffer.nil? ? '' : buffer.to_str
|
1031
|
-
buffer.slice!(0..-1) unless buffer.empty?
|
1032
|
-
return buffer if length == 0
|
1033
|
-
|
1034
|
-
raise IOError, 'closed stream' if closed?
|
1035
|
-
raise IOError, 'not opened for reading' unless readable?
|
1036
|
-
unless __io_like__internal_read_buffer.empty? then
|
1037
|
-
raise IOError, 'sysread on buffered IO'
|
1038
|
-
end
|
1306
|
+
delegate_r.character_io.set_encoding(ext_enc, int_enc, **opts)
|
1307
|
+
if duplexed?
|
1308
|
+
delegate_w.character_io.set_encoding(ext_enc, int_enc, **opts)
|
1309
|
+
end
|
1039
1310
|
|
1040
|
-
|
1041
|
-
|
1311
|
+
self
|
1312
|
+
end
|
1042
1313
|
|
1043
|
-
|
1314
|
+
##
|
1315
|
+
# Sets the external encoding of the stream based on a byte order mark (BOM)
|
1316
|
+
# in the next bytes of the stream if found or to `nil` if not found.
|
1317
|
+
#
|
1318
|
+
# @return [nil] if no byte order mark is found
|
1319
|
+
# @return [Encoding] the encoding indicated by the byte order mark
|
1320
|
+
#
|
1321
|
+
# @raise [ArgumentError] if the stream is not in binary mode, an internal
|
1322
|
+
# encoding is set, or the external encoding is set to anything other than
|
1323
|
+
# `Encoding::BINARY`
|
1324
|
+
#
|
1325
|
+
# @version \>= Ruby 2.7
|
1326
|
+
def set_encoding_by_bom
|
1327
|
+
unless binmode?
|
1328
|
+
raise ArgumentError, 'ASCII incompatible encoding needs binmode'
|
1329
|
+
end
|
1330
|
+
if nil != internal_encoding
|
1331
|
+
raise ArgumentError, 'encoding conversion is set'
|
1332
|
+
elsif nil != external_encoding && Encoding::BINARY != external_encoding
|
1333
|
+
raise ArgumentError, "encoding is set to #{external_encoding} already"
|
1044
1334
|
end
|
1045
1335
|
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
def sysseek(offset, whence = IO::SEEK_SET)
|
1062
|
-
raise IOError, 'closed stream' if closed?
|
1063
|
-
raise Errno::ESPIPE unless seekable?
|
1064
|
-
unless __io_like__internal_read_buffer.empty? then
|
1065
|
-
raise IOError, 'sysseek on buffered IO'
|
1336
|
+
return nil unless readable?
|
1337
|
+
|
1338
|
+
case b1 = getbyte
|
1339
|
+
when nil
|
1340
|
+
when 0xEF
|
1341
|
+
case b2 = getbyte
|
1342
|
+
when nil
|
1343
|
+
when 0xBB
|
1344
|
+
case b3 = getbyte
|
1345
|
+
when nil
|
1346
|
+
when 0xBF
|
1347
|
+
set_encoding(Encoding::UTF_8)
|
1348
|
+
return Encoding::UTF_8
|
1349
|
+
end
|
1350
|
+
ungetbyte(b3)
|
1066
1351
|
end
|
1067
|
-
|
1068
|
-
|
1352
|
+
ungetbyte(b2)
|
1353
|
+
when 0xFE
|
1354
|
+
case b2 = getbyte
|
1355
|
+
when nil
|
1356
|
+
when 0xFF
|
1357
|
+
set_encoding(Encoding::UTF_16BE)
|
1358
|
+
return Encoding::UTF_16BE
|
1069
1359
|
end
|
1070
|
-
|
1071
|
-
|
1360
|
+
ungetbyte(b2)
|
1361
|
+
when 0xFF
|
1362
|
+
case b2 = getbyte
|
1363
|
+
when nil
|
1364
|
+
when 0xFE
|
1365
|
+
case b3 = getbyte
|
1366
|
+
when nil
|
1367
|
+
when 0x00
|
1368
|
+
case b4 = getbyte
|
1369
|
+
when nil
|
1370
|
+
when 0x00
|
1371
|
+
set_encoding(Encoding::UTF_32LE)
|
1372
|
+
return Encoding::UTF_32LE
|
1373
|
+
end
|
1374
|
+
ungetbyte(b4)
|
1375
|
+
end
|
1376
|
+
ungetbyte(b3)
|
1377
|
+
set_encoding(Encoding::UTF_16LE)
|
1378
|
+
return Encoding::UTF_16LE
|
1379
|
+
end
|
1380
|
+
ungetbyte(b2)
|
1381
|
+
when 0x00
|
1382
|
+
case b2 = getbyte
|
1383
|
+
when nil
|
1384
|
+
when 0x00
|
1385
|
+
case b3 = getbyte
|
1386
|
+
when nil
|
1387
|
+
when 0xFE
|
1388
|
+
case b4 = getbyte
|
1389
|
+
when nil
|
1390
|
+
when 0xFF
|
1391
|
+
set_encoding(Encoding::UTF_32BE)
|
1392
|
+
return Encoding::UTF_32BE
|
1393
|
+
end
|
1394
|
+
ungetbyte(b4)
|
1395
|
+
end
|
1396
|
+
ungetbyte(b3)
|
1397
|
+
end
|
1398
|
+
ungetbyte(b2)
|
1072
1399
|
end
|
1400
|
+
ungetbyte(b1)
|
1073
1401
|
|
1074
|
-
|
1075
|
-
|
1076
|
-
#
|
1077
|
-
# Writes _string_ directly to the data stream, bypassing the internal write
|
1078
|
-
# buffer and returns the number of bytes written.
|
1079
|
-
#
|
1080
|
-
# As a side effect for non-duplex objects, the internal read buffer is
|
1081
|
-
# flushed.
|
1082
|
-
#
|
1083
|
-
# Raises IOError if #closed? returns +true+. Raises IOError unless
|
1084
|
-
# #writable? returns +true+.
|
1085
|
-
#
|
1086
|
-
# <b>NOTE:</b> Because this method relies on #unbuffered_write, it will also
|
1087
|
-
# raise the same errors and block at the same times as that function.
|
1088
|
-
def syswrite(string)
|
1089
|
-
raise IOError, 'closed stream' if closed?
|
1090
|
-
raise IOError, 'not opened for writing' unless writable?
|
1091
|
-
unless __io_like__internal_write_buffer.empty? then
|
1092
|
-
warn('warning: syswrite on buffered IO')
|
1093
|
-
end
|
1402
|
+
return nil
|
1403
|
+
end
|
1094
1404
|
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1405
|
+
##
|
1406
|
+
# Returns `true` if the internal write buffer is being bypassed and `false`
|
1407
|
+
# otherwise.
|
1408
|
+
#
|
1409
|
+
# @return [Boolean]
|
1410
|
+
#
|
1411
|
+
# @raise [IOError] if the stream is closed
|
1412
|
+
def sync
|
1413
|
+
assert_open
|
1414
|
+
delegate_w.character_io.sync?
|
1415
|
+
end
|
1101
1416
|
|
1102
|
-
|
1103
|
-
|
1417
|
+
##
|
1418
|
+
# When set to `true` the internal write buffer will be bypassed. Any data
|
1419
|
+
# currently in the buffer will be flushed prior to the next output operation.
|
1420
|
+
# When set to `false`, the internal write buffer will be enabled.
|
1421
|
+
#
|
1422
|
+
# @param sync [Boolean] the sync mode
|
1423
|
+
#
|
1424
|
+
# @return [Boolean] the given value for `sync`
|
1425
|
+
#
|
1426
|
+
# @raise [IOError] if the stream is closed
|
1427
|
+
def sync=(sync)
|
1428
|
+
assert_open
|
1429
|
+
delegate_w.character_io.sync = sync
|
1430
|
+
end
|
1104
1431
|
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1432
|
+
##
|
1433
|
+
# Reads and returns up to `length` bytes directly from the data stream,
|
1434
|
+
# bypassing the internal read buffer.
|
1435
|
+
#
|
1436
|
+
# If `buffer` is given, it is used to store the bytes that are read;
|
1437
|
+
# otherwise, a new buffer is created.
|
1438
|
+
#
|
1439
|
+
# Returns an empty String if `length` is `0` regardless of the status of the
|
1440
|
+
# data stream. This is for compatibility with `IO#sysread`.
|
1441
|
+
#
|
1442
|
+
# @param length [Integer] the number of bytes to read
|
1443
|
+
# @param buffer [String] a buffer into which bytes will be read
|
1444
|
+
#
|
1445
|
+
# @return [String] the bytes that were read
|
1446
|
+
#
|
1447
|
+
# @raise [EOFError] if reading begins at the end of the stream
|
1448
|
+
# @raise [IOError] if the internal read buffer is not empty
|
1449
|
+
# @raise [IOError] if the stream is not open for reading
|
1450
|
+
def sysread(length, buffer = nil)
|
1451
|
+
length = ensure_integer(length)
|
1452
|
+
raise ArgumentError, "negative length #{length} given" if length < 0
|
1453
|
+
buffer = ensure_string(buffer) unless nil == buffer
|
1454
|
+
|
1455
|
+
return (buffer || ''.b) if length == 0
|
1456
|
+
|
1457
|
+
assert_readable
|
1458
|
+
|
1459
|
+
if ! delegate_r.buffered_io.read_buffer_empty?
|
1460
|
+
raise IOError, 'sysread for buffered IO'
|
1461
|
+
elsif ! delegate_r.character_io.buffer_empty?
|
1462
|
+
raise IOError, 'byte oriented read for character buffered IO'
|
1111
1463
|
end
|
1112
1464
|
|
1113
|
-
|
1114
|
-
|
1115
|
-
#
|
1116
|
-
# Calls #unread with <tt>integer.chr</tt> as an argument.
|
1117
|
-
#
|
1118
|
-
# Raises IOError if #closed? returns +true+. Raises IOError unless
|
1119
|
-
# #readable? returns +true+.
|
1120
|
-
def ungetc(integer)
|
1121
|
-
unread(integer.chr)
|
1465
|
+
result = ensure_buffer(length, buffer) do |binary_buffer|
|
1466
|
+
delegate_r.blocking_io.read(length, buffer: binary_buffer)
|
1122
1467
|
end
|
1123
1468
|
|
1124
|
-
#
|
1125
|
-
|
1126
|
-
|
1127
|
-
# Pushes the given string onto the front of the internal read buffer and
|
1128
|
-
# returns +nil+. If _string_ is not a String, it is converted to one using
|
1129
|
-
# its +to_s+ method.
|
1130
|
-
#
|
1131
|
-
# Raises IOError if #closed? returns +true+. Raises IOError unless
|
1132
|
-
# #readable? returns +true+.
|
1133
|
-
def unread(string)
|
1134
|
-
raise IOError, 'closed stream' if closed?
|
1135
|
-
raise IOError, 'not opened for reading' unless readable?
|
1136
|
-
__io_like__internal_read_buffer.insert(0, string.to_s)
|
1137
|
-
nil
|
1138
|
-
end
|
1469
|
+
# The delegate returns the read content unless a buffer is given.
|
1470
|
+
return buffer ? buffer : result
|
1471
|
+
end
|
1139
1472
|
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1473
|
+
##
|
1474
|
+
# Sets the current, unbuffered stream position to `amount` based on the
|
1475
|
+
# setting of `whence`.
|
1476
|
+
#
|
1477
|
+
# | `whence` | `amount` Interpretation |
|
1478
|
+
# | -------- | ----------------------- |
|
1479
|
+
# | `:CUR` or `IO::SEEK_CUR` | `amount` added to current stream position |
|
1480
|
+
# | `:END` or `IO::SEEK_END` | `amount` added to end of stream position (`amount` will usually be negative here) |
|
1481
|
+
# | `:SET` or `IO::SEEK_SET` | `amount` used as absolute position |
|
1482
|
+
#
|
1483
|
+
# @param offset [Integer] the amount to move the position in bytes
|
1484
|
+
# @param whence [Integer, Symbol] the position alias from which to consider
|
1485
|
+
# `amount`
|
1486
|
+
#
|
1487
|
+
# @return [Integer] the new stream position
|
1488
|
+
#
|
1489
|
+
# @raise [IOError] if the internal read buffer is not empty
|
1490
|
+
# @raise [IOError] if the stream is closed
|
1491
|
+
# @raise [Errno::ESPIPE] if the stream is not seekable
|
1492
|
+
def sysseek(offset, whence = IO::SEEK_SET)
|
1493
|
+
assert_open
|
1494
|
+
if ! delegate_r.buffered_io.read_buffer_empty? ||
|
1495
|
+
! delegate_r.character_io.buffer_empty?
|
1496
|
+
raise IOError, 'sysseek for buffered IO'
|
1497
|
+
end
|
1498
|
+
unless delegate_w.buffered_io.write_buffer_empty?
|
1499
|
+
warn('warning: sysseek for buffered IO')
|
1159
1500
|
end
|
1160
1501
|
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1502
|
+
delegate.blocking_io.seek(offset, whence)
|
1503
|
+
end
|
1504
|
+
|
1505
|
+
##
|
1506
|
+
# Writes `string` directly to the data stream, bypassing the internal
|
1507
|
+
# write buffer.
|
1508
|
+
#
|
1509
|
+
# @param string [String] a string of bytes to be written
|
1510
|
+
#
|
1511
|
+
# @return [Integer] the number of bytes written
|
1512
|
+
#
|
1513
|
+
# @raise [IOError] if the stream is not open for writing
|
1514
|
+
def syswrite(string)
|
1515
|
+
assert_writable
|
1516
|
+
unless delegate_w.buffered_io.write_buffer_empty?
|
1517
|
+
warn('warning: syswrite for buffered IO')
|
1172
1518
|
end
|
1173
1519
|
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1520
|
+
delegate_w.buffered_io.flush || delegate_w.blocking_io.write(string.to_s.b)
|
1521
|
+
end
|
1522
|
+
|
1523
|
+
##
|
1524
|
+
# This is for compatibility with IO.
|
1525
|
+
alias_method :to_i, :fileno
|
1526
|
+
|
1527
|
+
##
|
1528
|
+
# @overload ungetbyte(string)
|
1529
|
+
# @param string [String] a string of bytes to push onto the internal read
|
1530
|
+
# buffer
|
1531
|
+
#
|
1532
|
+
# @overload ungetbyte(integer)
|
1533
|
+
# @param integer [Integer] a number whose low order byte will be pushed
|
1534
|
+
# onto the internal read buffer
|
1535
|
+
#
|
1536
|
+
# Pushes bytes onto the internal read buffer such that subsequent read
|
1537
|
+
# operations will return them first.
|
1538
|
+
#
|
1539
|
+
# @return [nil]
|
1540
|
+
#
|
1541
|
+
# @raise [IOError] if the stream is not open for reading
|
1542
|
+
# @raise [IOError] if the internal read buffer does not have enough space
|
1543
|
+
def ungetbyte(obj)
|
1544
|
+
assert_readable
|
1545
|
+
|
1546
|
+
return if nil == obj
|
1547
|
+
|
1548
|
+
string = case obj
|
1549
|
+
when String
|
1550
|
+
obj
|
1551
|
+
when Integer
|
1552
|
+
(obj & 255).chr
|
1553
|
+
else
|
1554
|
+
ensure_string(obj)
|
1555
|
+
end
|
1556
|
+
|
1557
|
+
delegate_r.character_io.unread(string.b)
|
1558
|
+
|
1559
|
+
nil
|
1560
|
+
end
|
1561
|
+
|
1562
|
+
##
|
1563
|
+
# @overload ungetc(string)
|
1564
|
+
# @param string [String] a string of characters to push onto the internal
|
1565
|
+
# read buffer
|
1566
|
+
#
|
1567
|
+
# @overload ungetc(integer)
|
1568
|
+
# @param integer [Integer] a number that will be converted into a character
|
1569
|
+
# using the stream's external encoding and pushed onto the internal read
|
1570
|
+
# buffer
|
1571
|
+
#
|
1572
|
+
# Pushes characters onto the internal read buffer such that subsequent read
|
1573
|
+
# operations will return them first.
|
1574
|
+
#
|
1575
|
+
# @return [nil]
|
1576
|
+
#
|
1577
|
+
# @raise [IOError] if the stream is not open for reading
|
1578
|
+
# @raise [IOError] if the internal read buffer does not have enough space
|
1579
|
+
def ungetc(string)
|
1580
|
+
assert_readable
|
1581
|
+
|
1582
|
+
return if nil == string && RBVER_LT_3_0
|
1583
|
+
|
1584
|
+
string = case string
|
1585
|
+
when String
|
1586
|
+
string.dup
|
1587
|
+
when Integer
|
1588
|
+
encoding = internal_encoding || external_encoding
|
1589
|
+
nil == encoding ? string.chr : string.chr(encoding)
|
1590
|
+
else
|
1591
|
+
ensure_string(string)
|
1592
|
+
end
|
1593
|
+
|
1594
|
+
delegate_r.character_io.unread(string.b)
|
1595
|
+
|
1596
|
+
nil
|
1597
|
+
end
|
1598
|
+
|
1599
|
+
##
|
1600
|
+
# @overload wait(events, timeout)
|
1601
|
+
# @param events [Integer] a bit mask of `IO::READABLE`, `IO::WRITABLE`, or
|
1602
|
+
# `IO::PRIORITY`
|
1603
|
+
# @param timeout [Numeric, nil] the timeout in seconds or no timeout if
|
1604
|
+
# `nil`
|
1605
|
+
#
|
1606
|
+
# @overload wait(timeout = nil, mode = :read)
|
1607
|
+
# @param timeout [Numeric]
|
1608
|
+
# @param mode [Symbol]
|
1609
|
+
#
|
1610
|
+
# @deprecated Included for compability with Ruby 2.7 and earlier
|
1611
|
+
#
|
1612
|
+
# @return [self] if the stream becomes ready for at least one of the given
|
1613
|
+
# events
|
1614
|
+
# @return [nil] if the IO does not become ready before the timeout
|
1615
|
+
#
|
1616
|
+
# @raise [IOError] if the stream is closed
|
1617
|
+
def wait(*args)
|
1618
|
+
events = 0
|
1619
|
+
timeout = nil
|
1620
|
+
if RBVER_LT_3_0
|
1621
|
+
# Ruby <=2.7 compatibility mode while running Ruby <=2.7.
|
1622
|
+
args.each do |arg|
|
1623
|
+
case arg
|
1624
|
+
when Symbol
|
1625
|
+
events |= wait_event_from_symbol(arg)
|
1626
|
+
else
|
1627
|
+
timeout = arg
|
1628
|
+
if nil != timeout && timeout < 0
|
1629
|
+
raise ArgumentError, 'time interval must not be negative'
|
1630
|
+
end
|
1201
1631
|
end
|
1202
1632
|
end
|
1203
|
-
|
1633
|
+
else
|
1634
|
+
if args.size < 2 || args.size >= 2 && Symbol === args[1]
|
1635
|
+
# Ruby <=2.7 compatibility mode while running Ruby >=3.0.
|
1636
|
+
timeout = args[0] if args.size > 0
|
1637
|
+
if nil != timeout && timeout < 0
|
1638
|
+
raise ArgumentError, 'time interval must not be negative'
|
1639
|
+
end
|
1640
|
+
events = args[1..-1]
|
1641
|
+
.map { |mode| wait_event_from_symbol(mode) }
|
1642
|
+
.inject(0) { |memo, value| memo | value }
|
1643
|
+
elsif args.size == 2
|
1644
|
+
# Ruby >=3.0 mode.
|
1645
|
+
events = ensure_integer(args[0])
|
1646
|
+
timeout = args[1]
|
1647
|
+
if nil != timeout && timeout < 0
|
1648
|
+
raise ArgumentError, 'time interval must not be negative'
|
1649
|
+
end
|
1650
|
+
else
|
1651
|
+
# Arguments are invalid, but punt like Ruby 3.0 does.
|
1652
|
+
return nil
|
1653
|
+
end
|
1204
1654
|
end
|
1655
|
+
events = IO::READABLE if events == 0
|
1205
1656
|
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1657
|
+
assert_open
|
1658
|
+
|
1659
|
+
return self if super(events, timeout)
|
1660
|
+
return nil
|
1661
|
+
end
|
1662
|
+
|
1663
|
+
unless RBVER_LT_3_0
|
1664
|
+
##
|
1665
|
+
# Waits until the stream is priority or until `timeout` is reached.
|
1666
|
+
#
|
1667
|
+
# Returns `true` immediately if buffered data is available to read.
|
1668
|
+
#
|
1669
|
+
# @return [self] when the stream is priority
|
1670
|
+
# @return [nil] when the call times out
|
1671
|
+
#
|
1672
|
+
# @raise [IOError] if the stream is not open for reading
|
1673
|
+
#
|
1674
|
+
# @version \>= Ruby 3.0
|
1675
|
+
def wait_priority(timeout = nil)
|
1676
|
+
assert_readable
|
1677
|
+
|
1678
|
+
return self if delegate.wait(IO::PRIORITY, timeout)
|
1679
|
+
return nil
|
1680
|
+
end
|
1681
|
+
end
|
1682
|
+
|
1683
|
+
##
|
1684
|
+
# Waits until the stream is readable or until `timeout` is reached.
|
1685
|
+
#
|
1686
|
+
# Returns `true` immediately if buffered data is available to read.
|
1687
|
+
#
|
1688
|
+
# @return [self] when the stream is readable
|
1689
|
+
# @return [nil] when the call times out
|
1690
|
+
#
|
1691
|
+
# @raise [IOError] if the stream is not open for reading
|
1692
|
+
def wait_readable(timeout = nil)
|
1693
|
+
assert_readable
|
1694
|
+
|
1695
|
+
return self if delegate.wait(IO::READABLE, timeout)
|
1696
|
+
return nil
|
1697
|
+
end
|
1698
|
+
|
1699
|
+
##
|
1700
|
+
# Waits until the stream is writable or until `timeout` is reached.
|
1701
|
+
#
|
1702
|
+
# @return [self] when the stream is writable
|
1703
|
+
# @return [nil] when the call times out
|
1704
|
+
#
|
1705
|
+
# @raise [IOError] if the stream is not open for writing
|
1706
|
+
def wait_writable(timeout = nil)
|
1707
|
+
assert_writable
|
1708
|
+
|
1709
|
+
return self if delegate.wait(IO::WRITABLE, timeout)
|
1710
|
+
return nil
|
1711
|
+
end
|
1712
|
+
|
1713
|
+
##
|
1714
|
+
# Writes the given arguments to the stream via an internal buffer and returns
|
1715
|
+
# the number of bytes written.
|
1716
|
+
#
|
1717
|
+
# If an argument is not a `String`, its `to_s` method is used to convert it
|
1718
|
+
# into one. The entire contents of all arguments are written, blocking as
|
1719
|
+
# necessary even if the underlying stream does not block.
|
1720
|
+
#
|
1721
|
+
# @param strings [Array<Object>] bytes to write to the stream
|
1722
|
+
#
|
1723
|
+
# @return [Integer] the total number of bytes written
|
1724
|
+
#
|
1725
|
+
# @raise [IOError] if the stream is not open for writing
|
1726
|
+
def write(*strings)
|
1727
|
+
# This short circuit is for compatibility with old Ruby versions where this
|
1728
|
+
# method took a single argument and would return 0 when the argument
|
1729
|
+
# resulted in a 0 length string without first checking if the stream was
|
1730
|
+
# already closed.
|
1731
|
+
if strings.size == 1
|
1732
|
+
# This satisfies rubyspec by ensuring that the argument's #to_s method is
|
1733
|
+
# only called once in the case where it results in a non-empty string and
|
1734
|
+
# the short circuit is skipped.
|
1735
|
+
strings[0] = strings[0].to_s
|
1736
|
+
return 0 if strings[0].empty?
|
1228
1737
|
end
|
1229
1738
|
|
1230
|
-
|
1231
|
-
# ios.__io_like__buffered_read(length) -> string
|
1232
|
-
#
|
1233
|
-
# Reads at most _length_ bytes first from an internal read buffer followed
|
1234
|
-
# by the underlying stream if necessary and returns the resulting buffer.
|
1235
|
-
#
|
1236
|
-
# Raises EOFError if the internal read buffer is empty and reading begins at
|
1237
|
-
# the end of the stream. Raises IOError unless #readable? returns +true+.
|
1238
|
-
#
|
1239
|
-
# <b>NOTE:</b> Because this method relies on #unbuffered_read, it raises all
|
1240
|
-
# errors raised by #unbuffered_read and blocks when #unbuffered_read blocks
|
1241
|
-
# whenever the internal read buffer is unable to fulfill the request.
|
1242
|
-
def __io_like__buffered_read(length)
|
1243
|
-
# Check the validity of the method arguments.
|
1244
|
-
raise ArgumentError, "non-positive length #{length} given" if length < 0
|
1245
|
-
|
1246
|
-
raise IOError, 'closed stream' if closed?
|
1247
|
-
raise IOError, 'not opened for reading' unless readable?
|
1248
|
-
|
1249
|
-
# Flush the internal write buffer for writable, non-duplexed objects.
|
1250
|
-
__io_like__buffered_flush if writable? && ! duplexed?
|
1251
|
-
|
1252
|
-
# Ensure that the internal read buffer has at least enough data to satisfy
|
1253
|
-
# the request.
|
1254
|
-
if __io_like__internal_read_buffer.length < length then
|
1255
|
-
unbuffered_length = length - __io_like__internal_read_buffer.length
|
1256
|
-
unbuffered_length = fill_size if unbuffered_length < fill_size
|
1257
|
-
|
1258
|
-
begin
|
1259
|
-
__io_like__internal_read_buffer << unbuffered_read(unbuffered_length)
|
1260
|
-
rescue EOFError, SystemCallError
|
1261
|
-
# Reraise the error if there is no data to return.
|
1262
|
-
raise if __io_like__internal_read_buffer.empty?
|
1263
|
-
end
|
1264
|
-
end
|
1739
|
+
assert_writable
|
1265
1740
|
|
1266
|
-
|
1267
|
-
buffer = __io_like__internal_read_buffer.slice!(0, length)
|
1741
|
+
delegate_w.buffered_io.flush if sync
|
1268
1742
|
|
1269
|
-
|
1743
|
+
bytes_written = 0
|
1744
|
+
strings.each do |string|
|
1745
|
+
bytes_written += delegate_w.character_io.write(string.to_s)
|
1270
1746
|
end
|
1271
1747
|
|
1272
|
-
|
1273
|
-
|
1274
|
-
#
|
1275
|
-
# Sets the current data position to _offset_ based on the setting of
|
1276
|
-
# _whence_. If _whence_ is unspecified or IO::SEEK_SET, _offset_ counts
|
1277
|
-
# from the beginning of the data. If _whence_ is IO::SEEK_END, _offset_
|
1278
|
-
# counts from the end of the data (_offset_ should be negative here). If
|
1279
|
-
# _whence_ is IO::SEEK_CUR, _offset_ is relative to the current position.
|
1280
|
-
#
|
1281
|
-
# As a side effect, the internal read and write buffers are flushed except
|
1282
|
-
# when seeking relative to the current position (whence is IO::SEEK_CUR) to
|
1283
|
-
# a location within the internal read buffer.
|
1284
|
-
#
|
1285
|
-
# Raises Errno::ESPIPE unless #seekable? returns +true+.
|
1286
|
-
#
|
1287
|
-
# See #seek for the usage of _offset_ and _whence_.
|
1288
|
-
#
|
1289
|
-
# <b>NOTE:</b> Because this method relies on #unbuffered_seek and
|
1290
|
-
# #unbuffered_write (when the internal write buffer is not empty), it will
|
1291
|
-
# raise the same errors and block at the same times as those functions.
|
1292
|
-
def __io_like__buffered_seek(offset, whence = IO::SEEK_SET)
|
1293
|
-
raise IOError, 'closed stream' if closed?
|
1294
|
-
raise Errno::ESPIPE unless seekable?
|
1295
|
-
|
1296
|
-
if whence == IO::SEEK_CUR && offset == 0 then
|
1297
|
-
# The seek is only determining the current position, so return the
|
1298
|
-
# buffered position based on the read buffer if it's not empty and the
|
1299
|
-
# write buffer otherwise.
|
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
|
1305
|
-
elsif whence == IO::SEEK_CUR && offset > 0 &&
|
1306
|
-
__io_like__internal_write_buffer.empty? &&
|
1307
|
-
offset <= __io_like__internal_read_buffer.length then
|
1308
|
-
# The seek is within the read buffer, so just discard a sufficient
|
1309
|
-
# amount of the buffer and report the new buffered position.
|
1310
|
-
__io_like__internal_read_buffer.slice!(0, offset)
|
1311
|
-
unbuffered_seek(0, IO::SEEK_CUR) -
|
1312
|
-
__io_like__internal_read_buffer.length
|
1313
|
-
else
|
1314
|
-
# The seek target is outside of the buffers, so flush the buffers and
|
1315
|
-
# jump to the new position.
|
1316
|
-
if whence == IO::SEEK_CUR then
|
1317
|
-
# Adjust relative offsets based on the current buffered offset.
|
1318
|
-
offset += __io_like__internal_read_buffer.empty? ?
|
1319
|
-
__io_like__internal_write_buffer.length :
|
1320
|
-
-__io_like__internal_read_buffer.length
|
1321
|
-
end
|
1748
|
+
bytes_written
|
1749
|
+
end
|
1322
1750
|
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1751
|
+
##
|
1752
|
+
# Enables blocking mode on the stream (via #nonblock=), flushes any buffered
|
1753
|
+
# data, and then directly writes `string`, bypassing the internal buffer.
|
1754
|
+
#
|
1755
|
+
# If `string` is not a `String`, its `to_s` method is used to convert it into
|
1756
|
+
# one. If any of `string` is written, this method returns the number of bytes
|
1757
|
+
# written, which may be less than all requested bytes (partial write).
|
1758
|
+
#
|
1759
|
+
# @param string [Object] bytes to write to the stream
|
1760
|
+
# @param exception [Boolean] when `true` causes this method to raise
|
1761
|
+
# exceptions when writing would block; otherwise, symbols are returned
|
1762
|
+
#
|
1763
|
+
# @return [Integer] the total number of bytes written
|
1764
|
+
# @return [:wait_readable, :wait_writable] if `exception` is `false` and
|
1765
|
+
# writing to the stream would block
|
1766
|
+
#
|
1767
|
+
# @raise [IOError] if the stream is not open for writing
|
1768
|
+
# @raise [IO::EWOULDBLOCKWaitReadable, IO::EWOULDBLOCKWaitWritable] if
|
1769
|
+
# `exception` is `true` and writing to the stream would block
|
1770
|
+
# @raise [Errno::EBADF] if non-blocking mode is not supported
|
1771
|
+
# @raise [SystemCallError] if there are low level errors
|
1772
|
+
def write_nonblock(string, exception: true)
|
1773
|
+
assert_writable
|
1774
|
+
|
1775
|
+
string = string.to_s
|
1776
|
+
|
1777
|
+
self.nonblock = true
|
1778
|
+
result = delegate_w.buffered_io.flush || delegate_w.concrete_io.write(string.b)
|
1779
|
+
case result
|
1780
|
+
when Integer
|
1781
|
+
return result
|
1782
|
+
else
|
1783
|
+
return nonblock_response(result, exception)
|
1784
|
+
end
|
1785
|
+
end
|
1326
1786
|
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1787
|
+
# Expose these to other instances of this class for use with #reopen.
|
1788
|
+
protected :delegate_r, :delegate_w
|
1789
|
+
|
1790
|
+
# Hide these to preserve the interface of IO.
|
1791
|
+
private :readable?, :writable?
|
1792
|
+
|
1793
|
+
private
|
1794
|
+
|
1795
|
+
##
|
1796
|
+
# This returns the class name as a string for all objects including those
|
1797
|
+
# where #class is not defined such as descendants of BasicObject.
|
1798
|
+
#
|
1799
|
+
# @param object [any] an object instance of any class
|
1800
|
+
#
|
1801
|
+
# @return [String] the class name of `object`
|
1802
|
+
def class_name_of(object)
|
1803
|
+
# This ensures that the standard #class method is used whether object
|
1804
|
+
# implements its own #inspect implementation or does not implement it at
|
1805
|
+
# all, such as for BasicObject descendants.
|
1806
|
+
Kernel.instance_method(:class).bind(object).call.to_s
|
1807
|
+
end
|
1808
|
+
|
1809
|
+
##
|
1810
|
+
# Ensures that a buffer, if provided, is large enough to hold the requested
|
1811
|
+
# number of bytes and is then truncated to the returned number of bytes while
|
1812
|
+
# ensuring that the encoding is preserved.
|
1813
|
+
#
|
1814
|
+
# @param length [Integer] the minimum size of the buffer in bytes
|
1815
|
+
# @param buffer [String, nil] the buffer
|
1816
|
+
#
|
1817
|
+
# @yieldparam binary_buffer [String, nil] a binary encoded String based on
|
1818
|
+
# `buffer` (if non-nil) that is at least `length` bytes long
|
1819
|
+
# @yieldreturn [Integer, String, Symbol] the result of a low level read
|
1820
|
+
# operation. (See {IO::LikeHelpers::AbstractIO#read})
|
1821
|
+
#
|
1822
|
+
# @return the result of the given block
|
1823
|
+
def ensure_buffer(length, buffer)
|
1824
|
+
if nil != buffer
|
1825
|
+
orig_encoding = buffer.encoding
|
1826
|
+
buffer.force_encoding(Encoding::BINARY)
|
1827
|
+
|
1828
|
+
# Ensure the given buffer is large enough to hold the requested number of
|
1829
|
+
# bytes.
|
1830
|
+
buffer << "\0".b * (length - buffer.bytesize) if length > buffer.bytesize
|
1330
1831
|
end
|
1331
1832
|
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
# <b>NOTE:</b> Because this method relies on #unbuffered_write, it raises
|
1343
|
-
# all errors raised by #unbuffered_write and blocks when #unbuffered_write
|
1344
|
-
# blocks whenever the internal write buffer is unable to fulfill the
|
1345
|
-
# request.
|
1346
|
-
def __io_like__buffered_write(string)
|
1347
|
-
raise IOError, 'closed stream' if closed?
|
1348
|
-
raise IOError, 'not opened for writing' unless writable?
|
1349
|
-
|
1350
|
-
# Flush the internal read buffer and set the unbuffered position to the
|
1351
|
-
# buffered position when dealing with non-duplexed objects.
|
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)
|
1355
|
-
end
|
1833
|
+
result = yield(buffer)
|
1834
|
+
ensure
|
1835
|
+
if nil != buffer
|
1836
|
+
# A buffer was given to fill, so the delegate returned the number of bytes
|
1837
|
+
# read. Truncate the buffer if necessary and restore its original
|
1838
|
+
# encoding.
|
1839
|
+
buffer.slice!((result || 0)..-1)
|
1840
|
+
buffer.force_encoding(orig_encoding)
|
1841
|
+
end
|
1842
|
+
end
|
1356
1843
|
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
return bytes_written
|
1844
|
+
##
|
1845
|
+
# Attempt to perform implicit conversion of `object` to an `Integer`.
|
1846
|
+
#
|
1847
|
+
# @param object [Object] an object to be converted via its `#to_int` method
|
1848
|
+
#
|
1849
|
+
# This method exists solely to make the message of any raised `TypeError`
|
1850
|
+
# exceptions exactly match what IO methods would produce in order to appease
|
1851
|
+
# overly prescriptive rubyspec tests; otherwise, the `Integer()` method would
|
1852
|
+
# suffice.
|
1853
|
+
#
|
1854
|
+
# @return [Integer] the converted value
|
1855
|
+
#
|
1856
|
+
# @raise [TypeError] when conversion fails
|
1857
|
+
def ensure_integer(object)
|
1858
|
+
object.to_int
|
1859
|
+
rescue NoMethodError
|
1860
|
+
if nil == object
|
1861
|
+
raise TypeError, 'no implicit conversion from nil to integer'
|
1376
1862
|
end
|
1377
1863
|
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1864
|
+
name = case object
|
1865
|
+
when nil
|
1866
|
+
'nil'
|
1867
|
+
when false
|
1868
|
+
'false'
|
1869
|
+
when true
|
1870
|
+
'true'
|
1871
|
+
else
|
1872
|
+
class_name_of(object)
|
1873
|
+
end
|
1874
|
+
raise TypeError,
|
1875
|
+
'no implicit conversion of %s into Integer' % [name]
|
1876
|
+
end
|
1877
|
+
|
1878
|
+
##
|
1879
|
+
# Attempt to perform implicit conversion of `object` to a `String`.
|
1880
|
+
#
|
1881
|
+
# @param object [Object] an object to be converted via its `#to_str` method
|
1882
|
+
#
|
1883
|
+
# This method exists because no other method is strict about implicit string
|
1884
|
+
# conversion while also raising `TypeError` for failures. For instance,
|
1885
|
+
# `String.new` first calls `#to_str` on its argument but then falls back to
|
1886
|
+
# `#to_s` if the former call fails. Some rubyspec tests require a `TypeError`
|
1887
|
+
# to be raised when implicit conversion fails, and directly calling `#to_str`
|
1888
|
+
# raises NoMethodError if the method does not exist.
|
1889
|
+
#
|
1890
|
+
# @return [String] the converted value
|
1891
|
+
#
|
1892
|
+
# @raise [TypeError] when conversion fails
|
1893
|
+
def ensure_string(object)
|
1894
|
+
begin
|
1895
|
+
result = object.to_str
|
1896
|
+
return result if String === result
|
1897
|
+
rescue NoMethodError
|
1898
|
+
name = case object
|
1899
|
+
when nil
|
1900
|
+
'nil'
|
1901
|
+
when false
|
1902
|
+
'false'
|
1903
|
+
when true
|
1904
|
+
'true'
|
1905
|
+
else
|
1906
|
+
class_name_of(object)
|
1907
|
+
end
|
1908
|
+
raise TypeError,
|
1909
|
+
'no implicit conversion of %s into String' % [name]
|
1381
1910
|
end
|
1382
1911
|
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1912
|
+
object_class = class_name_of(object)
|
1913
|
+
result_class = class_name_of(result)
|
1914
|
+
raise TypeError,
|
1915
|
+
'can\'t convert %s to String (%s#to_str gives %s)' %
|
1916
|
+
[object_class, object_class, result_class]
|
1917
|
+
end
|
1918
|
+
|
1919
|
+
##
|
1920
|
+
# Write `item` followed by the record separator. Recursively process
|
1921
|
+
# elements of `item` if it responds to `#to_ary` with a non-`nil` result.
|
1922
|
+
#
|
1923
|
+
# @param item [Object] the item to be `String`-ified and written to the stream
|
1924
|
+
# @param seen [Array] a list of `Objects` that have already been printed
|
1925
|
+
#
|
1926
|
+
# @return [nil]
|
1927
|
+
def flatten_puts(item, seen = [])
|
1928
|
+
if seen.include?(item.__id__)
|
1929
|
+
write('[...]')
|
1930
|
+
write(ORS)
|
1931
|
+
return
|
1386
1932
|
end
|
1387
1933
|
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1934
|
+
seen.push(item.__id__)
|
1935
|
+
|
1936
|
+
array = item.to_ary rescue nil
|
1937
|
+
if nil == array
|
1938
|
+
string = item.to_s
|
1939
|
+
unless String === string
|
1940
|
+
# This ensures that #inspect-like output is generated even if item
|
1941
|
+
# implements its own #inspect implementation or does not implement it at
|
1942
|
+
# all, such as for BasicObject descendants.
|
1943
|
+
string =
|
1944
|
+
Kernel.instance_method(:inspect).bind(item).call.sub(%r{ .*}, '>')
|
1945
|
+
end
|
1946
|
+
write(string)
|
1947
|
+
write(ORS) unless string.end_with?(ORS)
|
1948
|
+
else
|
1949
|
+
array.each { |i| flatten_puts(i, seen) }
|
1392
1950
|
end
|
1393
1951
|
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1952
|
+
seen.pop
|
1953
|
+
|
1954
|
+
nil
|
1955
|
+
end
|
1956
|
+
|
1957
|
+
##
|
1958
|
+
# Converts non-blocking responses into exceptions if requested.
|
1959
|
+
#
|
1960
|
+
# @param type [:wait_readable, :wait_writable] the type of non-blocking
|
1961
|
+
# response
|
1962
|
+
# @param exception [Boolean] if `true`, raise an exception for `type`
|
1963
|
+
#
|
1964
|
+
# @return [:wait_readable, :wait_writable] if `exception` is `false`
|
1965
|
+
def nonblock_response(type, exception)
|
1966
|
+
case type
|
1967
|
+
when :wait_readable
|
1968
|
+
return type unless exception
|
1969
|
+
raise IO::EWOULDBLOCKWaitReadable
|
1970
|
+
when :wait_writable
|
1971
|
+
return type unless exception
|
1972
|
+
raise IO::EWOULDBLOCKWaitWritable
|
1973
|
+
else
|
1974
|
+
raise ArgumentError, "Invalid type: #{type}"
|
1398
1975
|
end
|
1976
|
+
end
|
1399
1977
|
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1978
|
+
##
|
1979
|
+
# Parses the positional arguments for #readline, #gets, and related methods.
|
1980
|
+
#
|
1981
|
+
# @return [[String, Integer]] an array containing the separator string and the
|
1982
|
+
# maximum length
|
1983
|
+
def parse_readline_args(*args)
|
1984
|
+
if args.size > 2
|
1985
|
+
raise ArgumentError,
|
1986
|
+
"wrong number of arguments (given #{args.size}, expected 0..2)"
|
1987
|
+
elsif args.size == 2
|
1988
|
+
sep_string = nil == args[0] ? nil : ensure_string(args[0])
|
1989
|
+
limit = nil == args[1] ? nil : ensure_integer(args[1])
|
1990
|
+
elsif args.size == 1
|
1991
|
+
begin
|
1992
|
+
sep_string = nil == args[0] ? nil : ensure_string(args[0])
|
1993
|
+
limit = nil
|
1994
|
+
rescue TypeError
|
1995
|
+
limit = ensure_integer(args[0])
|
1996
|
+
sep_string = $/
|
1997
|
+
end
|
1998
|
+
else
|
1999
|
+
sep_string = $/
|
2000
|
+
limit = nil
|
1404
2001
|
end
|
1405
2002
|
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
|
2003
|
+
return [sep_string, limit]
|
2004
|
+
end
|
2005
|
+
|
2006
|
+
##
|
2007
|
+
# Reads and returns up to `length` bytes from this stream.
|
2008
|
+
#
|
2009
|
+
# This method always blocks, even when the stream is in non-blocking mode. An
|
2010
|
+
# empty `String` is returned if reading begins at the end of the stream.
|
2011
|
+
#
|
2012
|
+
# @param length [Integer] the number of bytes to read
|
2013
|
+
#
|
2014
|
+
# @return [String] up to `length` bytes read from this stream
|
2015
|
+
def read_bytes(length)
|
2016
|
+
buffer = ''.b
|
2017
|
+
|
2018
|
+
if delegate_r.buffered_io.read_buffer_empty?
|
2019
|
+
# Flush any pending write data in the buffered IO in preparation for
|
2020
|
+
# reading directly from the delegate behind it.
|
2021
|
+
delegate_r.buffered_io.flush
|
2022
|
+
else
|
2023
|
+
buffer << delegate_r.buffered_io.read(length)
|
2024
|
+
length -= buffer.bytesize
|
1410
2025
|
end
|
1411
2026
|
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
# implementation dependent manner when joining recursive arrays and so does
|
1418
|
-
# not always produce the expected results. Specifically, MRI 1.8.6 and
|
1419
|
-
# 1.8.7 behave as follows:
|
1420
|
-
#
|
1421
|
-
# x = []
|
1422
|
-
# x << 1 << x << 2
|
1423
|
-
# x.join(', ') => "1, 1, [...], 2, 2"
|
1424
|
-
#
|
1425
|
-
# The expected and necessary result for use with #puts is:
|
1426
|
-
#
|
1427
|
-
# "1, [...], 2"
|
1428
|
-
#
|
1429
|
-
# Things get progressively worse as the nesting and recursion become more
|
1430
|
-
# convoluted.
|
1431
|
-
def __io_like__array_join(array, separator, seen = [])
|
1432
|
-
seen.push(array.object_id)
|
1433
|
-
need_separator = false
|
1434
|
-
result = array.inject('') do |memo, item|
|
1435
|
-
memo << separator if need_separator
|
1436
|
-
need_separator = true
|
1437
|
-
|
1438
|
-
memo << if item.kind_of?(Array) then
|
1439
|
-
if seen.include?(item.object_id) then
|
1440
|
-
'[...]'
|
1441
|
-
else
|
1442
|
-
__io_like__array_join(item, separator, seen)
|
1443
|
-
end
|
1444
|
-
else
|
1445
|
-
item.to_s
|
1446
|
-
end
|
2027
|
+
begin
|
2028
|
+
while length > 0 do
|
2029
|
+
bytes = delegate_r.blocking_io.read(length)
|
2030
|
+
length -= bytes.bytesize
|
2031
|
+
buffer << bytes
|
1447
2032
|
end
|
1448
|
-
|
2033
|
+
rescue EOFError
|
2034
|
+
end
|
1449
2035
|
|
1450
|
-
|
2036
|
+
buffer
|
2037
|
+
end
|
2038
|
+
|
2039
|
+
##
|
2040
|
+
# @return [Symbol] a `Symbol` equivalent to the given `mode` for Ruby 2.7 and
|
2041
|
+
# lower for use with `#wait`
|
2042
|
+
def wait_event_from_symbol(mode)
|
2043
|
+
case mode
|
2044
|
+
when :r, :read, :readable
|
2045
|
+
IO::READABLE
|
2046
|
+
when :w, :write, :writable
|
2047
|
+
IO::WRITABLE
|
2048
|
+
when :rw, :read_write, :readable_writable
|
2049
|
+
IO::READABLE || IO::WRITABLE
|
2050
|
+
else
|
2051
|
+
raise ArgumentError, "unsupported mode: #{mode}"
|
1451
2052
|
end
|
1452
2053
|
end
|
1453
2054
|
end
|
2055
|
+
end
|
1454
2056
|
|
1455
2057
|
# vim: ts=2 sw=2 et
|