faraday 2.0.0.alpha.pre.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c5ab8c9cafcd2690a2ea370814f080f0a085e666377048166868b84a9b3fb7e
4
- data.tar.gz: 399207b7f32439dae2f9ad22bf839479e3cf715001f6b8d8a8fb8f88bb1f565d
3
+ metadata.gz: 2123a105dd09a93bec6fe115277fd7c58afa269bc1036524a422a3e45df2b40c
4
+ data.tar.gz: bdd311dabe80e2ecd28f7bf941ea0e551840b2bc783dd781b56999842086a31f
5
5
  SHA512:
6
- metadata.gz: 0a1b9107707c0f2ad30040885cd0037bf5ea64f3035e28b2cf4c8f0304de8b3acbc9217d6c77b0889a0603909dfaf87a9c54108a0a65e34291d13b69eae8efec
7
- data.tar.gz: 74083d46a172455f40fd28151b806678c4d8f404508f2b25e2a8eb7b08c025a870565467fd5dff2420e2f1ebb01327b09d5519877770f46e0ea7d83c30c15a13
6
+ metadata.gz: 943a1dd4a67287874fc3724d3d9ec7e41540cd3a08b528201b1af806d5dd56bceb976f54df6d0394fb25bffeb0bcb224831700c9ef46c1daf24cb3e13fd2ad52
7
+ data.tar.gz: 3ae115b30da8ec49253888f4a81522c14667a8da6b248b0d56192252b8d9bf9a6914f703530d467c2a83415a0862b73ccc17f799d9c1d0fba8289296b7cb0faf
@@ -56,7 +56,7 @@ RSpec.describe Client do
56
56
 
57
57
  it 'handles exception' do
58
58
  stubs.get('/ebi') do
59
- raise Faraday::ConnectionFailed, nil
59
+ raise Faraday::ConnectionFailed
60
60
  end
61
61
 
62
62
  expect { client.sushi('ebi') }.to raise_error(Faraday::ConnectionFailed)
@@ -60,7 +60,7 @@ class ClientTest < Test::Unit::TestCase
60
60
  def test_sushi_exception
61
61
  stubs = Faraday::Adapter::Test::Stubs.new
62
62
  stubs.get('/ebi') do
63
- raise Faraday::ConnectionFailed, nil
63
+ raise Faraday::ConnectionFailed
64
64
  end
65
65
 
66
66
  cli = client(stubs)
@@ -55,6 +55,7 @@ module Faraday
55
55
  @stack = {}
56
56
  @consumed = {}
57
57
  @strict_mode = strict_mode
58
+ @stubs_mutex = Monitor.new
58
59
  yield(self) if block_given?
59
60
  end
60
61
 
@@ -70,10 +71,13 @@ module Faraday
70
71
  stack = @stack[request_method]
71
72
  consumed = (@consumed[request_method] ||= [])
72
73
 
73
- stub, meta = matches?(stack, env)
74
- if stub
75
- consumed << stack.delete(stub)
76
- return stub, meta
74
+ @stubs_mutex.synchronize do
75
+ stub, meta = matches?(stack, env)
76
+ if stub
77
+ removed = stack.delete(stub)
78
+ consumed << removed unless removed.nil?
79
+ return stub, meta
80
+ end
77
81
  end
78
82
  matches?(consumed, env)
79
83
  end
@@ -117,7 +117,7 @@ module Faraday
117
117
 
118
118
  extend Forwardable
119
119
 
120
- def_delegators :builder, :build, :use, :request, :response, :adapter, :app
120
+ def_delegators :builder, :use, :request, :response, :adapter, :app
121
121
 
122
122
  # Closes the underlying resources and/or connections. In the case of
123
123
  # persistent connections, this closes all currently open connections
data/lib/faraday/error.rb CHANGED
@@ -6,7 +6,7 @@ module Faraday
6
6
  class Error < StandardError
7
7
  attr_reader :response, :wrapped_exception
8
8
 
9
- def initialize(exc, response = nil)
9
+ def initialize(exc = nil, response = nil)
10
10
  @wrapped_exception = nil unless defined?(@wrapped_exception)
11
11
  @response = nil unless defined?(@response)
12
12
  super(exc_msg_and_response!(exc, response))
@@ -141,13 +141,7 @@ module Faraday
141
141
  class SSLError < Error
142
142
  end
143
143
 
144
- # Raised by FaradayMiddleware::ResponseMiddleware
144
+ # Raised by middlewares that parse the response, like the JSON response middleware.
145
145
  class ParsingError < Error
146
146
  end
147
-
148
- # Exception used to control the Retry middleware.
149
- #
150
- # @see Faraday::Request::Retry
151
- class RetriableResponse < Error
152
- end
153
147
  end
@@ -58,23 +58,22 @@ module Faraday
58
58
  end
59
59
  end
60
60
 
61
- def initialize(handlers = [], adapter = nil, &block)
62
- @adapter = adapter
63
- @handlers = handlers
64
- if block
65
- build(&block)
66
- elsif @handlers.empty?
67
- # default stack, if nothing else is configured
68
- request :url_encoded
69
- self.adapter Faraday.default_adapter
70
- end
61
+ def initialize(&block)
62
+ @adapter = nil
63
+ @handlers = []
64
+ build(&block)
65
+ end
66
+
67
+ def initialize_dup(original)
68
+ super
69
+ @adapter = original.adapter
70
+ @handlers = original.handlers.dup
71
71
  end
72
72
 
73
- def build(options = {})
73
+ def build
74
74
  raise_if_locked
75
- @handlers.clear unless options[:keep]
76
- yield(self) if block_given?
77
- adapter(Faraday.default_adapter) unless @adapter
75
+ block_given? ? yield(self) : request(:url_encoded)
76
+ adapter(Faraday.default_adapter, **Faraday.default_adapter_options) unless @adapter
78
77
  end
79
78
 
80
79
  def [](idx)
@@ -109,7 +108,7 @@ module Faraday
109
108
  end
110
109
 
111
110
  ruby2_keywords def adapter(klass = NO_ARGUMENT, *args, &block)
112
- return @adapter if klass == NO_ARGUMENT
111
+ return @adapter if klass == NO_ARGUMENT || klass.nil?
113
112
 
114
113
  klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol)
115
114
  @adapter = self.class::Handler.new(klass, *args, &block)
@@ -164,6 +163,7 @@ module Faraday
164
163
  def app
165
164
  @app ||= begin
166
165
  lock!
166
+ ensure_adapter!
167
167
  to_app
168
168
  end
169
169
  end
@@ -182,10 +182,6 @@ module Faraday
182
182
  @adapter == other.adapter
183
183
  end
184
184
 
185
- def dup
186
- self.class.new(@handlers.dup, @adapter.dup)
187
- end
188
-
189
185
  # ENV Keys
190
186
  # :http_method - a symbolized request HTTP method (:get, :post)
191
187
  # :body - the request body that will eventually be converted to a string.
@@ -216,6 +212,9 @@ module Faraday
216
212
  private
217
213
 
218
214
  LOCK_ERR = "can't modify middleware stack after making a request"
215
+ MISSING_ADAPTER_ERROR = "An attempt to run a request with a Faraday::Connection without adapter has been made.\n" \
216
+ "Please set Faraday.default_adapter or provide one when initializing the connection.\n" \
217
+ 'For more info, check https://lostisland.github.io/faraday/usage/.'
219
218
 
220
219
  def raise_if_locked
221
220
  raise StackLocked, LOCK_ERR if locked?
@@ -227,6 +226,10 @@ module Faraday
227
226
  raise 'Adapter should be set using the `adapter` method, not `use`'
228
227
  end
229
228
 
229
+ def ensure_adapter!
230
+ raise MISSING_ADAPTER_ERROR unless @adapter
231
+ end
232
+
230
233
  def adapter_set?
231
234
  !@adapter.nil?
232
235
  end
@@ -8,10 +8,11 @@ module Faraday
8
8
 
9
9
  # @param app [#call]
10
10
  # @param type [String, Symbol] Type of Authorization
11
- # @param params [Array<String, Proc>] parameters to build the Authorization header.
11
+ # @param params [Array<String, Proc, #call>] parameters to build the Authorization header.
12
12
  # If the type is `:basic`, then these can be a login and password pair.
13
13
  # Otherwise, a single value is expected that will be appended after the type.
14
- # This value can be a proc, in which case it will be invoked on each request.
14
+ # This value can be a proc or an object responding to `.call`, in which case
15
+ # it will be invoked on each request.
15
16
  def initialize(app, type, *params)
16
17
  @type = type
17
18
  @params = params
@@ -37,7 +38,7 @@ module Faraday
37
38
  raise ArgumentError, "Unexpected params received (got #{params.size} instead of 1)"
38
39
  else
39
40
  value = params.first
40
- value = value.call if value.is_a?(Proc)
41
+ value = value.call if value.is_a?(Proc) || value.respond_to?(:call)
41
42
  "#{type} #{value}"
42
43
  end
43
44
  end
@@ -133,6 +133,4 @@ end
133
133
  require 'faraday/request/authorization'
134
134
  require 'faraday/request/instrumentation'
135
135
  require 'faraday/request/json'
136
- require 'faraday/request/multipart'
137
- require 'faraday/request/retry'
138
136
  require 'faraday/request/url_encoded'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- VERSION = '2.0.0.alpha-3'
4
+ VERSION = '2.1.0'
5
5
  end
data/lib/faraday.rb CHANGED
@@ -17,9 +17,7 @@ require 'faraday/middleware'
17
17
  require 'faraday/adapter'
18
18
  require 'faraday/request'
19
19
  require 'faraday/response'
20
- require 'faraday/file_part'
21
- require 'faraday/param_part'
22
-
20
+ require 'faraday/net_http'
23
21
  # This is the main namespace for Faraday.
24
22
  #
25
23
  # It provides methods to create {Connection} objects, and HTTP-related
@@ -56,6 +54,10 @@ module Faraday
56
54
  # @return [Symbol] the new default_adapter.
57
55
  attr_reader :default_adapter
58
56
 
57
+ # Option for the default_adapter
58
+ # @return [Hash] default_adapter options
59
+ attr_accessor :default_adapter_options
60
+
59
61
  # Documented below, see default_connection
60
62
  attr_writer :default_connection
61
63
 
@@ -150,5 +152,6 @@ module Faraday
150
152
  self.ignore_env_proxy = false
151
153
  self.root_path = File.expand_path __dir__
152
154
  self.lib_path = File.expand_path 'faraday', __dir__
153
- self.default_adapter = :test
155
+ self.default_adapter = :net_http
156
+ self.default_adapter_options = {}
154
157
  end
@@ -151,6 +151,9 @@ RSpec.describe Faraday::Connection do
151
151
  end
152
152
 
153
153
  describe '#close' do
154
+ before { Faraday.default_adapter = :test }
155
+ after { Faraday.default_adapter = nil }
156
+
154
157
  it 'can close underlying app' do
155
158
  expect(conn.app).to receive(:close)
156
159
  conn.close
@@ -20,6 +20,8 @@ RSpec.describe Faraday::RackBuilder do
20
20
  end
21
21
 
22
22
  subject { conn.builder }
23
+ before { Faraday.default_adapter = :test }
24
+ after { Faraday.default_adapter = nil }
23
25
 
24
26
  context 'with default stack' do
25
27
  let(:conn) { Faraday::Connection.new }
@@ -86,13 +88,6 @@ RSpec.describe Faraday::RackBuilder do
86
88
 
87
89
  it { expect(subject.handlers).to eq([Apple]) }
88
90
 
89
- it 'allows rebuilding' do
90
- subject.build do |builder|
91
- builder.use(Orange)
92
- end
93
- expect(subject.handlers).to eq([Orange])
94
- end
95
-
96
91
  it 'allows use' do
97
92
  subject.use(Orange)
98
93
  expect(subject.handlers).to eq([Apple, Orange])
@@ -156,6 +151,33 @@ RSpec.describe Faraday::RackBuilder do
156
151
  end
157
152
  end
158
153
 
154
+ context 'when adapter is added with named options' do
155
+ after { Faraday.default_adapter_options = {} }
156
+ let(:conn) { Faraday::Connection.new {} }
157
+
158
+ let(:cat_adapter) do
159
+ Class.new(Faraday::Adapter) do
160
+ attr_accessor :name
161
+
162
+ def initialize(app, name:)
163
+ super(app)
164
+ @name = name
165
+ end
166
+ end
167
+ end
168
+
169
+ let(:cat) { subject.adapter.build }
170
+
171
+ it 'adds a handler to construct adapter with named options' do
172
+ Faraday.default_adapter = cat_adapter
173
+ Faraday.default_adapter_options = { name: 'Chloe' }
174
+ expect { cat }.to_not output(
175
+ /warning: Using the last argument as keyword parameters is deprecated/
176
+ ).to_stderr
177
+ expect(cat.name).to eq 'Chloe'
178
+ end
179
+ end
180
+
159
181
  context 'when middleware is added with named arguments' do
160
182
  let(:conn) { Faraday::Connection.new {} }
161
183
 
@@ -63,6 +63,15 @@ RSpec.describe Faraday::Request::Authorization do
63
63
  include_examples 'does not interfere with existing authentication'
64
64
  end
65
65
 
66
+ context 'when passed a callable' do
67
+ let(:callable) { double('Callable Authorizer', call: 'custom_from_callable') }
68
+ let(:auth_config) { [callable] }
69
+
70
+ it { expect(response.body).to eq('Bearer custom_from_callable') }
71
+
72
+ include_examples 'does not interfere with existing authentication'
73
+ end
74
+
66
75
  context 'when passed too many arguments' do
67
76
  let(:auth_config) { %w[baz foo] }
68
77
 
@@ -3,7 +3,6 @@
3
3
  RSpec.describe Faraday::Request::UrlEncoded do
4
4
  let(:conn) do
5
5
  Faraday.new do |b|
6
- b.request :multipart
7
6
  b.request :url_encoded
8
7
  b.adapter :test do |stub|
9
8
  stub.post('/echo') do |env|
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'multipart_parser/reader'
4
-
5
3
  module Faraday
6
4
  module HelperMethods
7
5
  def self.included(base)
@@ -86,41 +84,6 @@ module Faraday
86
84
  end
87
85
  end
88
86
 
89
- def multipart_file
90
- Faraday::FilePart.new(__FILE__, 'text/x-ruby')
91
- end
92
-
93
- # parse boundary out of a Content-Type header like:
94
- # Content-Type: multipart/form-data; boundary=gc0p4Jq0M2Yt08jU534c0p
95
- def parse_multipart_boundary(ctype)
96
- MultipartParser::Reader.extract_boundary_value(ctype)
97
- end
98
-
99
- # parse a multipart MIME message, returning a hash of any multipart errors
100
- def parse_multipart(boundary, body)
101
- reader = MultipartParser::Reader.new(boundary)
102
- result = { errors: [], parts: [] }
103
- def result.part(name)
104
- hash = self[:parts].detect { |h| h[:part].name == name }
105
- [hash[:part], hash[:body].join]
106
- end
107
-
108
- reader.on_part do |part|
109
- result[:parts] << thispart = {
110
- part: part,
111
- body: []
112
- }
113
- part.on_data do |chunk|
114
- thispart[:body] << chunk
115
- end
116
- end
117
- reader.on_error do |msg|
118
- result[:errors] << msg
119
- end
120
- reader.write(body)
121
- result
122
- end
123
-
124
87
  def method_with_body?(method)
125
88
  self.class.method_with_body?(method)
126
89
  end
@@ -40,7 +40,6 @@ shared_examples 'adapter examples' do |**options|
40
40
  conn_options[:ssl][:ca_file] ||= ENV['SSL_FILE']
41
41
 
42
42
  Faraday.new(remote, conn_options) do |conn|
43
- conn.request :multipart
44
43
  conn.request :url_encoded
45
44
  conn.response :raise_error
46
45
  conn.adapter described_class, *adapter_options
@@ -126,19 +126,6 @@ shared_examples 'a request method' do |http_method|
126
126
  expect { conn.public_send(http_method, '/') }.to raise_error(exc)
127
127
  end
128
128
 
129
- # Can't send files on get, head and delete methods
130
- if method_with_body?(http_method)
131
- it 'sends files' do
132
- payload = { uploaded_file: multipart_file }
133
- request_stub.with(headers: { 'Content-Type' => %r{\Amultipart/form-data} }) do |request|
134
- # WebMock does not support matching body for multipart/form-data requests yet :(
135
- # https://github.com/bblimke/webmock/issues/623
136
- request.body.include?('RubyMultipartPost')
137
- end
138
- conn.public_send(http_method, '/', payload)
139
- end
140
- end
141
-
142
129
  on_feature :reason_phrase_parse do
143
130
  it 'parses the reason phrase' do
144
131
  request_stub.to_return(status: [200, 'OK'])
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.alpha.pre.3
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - "@technoweenie"
@@ -10,28 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-11-30 00:00:00.000000000 Z
13
+ date: 2022-01-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: multipart-post
16
+ name: faraday-net_http
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - ">="
20
- - !ruby/object:Gem::Version
21
- version: '1.2'
22
- - - "<"
19
+ - - "~>"
23
20
  - !ruby/object:Gem::Version
24
- version: '3'
21
+ version: '2.0'
25
22
  type: :runtime
26
23
  prerelease: false
27
24
  version_requirements: !ruby/object:Gem::Requirement
28
25
  requirements:
29
- - - ">="
26
+ - - "~>"
30
27
  - !ruby/object:Gem::Version
31
- version: '1.2'
32
- - - "<"
33
- - !ruby/object:Gem::Version
34
- version: '3'
28
+ version: '2.0'
35
29
  - !ruby/object:Gem::Dependency
36
30
  name: ruby2_keywords
37
31
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +60,6 @@ files:
66
60
  - lib/faraday/encoders/flat_params_encoder.rb
67
61
  - lib/faraday/encoders/nested_params_encoder.rb
68
62
  - lib/faraday/error.rb
69
- - lib/faraday/file_part.rb
70
63
  - lib/faraday/logging/formatter.rb
71
64
  - lib/faraday/methods.rb
72
65
  - lib/faraday/middleware.rb
@@ -77,15 +70,12 @@ files:
77
70
  - lib/faraday/options/proxy_options.rb
78
71
  - lib/faraday/options/request_options.rb
79
72
  - lib/faraday/options/ssl_options.rb
80
- - lib/faraday/param_part.rb
81
73
  - lib/faraday/parameters.rb
82
74
  - lib/faraday/rack_builder.rb
83
75
  - lib/faraday/request.rb
84
76
  - lib/faraday/request/authorization.rb
85
77
  - lib/faraday/request/instrumentation.rb
86
78
  - lib/faraday/request/json.rb
87
- - lib/faraday/request/multipart.rb
88
- - lib/faraday/request/retry.rb
89
79
  - lib/faraday/request/url_encoded.rb
90
80
  - lib/faraday/response.rb
91
81
  - lib/faraday/response/json.rb
@@ -99,7 +89,6 @@ files:
99
89
  - spec/faraday/adapter/test_spec.rb
100
90
  - spec/faraday/adapter_registry_spec.rb
101
91
  - spec/faraday/adapter_spec.rb
102
- - spec/faraday/composite_read_io_spec.rb
103
92
  - spec/faraday/connection_spec.rb
104
93
  - spec/faraday/error_spec.rb
105
94
  - spec/faraday/middleware_spec.rb
@@ -113,8 +102,6 @@ files:
113
102
  - spec/faraday/request/authorization_spec.rb
114
103
  - spec/faraday/request/instrumentation_spec.rb
115
104
  - spec/faraday/request/json_spec.rb
116
- - spec/faraday/request/multipart_spec.rb
117
- - spec/faraday/request/retry_spec.rb
118
105
  - spec/faraday/request/url_encoded_spec.rb
119
106
  - spec/faraday/request_spec.rb
120
107
  - spec/faraday/response/json_spec.rb
@@ -137,7 +124,7 @@ licenses:
137
124
  - MIT
138
125
  metadata:
139
126
  homepage_uri: https://lostisland.github.io/faraday
140
- changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.0.0.alpha.pre.3
127
+ changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.1.0
141
128
  source_code_uri: https://github.com/lostisland/faraday
142
129
  bug_tracker_uri: https://github.com/lostisland/faraday/issues
143
130
  post_install_message:
@@ -152,9 +139,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
152
139
  version: '2.6'
153
140
  required_rubygems_version: !ruby/object:Gem::Requirement
154
141
  requirements:
155
- - - ">"
142
+ - - ">="
156
143
  - !ruby/object:Gem::Version
157
- version: 1.3.1
144
+ version: '0'
158
145
  requirements: []
159
146
  rubygems_version: 3.1.6
160
147
  signing_key:
@@ -1,122 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'stringio'
4
-
5
- # multipart-post gem
6
- require 'composite_io'
7
- require 'parts'
8
-
9
- module Faraday
10
- # Multipart value used to POST a binary data from a file or
11
- #
12
- # @example
13
- # payload = { file: Faraday::FilePart.new("file_name.ext", "content/type") }
14
- # http.post("/upload", payload)
15
- #
16
-
17
- # @!method initialize(filename_or_io, content_type, filename = nil, opts = {})
18
- #
19
- # @param filename_or_io [String, IO] Either a String filename to a local
20
- # file or an open IO object.
21
- # @param content_type [String] String content type of the file data.
22
- # @param filename [String] Optional String filename, usually to add context
23
- # to a given IO object.
24
- # @param opts [Hash] Optional Hash of String key/value pairs to describethis
25
- # this uploaded file. Expected Header keys include:
26
- # * Content-Transfer-Encoding - Defaults to "binary"
27
- # * Content-Disposition - Defaults to "form-data"
28
- # * Content-Type - Defaults to the content_type argument.
29
- # * Content-ID - Optional.
30
- #
31
- # @return [Faraday::FilePart]
32
- #
33
- # @!attribute [r] content_type
34
- # The uploaded binary data's content type.
35
- #
36
- # @return [String]
37
- #
38
- # @!attribute [r] original_filename
39
- # The base filename, taken either from the filename_or_io or filename
40
- # arguments in #initialize.
41
- #
42
- # @return [String]
43
- #
44
- # @!attribute [r] opts
45
- # Extra String key/value pairs to make up the header for this uploaded file.
46
- #
47
- # @return [Hash]
48
- #
49
- # @!attribute [r] io
50
- # The open IO object for the uploaded file.
51
- #
52
- # @return [IO]
53
- FilePart = ::UploadIO
54
-
55
- Parts = ::Parts
56
-
57
- # Similar to, but not compatible with CompositeReadIO provided by the
58
- # multipart-post gem.
59
- # https://github.com/nicksieger/multipart-post/blob/master/lib/composite_io.rb
60
- class CompositeReadIO
61
- def initialize(*parts)
62
- @parts = parts.flatten
63
- @ios = @parts.map(&:to_io)
64
- @index = 0
65
- end
66
-
67
- # @return [Integer] sum of the lengths of all the parts
68
- def length
69
- @parts.inject(0) { |sum, part| sum + part.length }
70
- end
71
-
72
- # Rewind each of the IOs and reset the index to 0.
73
- #
74
- # @return [void]
75
- def rewind
76
- @ios.each(&:rewind)
77
- @index = 0
78
- end
79
-
80
- # Read from IOs in order until `length` bytes have been received.
81
- #
82
- # @param length [Integer, nil]
83
- # @param outbuf [String, nil]
84
- def read(length = nil, outbuf = nil)
85
- got_result = false
86
- outbuf = outbuf ? (+outbuf).replace('') : +''
87
-
88
- while (io = current_io)
89
- if (result = io.read(length))
90
- got_result ||= !result.nil?
91
- result.force_encoding('BINARY') if result.respond_to?(:force_encoding)
92
- outbuf << result
93
- length -= result.length if length
94
- break if length&.zero?
95
- end
96
- advance_io
97
- end
98
- !got_result && length ? nil : outbuf
99
- end
100
-
101
- # Close each of the IOs.
102
- #
103
- # @return [void]
104
- def close
105
- @ios.each(&:close)
106
- end
107
-
108
- def ensure_open_and_readable
109
- # Rubinius compatibility
110
- end
111
-
112
- private
113
-
114
- def current_io
115
- @ios[@index]
116
- end
117
-
118
- def advance_io
119
- @index += 1
120
- end
121
- end
122
- end