faraday 1.7.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +193 -3
  3. data/README.md +11 -9
  4. data/examples/client_spec.rb +19 -19
  5. data/examples/client_test.rb +22 -22
  6. data/lib/faraday/adapter/test.rb +10 -4
  7. data/lib/faraday/adapter.rb +2 -5
  8. data/lib/faraday/connection.rb +17 -93
  9. data/lib/faraday/encoders/nested_params_encoder.rb +2 -2
  10. data/lib/faraday/error.rb +3 -8
  11. data/lib/faraday/logging/formatter.rb +1 -0
  12. data/lib/faraday/middleware.rb +0 -1
  13. data/lib/faraday/middleware_registry.rb +17 -63
  14. data/lib/faraday/options.rb +3 -3
  15. data/lib/faraday/rack_builder.rb +23 -20
  16. data/lib/faraday/request/authorization.rb +32 -38
  17. data/lib/faraday/request/instrumentation.rb +2 -0
  18. data/lib/faraday/request/json.rb +55 -0
  19. data/lib/faraday/request/url_encoded.rb +2 -0
  20. data/lib/faraday/request.rb +11 -31
  21. data/lib/faraday/response/json.rb +54 -0
  22. data/lib/faraday/response/logger.rb +4 -4
  23. data/lib/faraday/response/raise_error.rb +9 -1
  24. data/lib/faraday/response.rb +8 -19
  25. data/lib/faraday/utils/headers.rb +1 -1
  26. data/lib/faraday/utils.rb +10 -5
  27. data/lib/faraday/version.rb +1 -1
  28. data/lib/faraday.rb +11 -39
  29. data/spec/faraday/connection_spec.rb +136 -85
  30. data/spec/faraday/middleware_registry_spec.rb +31 -0
  31. data/spec/faraday/options/env_spec.rb +2 -2
  32. data/spec/faraday/rack_builder_spec.rb +26 -54
  33. data/spec/faraday/request/authorization_spec.rb +19 -24
  34. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  35. data/spec/faraday/request/json_spec.rb +111 -0
  36. data/spec/faraday/request/url_encoded_spec.rb +0 -1
  37. data/spec/faraday/request_spec.rb +4 -15
  38. data/spec/faraday/response/json_spec.rb +117 -0
  39. data/spec/faraday/response/raise_error_spec.rb +7 -4
  40. data/spec/faraday/utils/headers_spec.rb +2 -2
  41. data/spec/faraday/utils_spec.rb +62 -1
  42. data/spec/support/fake_safe_buffer.rb +1 -1
  43. data/spec/support/helper_methods.rb +0 -37
  44. data/spec/support/shared_examples/adapter.rb +0 -1
  45. data/spec/support/shared_examples/request_method.rb +5 -18
  46. metadata +12 -147
  47. data/lib/faraday/adapter/typhoeus.rb +0 -15
  48. data/lib/faraday/autoload.rb +0 -87
  49. data/lib/faraday/dependency_loader.rb +0 -37
  50. data/lib/faraday/file_part.rb +0 -128
  51. data/lib/faraday/param_part.rb +0 -53
  52. data/lib/faraday/request/basic_authentication.rb +0 -20
  53. data/lib/faraday/request/multipart.rb +0 -106
  54. data/lib/faraday/request/retry.rb +0 -239
  55. data/lib/faraday/request/token_authentication.rb +0 -20
  56. data/spec/faraday/adapter/em_http_spec.rb +0 -49
  57. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -18
  58. data/spec/faraday/adapter/excon_spec.rb +0 -49
  59. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  60. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  61. data/spec/faraday/adapter/patron_spec.rb +0 -18
  62. data/spec/faraday/adapter/rack_spec.rb +0 -8
  63. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  64. data/spec/faraday/composite_read_io_spec.rb +0 -80
  65. data/spec/faraday/request/multipart_spec.rb +0 -302
  66. data/spec/faraday/request/retry_spec.rb +0 -242
  67. data/spec/faraday/response/middleware_spec.rb +0 -68
  68. data/spec/support/webmock_rack_app.rb +0 -68
@@ -3,7 +3,7 @@
3
3
  RSpec.describe Faraday::Request::Authorization do
4
4
  let(:conn) do
5
5
  Faraday.new do |b|
6
- b.request auth_type, *auth_config
6
+ b.request :authorization, auth_type, *auth_config
7
7
  b.adapter :test do |stub|
8
8
  stub.get('/auth-echo') do |env|
9
9
  [200, {}, env[:request_headers]['Authorization']]
@@ -14,10 +14,10 @@ RSpec.describe Faraday::Request::Authorization do
14
14
 
15
15
  shared_examples 'does not interfere with existing authentication' do
16
16
  context 'and request already has an authentication header' do
17
- let(:response) { conn.get('/auth-echo', nil, authorization: 'Token token="bar"') }
17
+ let(:response) { conn.get('/auth-echo', nil, authorization: 'OAuth oauth_token') }
18
18
 
19
19
  it 'does not interfere with existing authorization' do
20
- expect(response.body).to eq('Token token="bar"')
20
+ expect(response.body).to eq('OAuth oauth_token')
21
21
  end
22
22
  end
23
23
  end
@@ -25,7 +25,7 @@ RSpec.describe Faraday::Request::Authorization do
25
25
  let(:response) { conn.get('/auth-echo') }
26
26
 
27
27
  describe 'basic_auth' do
28
- let(:auth_type) { :basic_auth }
28
+ let(:auth_type) { :basic }
29
29
 
30
30
  context 'when passed correct params' do
31
31
  let(:auth_config) { %w[aladdin opensesame] }
@@ -44,43 +44,38 @@ RSpec.describe Faraday::Request::Authorization do
44
44
  end
45
45
  end
46
46
 
47
- describe 'token_auth' do
48
- let(:auth_type) { :token_auth }
47
+ describe 'authorization' do
48
+ let(:auth_type) { :Bearer }
49
49
 
50
- context 'when passed correct params' do
51
- let(:auth_config) { 'quux' }
50
+ context 'when passed a string' do
51
+ let(:auth_config) { ['custom'] }
52
52
 
53
- it { expect(response.body).to eq('Token token="quux"') }
53
+ it { expect(response.body).to eq('Bearer custom') }
54
54
 
55
55
  include_examples 'does not interfere with existing authentication'
56
56
  end
57
57
 
58
- context 'when other values are provided' do
59
- let(:auth_config) { ['baz', { foo: 42 }] }
58
+ context 'when passed a proc' do
59
+ let(:auth_config) { [-> { 'custom_from_proc' }] }
60
60
 
61
- it { expect(response.body).to match(/^Token /) }
62
- it { expect(response.body).to match(/token="baz"/) }
63
- it { expect(response.body).to match(/foo="42"/) }
61
+ it { expect(response.body).to eq('Bearer custom_from_proc') }
64
62
 
65
63
  include_examples 'does not interfere with existing authentication'
66
64
  end
67
- end
68
-
69
- describe 'authorization' do
70
- let(:auth_type) { :authorization }
71
65
 
72
- context 'when passed two strings' do
73
- let(:auth_config) { ['custom', 'abc def'] }
66
+ context 'when passed a callable' do
67
+ let(:callable) { double('Callable Authorizer', call: 'custom_from_callable') }
68
+ let(:auth_config) { [callable] }
74
69
 
75
- it { expect(response.body).to eq('custom abc def') }
70
+ it { expect(response.body).to eq('Bearer custom_from_callable') }
76
71
 
77
72
  include_examples 'does not interfere with existing authentication'
78
73
  end
79
74
 
80
- context 'when passed a string and a hash' do
81
- let(:auth_config) { ['baz', { foo: 42 }] }
75
+ context 'when passed too many arguments' do
76
+ let(:auth_config) { %w[baz foo] }
82
77
 
83
- it { expect(response.body).to eq('baz foo="42"') }
78
+ it { expect { response }.to raise_error(ArgumentError) }
84
79
 
85
80
  include_examples 'does not interfere with existing authentication'
86
81
  end
@@ -30,13 +30,11 @@ RSpec.describe Faraday::Request::Instrumentation do
30
30
 
31
31
  it { expect(options.name).to eq('request.faraday') }
32
32
  it 'defaults to ActiveSupport::Notifications' do
33
- begin
34
- res = options.instrumenter
35
- rescue NameError => e
36
- expect(e.to_s).to match('ActiveSupport')
37
- else
38
- expect(res).to eq(ActiveSupport::Notifications)
39
- end
33
+ res = options.instrumenter
34
+ rescue NameError => e
35
+ expect(e.to_s).to match('ActiveSupport')
36
+ else
37
+ expect(res).to eq(ActiveSupport::Notifications)
40
38
  end
41
39
 
42
40
  it 'instruments with default name' do
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Request::Json do
4
+ let(:middleware) { described_class.new(->(env) { Faraday::Response.new(env) }) }
5
+
6
+ def process(body, content_type = nil)
7
+ env = { body: body, request_headers: Faraday::Utils::Headers.new }
8
+ env[:request_headers]['content-type'] = content_type if content_type
9
+ middleware.call(Faraday::Env.from(env)).env
10
+ end
11
+
12
+ def result_body
13
+ result[:body]
14
+ end
15
+
16
+ def result_type
17
+ result[:request_headers]['content-type']
18
+ end
19
+
20
+ context 'no body' do
21
+ let(:result) { process(nil) }
22
+
23
+ it "doesn't change body" do
24
+ expect(result_body).to be_nil
25
+ end
26
+
27
+ it "doesn't add content type" do
28
+ expect(result_type).to be_nil
29
+ end
30
+ end
31
+
32
+ context 'empty body' do
33
+ let(:result) { process('') }
34
+
35
+ it "doesn't change body" do
36
+ expect(result_body).to be_empty
37
+ end
38
+
39
+ it "doesn't add content type" do
40
+ expect(result_type).to be_nil
41
+ end
42
+ end
43
+
44
+ context 'string body' do
45
+ let(:result) { process('{"a":1}') }
46
+
47
+ it "doesn't change body" do
48
+ expect(result_body).to eq('{"a":1}')
49
+ end
50
+
51
+ it 'adds content type' do
52
+ expect(result_type).to eq('application/json')
53
+ end
54
+ end
55
+
56
+ context 'object body' do
57
+ let(:result) { process(a: 1) }
58
+
59
+ it 'encodes body' do
60
+ expect(result_body).to eq('{"a":1}')
61
+ end
62
+
63
+ it 'adds content type' do
64
+ expect(result_type).to eq('application/json')
65
+ end
66
+ end
67
+
68
+ context 'empty object body' do
69
+ let(:result) { process({}) }
70
+
71
+ it 'encodes body' do
72
+ expect(result_body).to eq('{}')
73
+ end
74
+ end
75
+
76
+ context 'object body with json type' do
77
+ let(:result) { process({ a: 1 }, 'application/json; charset=utf-8') }
78
+
79
+ it 'encodes body' do
80
+ expect(result_body).to eq('{"a":1}')
81
+ end
82
+
83
+ it "doesn't change content type" do
84
+ expect(result_type).to eq('application/json; charset=utf-8')
85
+ end
86
+ end
87
+
88
+ context 'object body with vendor json type' do
89
+ let(:result) { process({ a: 1 }, 'application/vnd.myapp.v1+json; charset=utf-8') }
90
+
91
+ it 'encodes body' do
92
+ expect(result_body).to eq('{"a":1}')
93
+ end
94
+
95
+ it "doesn't change content type" do
96
+ expect(result_type).to eq('application/vnd.myapp.v1+json; charset=utf-8')
97
+ end
98
+ end
99
+
100
+ context 'object body with incompatible type' do
101
+ let(:result) { process({ a: 1 }, 'application/xml; charset=utf-8') }
102
+
103
+ it "doesn't change body" do
104
+ expect(result_body).to eq(a: 1)
105
+ end
106
+
107
+ it "doesn't change content type" do
108
+ expect(result_type).to eq('application/xml; charset=utf-8')
109
+ end
110
+ end
111
+ end
@@ -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|
@@ -2,7 +2,7 @@
2
2
 
3
3
  RSpec.describe Faraday::Request do
4
4
  let(:conn) do
5
- Faraday.new(url: 'http://sushi.com/api',
5
+ Faraday.new(url: 'http://httpbingo.org/api',
6
6
  headers: { 'Mime-Version' => '1.0' },
7
7
  request: { oauth: { consumer_key: 'anonymous' } })
8
8
  end
@@ -22,23 +22,12 @@ RSpec.describe Faraday::Request do
22
22
  it { expect(subject.http_method).to eq(:post) }
23
23
  end
24
24
 
25
- describe 'deprecate method for HTTP method' do
26
- let(:http_method) { :post }
27
- let(:expected_warning) do
28
- %r{WARNING: `Faraday::Request#method` is deprecated; use `#http_method` instead. It will be removed in or after version 2.0.\n`Faraday::Request#method` called from .+/spec/faraday/request_spec.rb:\d+.}
29
- end
30
-
31
- it { expect(subject.method).to eq(:post) }
32
-
33
- it { expect { subject.method }.to output(expected_warning).to_stderr }
34
- end
35
-
36
25
  context 'when setting the url on setup with a URI' do
37
26
  let(:block) { proc { |req| req.url URI.parse('foo.json?a=1') } }
38
27
 
39
28
  it { expect(subject.path).to eq(URI.parse('foo.json')) }
40
29
  it { expect(subject.params).to eq('a' => '1') }
41
- it { expect(subject.to_env(conn).url.to_s).to eq('http://sushi.com/api/foo.json?a=1') }
30
+ it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') }
42
31
  end
43
32
 
44
33
  context 'when setting the url on setup with a string path and params' do
@@ -46,7 +35,7 @@ RSpec.describe Faraday::Request do
46
35
 
47
36
  it { expect(subject.path).to eq('foo.json') }
48
37
  it { expect(subject.params).to eq('a' => 1) }
49
- it { expect(subject.to_env(conn).url.to_s).to eq('http://sushi.com/api/foo.json?a=1') }
38
+ it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') }
50
39
  end
51
40
 
52
41
  context 'when setting the url on setup with a path including params' do
@@ -54,7 +43,7 @@ RSpec.describe Faraday::Request do
54
43
 
55
44
  it { expect(subject.path).to eq('foo.json') }
56
45
  it { expect(subject.params).to eq('a' => '1', 'b' => '2') }
57
- it { expect(subject.to_env(conn).url.to_s).to eq('http://sushi.com/api/foo.json?a=1&b=2') }
46
+ it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1&b=2') }
58
47
  end
59
48
 
60
49
  context 'when setting a header on setup with []= syntax' do
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Response::Json, type: :response do
4
+ let(:options) { {} }
5
+ let(:headers) { {} }
6
+ let(:middleware) do
7
+ described_class.new(lambda { |env|
8
+ Faraday::Response.new(env)
9
+ }, **options)
10
+ end
11
+
12
+ def process(body, content_type = 'application/json', options = {})
13
+ env = {
14
+ body: body, request: options,
15
+ request_headers: Faraday::Utils::Headers.new,
16
+ response_headers: Faraday::Utils::Headers.new(headers)
17
+ }
18
+ env[:response_headers]['content-type'] = content_type if content_type
19
+ yield(env) if block_given?
20
+ middleware.call(Faraday::Env.from(env))
21
+ end
22
+
23
+ context 'no type matching' do
24
+ it "doesn't change nil body" do
25
+ expect(process(nil).body).to be_nil
26
+ end
27
+
28
+ it 'nullifies empty body' do
29
+ expect(process('').body).to be_nil
30
+ end
31
+
32
+ it 'parses json body' do
33
+ response = process('{"a":1}')
34
+ expect(response.body).to eq('a' => 1)
35
+ expect(response.env[:raw_body]).to be_nil
36
+ end
37
+ end
38
+
39
+ context 'with preserving raw' do
40
+ let(:options) { { preserve_raw: true } }
41
+
42
+ it 'parses json body' do
43
+ response = process('{"a":1}')
44
+ expect(response.body).to eq('a' => 1)
45
+ expect(response.env[:raw_body]).to eq('{"a":1}')
46
+ end
47
+ end
48
+
49
+ context 'with default regexp type matching' do
50
+ it 'parses json body of correct type' do
51
+ response = process('{"a":1}', 'application/x-json')
52
+ expect(response.body).to eq('a' => 1)
53
+ end
54
+
55
+ it 'ignores json body of incorrect type' do
56
+ response = process('{"a":1}', 'text/json-xml')
57
+ expect(response.body).to eq('{"a":1}')
58
+ end
59
+ end
60
+
61
+ context 'with array type matching' do
62
+ let(:options) { { content_type: %w[a/b c/d] } }
63
+
64
+ it 'parses json body of correct type' do
65
+ expect(process('{"a":1}', 'a/b').body).to be_a(Hash)
66
+ expect(process('{"a":1}', 'c/d').body).to be_a(Hash)
67
+ end
68
+
69
+ it 'ignores json body of incorrect type' do
70
+ expect(process('{"a":1}', 'a/d').body).not_to be_a(Hash)
71
+ end
72
+ end
73
+
74
+ it 'chokes on invalid json' do
75
+ expect { process('{!') }.to raise_error(Faraday::ParsingError)
76
+ end
77
+
78
+ it 'includes the response on the ParsingError instance' do
79
+ process('{') { |env| env[:response] = Faraday::Response.new }
80
+ raise 'Parsing should have failed.'
81
+ rescue Faraday::ParsingError => e
82
+ expect(e.response).to be_a(Faraday::Response)
83
+ end
84
+
85
+ context 'HEAD responses' do
86
+ it "nullifies the body if it's only one space" do
87
+ response = process(' ')
88
+ expect(response.body).to be_nil
89
+ end
90
+
91
+ it "nullifies the body if it's two spaces" do
92
+ response = process(' ')
93
+ expect(response.body).to be_nil
94
+ end
95
+ end
96
+
97
+ context 'JSON options' do
98
+ let(:body) { '{"a": 1}' }
99
+ let(:result) { { a: 1 } }
100
+ let(:options) do
101
+ {
102
+ parser_options: {
103
+ symbolize_names: true
104
+ }
105
+ }
106
+ end
107
+
108
+ it 'passes relevant options to JSON parse' do
109
+ expect(::JSON).to receive(:parse)
110
+ .with(body, options[:parser_options])
111
+ .and_return(result)
112
+
113
+ response = process(body)
114
+ expect(response.body).to eq(result)
115
+ end
116
+ end
117
+ end
@@ -139,7 +139,7 @@ RSpec.describe Faraday::Response::RaiseError do
139
139
  Faraday.new do |b|
140
140
  b.response :raise_error
141
141
  b.adapter :test do |stub|
142
- stub.post('request?full=true', request_body, request_headers) do
142
+ stub.post(url, request_body, request_headers) do
143
143
  [400, { 'X-Reason' => 'because' }, 'keep looking']
144
144
  end
145
145
  end
@@ -147,11 +147,13 @@ RSpec.describe Faraday::Response::RaiseError do
147
147
  end
148
148
  let(:request_body) { JSON.generate({ 'item' => 'sth' }) }
149
149
  let(:request_headers) { { 'Authorization' => 'Basic 123' } }
150
+ let(:url_path) { 'request' }
151
+ let(:query_params) { 'full=true' }
152
+ let(:url) { "#{url_path}?#{query_params}" }
150
153
 
151
154
  subject(:perform_request) do
152
- conn.post 'request' do |req|
155
+ conn.post url do |req|
153
156
  req.headers['Authorization'] = 'Basic 123'
154
- req.params[:full] = true
155
157
  req.body = request_body
156
158
  end
157
159
  end
@@ -159,7 +161,8 @@ RSpec.describe Faraday::Response::RaiseError do
159
161
  it 'returns the request info in the exception' do
160
162
  expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
161
163
  expect(ex.response[:request][:method]).to eq(:post)
162
- expect(ex.response[:request][:url_path]).to eq('/request')
164
+ expect(ex.response[:request][:url]).to eq(URI("http:/#{url}"))
165
+ expect(ex.response[:request][:url_path]).to eq("/#{url_path}")
163
166
  expect(ex.response[:request][:params]).to eq({ 'full' => 'true' })
164
167
  expect(ex.response[:request][:headers]).to match(a_hash_including(request_headers))
165
168
  expect(ex.response[:request][:body]).to eq(request_body)
@@ -68,9 +68,9 @@ RSpec.describe Faraday::Utils::Headers do
68
68
  end
69
69
 
70
70
  context 'when response headers values include a colon' do
71
- let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://sushi.com/\r\n\r\n" }
71
+ let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://httpbingo.org/\r\n\r\n" }
72
72
 
73
- it { expect(subject['location']).to eq('http://sushi.com/') }
73
+ it { expect(subject['location']).to eq('http://httpbingo.org/') }
74
74
  end
75
75
 
76
76
  context 'when response headers include a blank line' do
@@ -4,7 +4,7 @@ RSpec.describe Faraday::Utils do
4
4
  describe 'headers parsing' do
5
5
  let(:multi_response_headers) do
6
6
  "HTTP/1.x 500 OK\r\nContent-Type: text/html; charset=UTF-8\r\n" \
7
- "HTTP/1.x 200 OK\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n"
7
+ "HTTP/1.x 200 OK\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n"
8
8
  end
9
9
 
10
10
  it 'parse headers for aggregated responses' do
@@ -53,4 +53,65 @@ RSpec.describe Faraday::Utils do
53
53
  expect(headers).not_to have_key('authorization')
54
54
  end
55
55
  end
56
+
57
+ describe '.deep_merge!' do
58
+ let(:connection_options) { Faraday::ConnectionOptions.new }
59
+ let(:url) do
60
+ {
61
+ url: 'http://example.com/abc',
62
+ headers: { 'Mime-Version' => '1.0' },
63
+ request: { oauth: { consumer_key: 'anonymous' } },
64
+ ssl: { version: '2' }
65
+ }
66
+ end
67
+
68
+ it 'recursively merges the headers' do
69
+ connection_options.headers = { user_agent: 'My Agent 1.0' }
70
+ deep_merge = Faraday::Utils.deep_merge!(connection_options, url)
71
+
72
+ expect(deep_merge.headers).to eq('Mime-Version' => '1.0', user_agent: 'My Agent 1.0')
73
+ end
74
+
75
+ context 'when a target hash has an Options Struct value' do
76
+ let(:request) do
77
+ {
78
+ params_encoder: nil,
79
+ proxy: nil,
80
+ bind: nil,
81
+ timeout: nil,
82
+ open_timeout: nil,
83
+ read_timeout: nil,
84
+ write_timeout: nil,
85
+ boundary: nil,
86
+ oauth: { consumer_key: 'anonymous' },
87
+ context: nil,
88
+ on_data: nil
89
+ }
90
+ end
91
+ let(:ssl) do
92
+ {
93
+ verify: nil,
94
+ ca_file: nil,
95
+ ca_path: nil,
96
+ verify_mode: nil,
97
+ cert_store: nil,
98
+ client_cert: nil,
99
+ client_key: nil,
100
+ certificate: nil,
101
+ private_key: nil,
102
+ verify_depth: nil,
103
+ version: '2',
104
+ min_version: nil,
105
+ max_version: nil
106
+ }
107
+ end
108
+
109
+ it 'does not overwrite an Options Struct value' do
110
+ deep_merge = Faraday::Utils.deep_merge!(connection_options, url)
111
+
112
+ expect(deep_merge.request.to_h).to eq(request)
113
+ expect(deep_merge.ssl.to_h).to eq(ssl)
114
+ end
115
+ end
116
+ end
56
117
  end
@@ -8,7 +8,7 @@ FakeSafeBuffer = Struct.new(:string) do
8
8
 
9
9
  def gsub(regex)
10
10
  string.gsub(regex) do
11
- match, = $&, '' =~ /a/
11
+ match, = Regexp.last_match(0), '' =~ /a/ # rubocop:disable Performance/StringInclude
12
12
  yield(match)
13
13
  end
14
14
  end
@@ -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
@@ -79,7 +79,7 @@ shared_examples 'a request method' do |http_method|
79
79
 
80
80
  on_feature :request_body_on_query_methods do
81
81
  it 'sends request body' do
82
- request_stub.with(Hash[:body, 'test'])
82
+ request_stub.with({ body: 'test' })
83
83
  res = if query_or_body == :body
84
84
  conn.public_send(http_method, '/', 'test')
85
85
  else
@@ -93,7 +93,7 @@ shared_examples 'a request method' do |http_method|
93
93
 
94
94
  it 'sends url encoded parameters' do
95
95
  payload = { name: 'zack' }
96
- request_stub.with(Hash[query_or_body, payload])
96
+ request_stub.with({ query_or_body => payload })
97
97
  res = conn.public_send(http_method, '/', payload)
98
98
  if query_or_body == :query
99
99
  expect(res.env.request_body).to be_nil
@@ -104,7 +104,7 @@ shared_examples 'a request method' do |http_method|
104
104
 
105
105
  it 'sends url encoded nested parameters' do
106
106
  payload = { name: { first: 'zack' } }
107
- request_stub.with(Hash[query_or_body, payload])
107
+ request_stub.with({ query_or_body => payload })
108
108
  conn.public_send(http_method, '/', payload)
109
109
  end
110
110
 
@@ -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'])
@@ -199,11 +186,11 @@ shared_examples 'a request method' do |http_method|
199
186
  @payload2 = { b: '2' }
200
187
 
201
188
  request_stub
202
- .with(Hash[query_or_body, @payload1])
189
+ .with({ query_or_body => @payload1 })
203
190
  .to_return(body: @payload1.to_json)
204
191
 
205
192
  stub_request(http_method, remote)
206
- .with(Hash[query_or_body, @payload2])
193
+ .with({ query_or_body => @payload2 })
207
194
  .to_return(body: @payload2.to_json)
208
195
 
209
196
  conn.in_parallel do