faraday 2.0.0.alpha.pre.3 → 2.1.0

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