faraday 0.17.6 → 1.0.1
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 +4 -4
- data/CHANGELOG.md +52 -8
- data/LICENSE.md +1 -1
- data/README.md +18 -358
- data/Rakefile +1 -7
- data/examples/client_spec.rb +65 -0
- data/examples/client_test.rb +79 -0
- data/lib/faraday/adapter/em_http.rb +142 -99
- data/lib/faraday/adapter/em_http_ssl_patch.rb +24 -18
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
- data/lib/faraday/adapter/em_synchrony.rb +104 -60
- data/lib/faraday/adapter/excon.rb +98 -56
- data/lib/faraday/adapter/httpclient.rb +83 -59
- data/lib/faraday/adapter/net_http.rb +129 -63
- data/lib/faraday/adapter/net_http_persistent.rb +50 -27
- data/lib/faraday/adapter/patron.rb +80 -43
- data/lib/faraday/adapter/rack.rb +30 -13
- data/lib/faraday/adapter/test.rb +86 -53
- data/lib/faraday/adapter/typhoeus.rb +4 -1
- data/lib/faraday/adapter.rb +82 -22
- data/lib/faraday/adapter_registry.rb +30 -0
- data/lib/faraday/autoload.rb +47 -36
- data/lib/faraday/connection.rb +312 -182
- data/lib/faraday/dependency_loader.rb +37 -0
- data/lib/faraday/encoders/flat_params_encoder.rb +98 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
- data/lib/faraday/error.rb +9 -35
- data/lib/faraday/file_part.rb +128 -0
- data/lib/faraday/logging/formatter.rb +105 -0
- data/lib/faraday/middleware.rb +12 -28
- data/lib/faraday/middleware_registry.rb +129 -0
- data/lib/faraday/options/connection_options.rb +22 -0
- data/lib/faraday/options/env.rb +181 -0
- data/lib/faraday/options/proxy_options.rb +28 -0
- data/lib/faraday/options/request_options.rb +22 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/options.rb +32 -183
- data/lib/faraday/param_part.rb +53 -0
- data/lib/faraday/parameters.rb +4 -197
- data/lib/faraday/rack_builder.rb +66 -55
- data/lib/faraday/request/authorization.rb +44 -30
- data/lib/faraday/request/basic_authentication.rb +14 -7
- data/lib/faraday/request/instrumentation.rb +45 -27
- data/lib/faraday/request/multipart.rb +79 -48
- data/lib/faraday/request/retry.rb +197 -171
- data/lib/faraday/request/token_authentication.rb +15 -10
- data/lib/faraday/request/url_encoded.rb +43 -23
- data/lib/faraday/request.rb +68 -38
- data/lib/faraday/response/logger.rb +22 -69
- data/lib/faraday/response/raise_error.rb +38 -18
- data/lib/faraday/response.rb +24 -14
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/lib/faraday/utils.rb +36 -245
- data/lib/faraday.rb +94 -175
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- data/spec/faraday/adapter/em_http_spec.rb +47 -0
- data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
- data/spec/faraday/adapter/excon_spec.rb +49 -0
- data/spec/faraday/adapter/httpclient_spec.rb +73 -0
- data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
- data/spec/faraday/adapter/net_http_spec.rb +64 -0
- data/spec/faraday/adapter/patron_spec.rb +18 -0
- data/spec/faraday/adapter/rack_spec.rb +8 -0
- data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
- data/spec/faraday/adapter_registry_spec.rb +28 -0
- data/spec/faraday/adapter_spec.rb +55 -0
- data/spec/faraday/composite_read_io_spec.rb +80 -0
- data/spec/faraday/connection_spec.rb +691 -0
- data/spec/faraday/error_spec.rb +0 -57
- data/spec/faraday/middleware_spec.rb +26 -0
- data/spec/faraday/options/env_spec.rb +70 -0
- data/spec/faraday/options/options_spec.rb +297 -0
- data/spec/faraday/options/proxy_options_spec.rb +37 -0
- data/spec/faraday/options/request_options_spec.rb +19 -0
- data/spec/faraday/params_encoders/flat_spec.rb +34 -0
- data/spec/faraday/params_encoders/nested_spec.rb +134 -0
- data/spec/faraday/rack_builder_spec.rb +196 -0
- data/spec/faraday/request/authorization_spec.rb +88 -0
- data/spec/faraday/request/instrumentation_spec.rb +76 -0
- data/spec/faraday/request/multipart_spec.rb +274 -0
- data/spec/faraday/request/retry_spec.rb +242 -0
- data/spec/faraday/request/url_encoded_spec.rb +83 -0
- data/spec/faraday/request_spec.rb +109 -0
- data/spec/faraday/response/logger_spec.rb +220 -0
- data/spec/faraday/response/middleware_spec.rb +68 -0
- data/spec/faraday/response/raise_error_spec.rb +15 -15
- data/spec/faraday/response_spec.rb +75 -0
- data/spec/faraday/utils/headers_spec.rb +82 -0
- data/spec/faraday/utils_spec.rb +56 -0
- data/spec/faraday_spec.rb +37 -0
- data/spec/spec_helper.rb +63 -36
- data/spec/support/disabling_stub.rb +14 -0
- data/spec/support/fake_safe_buffer.rb +15 -0
- data/spec/support/helper_methods.rb +133 -0
- data/spec/support/shared_examples/adapter.rb +104 -0
- data/spec/support/shared_examples/params_encoder.rb +18 -0
- data/spec/support/shared_examples/request_method.rb +234 -0
- data/spec/support/streaming_response_checker.rb +35 -0
- data/spec/support/webmock_rack_app.rb +68 -0
- metadata +66 -38
- data/lib/faraday/deprecate.rb +0 -109
- data/lib/faraday/upload_io.rb +0 -77
- data/spec/faraday/deprecate_spec.rb +0 -147
- data/test/adapters/default_test.rb +0 -14
- data/test/adapters/em_http_test.rb +0 -30
- data/test/adapters/em_synchrony_test.rb +0 -32
- data/test/adapters/excon_test.rb +0 -30
- data/test/adapters/httpclient_test.rb +0 -34
- data/test/adapters/integration.rb +0 -263
- data/test/adapters/logger_test.rb +0 -136
- data/test/adapters/net_http_persistent_test.rb +0 -114
- data/test/adapters/net_http_test.rb +0 -79
- data/test/adapters/patron_test.rb +0 -40
- data/test/adapters/rack_test.rb +0 -38
- data/test/adapters/test_middleware_test.rb +0 -157
- data/test/adapters/typhoeus_test.rb +0 -38
- data/test/authentication_middleware_test.rb +0 -65
- data/test/composite_read_io_test.rb +0 -109
- data/test/connection_test.rb +0 -738
- data/test/env_test.rb +0 -268
- data/test/helper.rb +0 -75
- data/test/live_server.rb +0 -67
- data/test/middleware/instrumentation_test.rb +0 -88
- data/test/middleware/retry_test.rb +0 -282
- data/test/middleware_stack_test.rb +0 -260
- data/test/multibyte.txt +0 -1
- data/test/options_test.rb +0 -333
- data/test/parameters_test.rb +0 -157
- data/test/request_middleware_test.rb +0 -126
- data/test/response_middleware_test.rb +0 -72
- data/test/strawberry.rb +0 -2
- data/test/utils_test.rb +0 -98
data/spec/faraday/error_spec.rb
CHANGED
@@ -41,62 +41,5 @@ RSpec.describe Faraday::ClientError do
|
|
41
41
|
it { expect(subject.message).to eq('["error1", "error2"]') }
|
42
42
|
it { expect(subject.inspect).to eq('#<Faraday::ClientError #<Faraday::ClientError: ["error1", "error2"]>>') }
|
43
43
|
end
|
44
|
-
|
45
|
-
context 'maintains backward-compatibility until 1.0' do
|
46
|
-
it 'does not raise an error for error-namespaced classes but prints an error message' do
|
47
|
-
error_message, error = with_warn_squelching { Faraday::Error::ClientError.new('foo') }
|
48
|
-
|
49
|
-
expect(error).to be_a Faraday::ClientError
|
50
|
-
expect(error_message).to match(
|
51
|
-
Regexp.new(
|
52
|
-
'NOTE: Faraday::Error::ClientError.new is deprecated; '\
|
53
|
-
'use Faraday::ClientError.new instead. It will be removed in or after version 1.0'
|
54
|
-
)
|
55
|
-
)
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'does not raise an error for inherited error-namespaced classes but prints an error message' do
|
59
|
-
error_message, = with_warn_squelching { Class.new(Faraday::Error::ClientError) }
|
60
|
-
|
61
|
-
expect(error_message).to match(
|
62
|
-
Regexp.new(
|
63
|
-
'NOTE: Inheriting Faraday::Error::ClientError is deprecated; '\
|
64
|
-
'use Faraday::ClientError instead. It will be removed in or after version 1.0'
|
65
|
-
)
|
66
|
-
)
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'allows backward-compatible class to be subclassed' do
|
70
|
-
expect {
|
71
|
-
with_warn_squelching { Class.new(Faraday::Error::ClientError) }
|
72
|
-
}.not_to raise_error
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'allows rescuing of a current error with a deprecated error' do
|
76
|
-
expect { raise Faraday::ClientError, nil }.to raise_error(Faraday::Error::ClientError)
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'allows rescuing of a current error with a current error' do
|
80
|
-
expect { raise Faraday::ClientError, nil }.to raise_error(Faraday::ClientError)
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'allows rescuing of a deprecated error with a deprecated error' do
|
84
|
-
expect { raise Faraday::Error::ClientError, nil }.to raise_error(Faraday::Error::ClientError)
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'allows rescuing of a deprecated error with a current error' do
|
88
|
-
expect { raise Faraday::Error::ClientError, nil }.to raise_error(Faraday::ClientError)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def with_warn_squelching
|
93
|
-
stderr_catcher = StringIO.new
|
94
|
-
original_stderr = $stderr
|
95
|
-
$stderr = stderr_catcher
|
96
|
-
result = yield if block_given?
|
97
|
-
[stderr_catcher.tap(&:rewind).string, result]
|
98
|
-
ensure
|
99
|
-
$stderr = original_stderr
|
100
|
-
end
|
101
44
|
end
|
102
45
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::Middleware do
|
4
|
+
subject { described_class.new(app) }
|
5
|
+
|
6
|
+
describe '#close' do
|
7
|
+
context "with app that doesn't support \#close" do
|
8
|
+
let(:app) { double }
|
9
|
+
|
10
|
+
it 'should issue warning' do
|
11
|
+
expect(subject).to receive(:warn)
|
12
|
+
subject.close
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "with app that supports \#close" do
|
17
|
+
let(:app) { double }
|
18
|
+
|
19
|
+
it 'should issue warning' do
|
20
|
+
expect(app).to receive(:close)
|
21
|
+
expect(subject).to_not receive(:warn)
|
22
|
+
subject.close
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::Env do
|
4
|
+
subject(:env) { described_class.new }
|
5
|
+
|
6
|
+
it 'allows to access members' do
|
7
|
+
expect(env.method).to be_nil
|
8
|
+
env.method = :get
|
9
|
+
expect(env.method).to eq(:get)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'allows to access symbol non members' do
|
13
|
+
expect(env[:custom]).to be_nil
|
14
|
+
env[:custom] = :boom
|
15
|
+
expect(env[:custom]).to eq(:boom)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'allows to access string non members' do
|
19
|
+
expect(env['custom']).to be_nil
|
20
|
+
env['custom'] = :boom
|
21
|
+
expect(env['custom']).to eq(:boom)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'ignores false when fetching' do
|
25
|
+
ssl = Faraday::SSLOptions.new
|
26
|
+
ssl.verify = false
|
27
|
+
expect(ssl.fetch(:verify, true)).to be_falsey
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'retains custom members' do
|
31
|
+
env[:foo] = 'custom 1'
|
32
|
+
env[:bar] = :custom_2
|
33
|
+
env2 = Faraday::Env.from(env)
|
34
|
+
env2[:baz] = 'custom 3'
|
35
|
+
|
36
|
+
expect(env2[:foo]).to eq('custom 1')
|
37
|
+
expect(env2[:bar]).to eq(:custom_2)
|
38
|
+
expect(env[:baz]).to be_nil
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#body' do
|
42
|
+
subject(:env) { described_class.from(body: { foo: 'bar' }) }
|
43
|
+
|
44
|
+
context 'when response is not finished yet' do
|
45
|
+
it 'returns the request body' do
|
46
|
+
expect(env.body).to eq(foo: 'bar')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when response is finished' do
|
51
|
+
before do
|
52
|
+
env.status = 200
|
53
|
+
env.body = { bar: 'foo' }
|
54
|
+
env.response = Faraday::Response.new(env)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns the response body' do
|
58
|
+
expect(env.body).to eq(bar: 'foo')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'allows to access request_body' do
|
62
|
+
expect(env.request_body).to eq(foo: 'bar')
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'allows to access response_body' do
|
66
|
+
expect(env.response_body).to eq(bar: 'foo')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,297 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::Options do
|
4
|
+
SubOptions = Class.new(Faraday::Options.new(:sub_a, :sub_b))
|
5
|
+
class ParentOptions < Faraday::Options.new(:a, :b, :c)
|
6
|
+
options c: SubOptions
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#merge' do
|
10
|
+
it 'merges options with hashes' do
|
11
|
+
options = ParentOptions.new(1)
|
12
|
+
expect(options.a).to eq(1)
|
13
|
+
expect(options.b).to be_nil
|
14
|
+
|
15
|
+
dup = options.merge a: 2, b: 3
|
16
|
+
expect(dup.a).to eq(2)
|
17
|
+
expect(dup.b).to eq(3)
|
18
|
+
expect(options.a).to eq(1)
|
19
|
+
expect(options.b).to be_nil
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'deeply merges two options' do
|
23
|
+
sub_opts1 = SubOptions.from(sub_a: 3)
|
24
|
+
sub_opts2 = SubOptions.from(sub_b: 4)
|
25
|
+
opt1 = ParentOptions.from(a: 1, c: sub_opts1)
|
26
|
+
opt2 = ParentOptions.from(b: 2, c: sub_opts2)
|
27
|
+
|
28
|
+
merged = opt1.merge(opt2)
|
29
|
+
|
30
|
+
expected_sub_opts = SubOptions.from(sub_a: 3, sub_b: 4)
|
31
|
+
expected = ParentOptions.from(a: 1, b: 2, c: expected_sub_opts)
|
32
|
+
expect(merged).to eq(expected)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'deeply merges options with hashes' do
|
36
|
+
sub_opts1 = SubOptions.from(sub_a: 3)
|
37
|
+
sub_opts2 = { sub_b: 4 }
|
38
|
+
opt1 = ParentOptions.from(a: 1, c: sub_opts1)
|
39
|
+
opt2 = { b: 2, c: sub_opts2 }
|
40
|
+
|
41
|
+
merged = opt1.merge(opt2)
|
42
|
+
|
43
|
+
expected_sub_opts = SubOptions.from(sub_a: 3, sub_b: 4)
|
44
|
+
expected = ParentOptions.from(a: 1, b: 2, c: expected_sub_opts)
|
45
|
+
expect(merged).to eq(expected)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'deeply merges options with nil' do
|
49
|
+
sub_opts = SubOptions.new(3, 4)
|
50
|
+
options = ParentOptions.new(1, 2, sub_opts)
|
51
|
+
expect(options.a).to eq(1)
|
52
|
+
expect(options.b).to eq(2)
|
53
|
+
expect(options.c.sub_a).to eq(3)
|
54
|
+
expect(options.c.sub_b).to eq(4)
|
55
|
+
|
56
|
+
options2 = ParentOptions.from(b: 5, c: nil)
|
57
|
+
|
58
|
+
merged = options.merge(options2)
|
59
|
+
|
60
|
+
expect(merged.b).to eq(5)
|
61
|
+
expect(merged.c).to eq(sub_opts)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'deeply merges options with options having nil sub-options' do
|
65
|
+
options = ParentOptions.from(a: 1)
|
66
|
+
|
67
|
+
sub_opts = SubOptions.new(3, 4)
|
68
|
+
options2 = ParentOptions.from(b: 2, c: sub_opts)
|
69
|
+
|
70
|
+
expect(options.a).to eq(1)
|
71
|
+
expect(options2.b).to eq(2)
|
72
|
+
expect(options2.c.sub_a).to eq(3)
|
73
|
+
expect(options2.c.sub_b).to eq(4)
|
74
|
+
|
75
|
+
merged = options.merge(options2)
|
76
|
+
|
77
|
+
expect(merged.c).to eq(sub_opts)
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#dup' do
|
81
|
+
it 'duplicate options but not sub-options' do
|
82
|
+
sub_opts = SubOptions.from(sub_a: 3)
|
83
|
+
opts = ParentOptions.from(b: 1, c: sub_opts)
|
84
|
+
|
85
|
+
duped = opts.dup
|
86
|
+
duped.b = 2
|
87
|
+
duped.c.sub_a = 4
|
88
|
+
|
89
|
+
expect(opts.b).to eq(1)
|
90
|
+
expect(opts.c.sub_a).to eq(4)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#deep_dup' do
|
95
|
+
it 'duplicate options and also suboptions' do
|
96
|
+
sub_opts = SubOptions.from(sub_a: 3)
|
97
|
+
opts = ParentOptions.from(b: 1, c: sub_opts)
|
98
|
+
|
99
|
+
duped = opts.deep_dup
|
100
|
+
duped.b = 2
|
101
|
+
duped.c.sub_a = 4
|
102
|
+
|
103
|
+
expect(opts.b).to eq(1)
|
104
|
+
expect(opts.c.sub_a).to eq(3)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '#clear' do
|
109
|
+
it 'clears the options' do
|
110
|
+
options = SubOptions.new(1)
|
111
|
+
expect(options.empty?).not_to be_truthy
|
112
|
+
options.clear
|
113
|
+
expect(options.empty?).to be_truthy
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#empty?' do
|
118
|
+
it 'returns true only if all options are nil' do
|
119
|
+
options = SubOptions.new
|
120
|
+
expect(options.empty?).to be_truthy
|
121
|
+
options.sub_a = 1
|
122
|
+
expect(options.empty?).not_to be_truthy
|
123
|
+
options.delete(:sub_a)
|
124
|
+
expect(options.empty?).to be_truthy
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#each_key' do
|
129
|
+
it 'allows to iterate through keys' do
|
130
|
+
options = ParentOptions.new(1, 2, 3)
|
131
|
+
enum = options.each_key
|
132
|
+
expect(enum.next.to_sym).to eq(:a)
|
133
|
+
expect(enum.next.to_sym).to eq(:b)
|
134
|
+
expect(enum.next.to_sym).to eq(:c)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe '#key?' do
|
139
|
+
it 'returns true if the key exists and is not nil' do
|
140
|
+
options = SubOptions.new
|
141
|
+
expect(options.key?(:sub_a)).not_to be_truthy
|
142
|
+
options.sub_a = 1
|
143
|
+
expect(options.key?(:sub_a)).to be_truthy
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe '#each_value' do
|
148
|
+
it 'allows to iterate through values' do
|
149
|
+
options = ParentOptions.new(1, 2, 3)
|
150
|
+
enum = options.each_value
|
151
|
+
expect(enum.next).to eq(1)
|
152
|
+
expect(enum.next).to eq(2)
|
153
|
+
expect(enum.next).to eq(3)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe '#value?' do
|
158
|
+
it 'returns true if any key has that value' do
|
159
|
+
options = SubOptions.new
|
160
|
+
expect(options.value?(1)).not_to be_truthy
|
161
|
+
options.sub_a = 1
|
162
|
+
expect(options.value?(1)).to be_truthy
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe '#update' do
|
167
|
+
it 'updates options from hashes' do
|
168
|
+
options = ParentOptions.new(1)
|
169
|
+
expect(options.a).to eq(1)
|
170
|
+
expect(options.b).to be_nil
|
171
|
+
|
172
|
+
updated = options.update a: 2, b: 3
|
173
|
+
expect(options.a).to eq(2)
|
174
|
+
expect(options.b).to eq(3)
|
175
|
+
expect(updated).to eq(options)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe '#delete' do
|
180
|
+
it 'allows to remove value for key' do
|
181
|
+
options = ParentOptions.new(1)
|
182
|
+
expect(options.a).to eq(1)
|
183
|
+
expect(options.delete(:a)).to eq(1)
|
184
|
+
expect(options.a).to be_nil
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe '#from' do
|
189
|
+
it { expect { ParentOptions.from invalid: 1 }.to raise_error(NoMethodError) }
|
190
|
+
|
191
|
+
it 'works with options' do
|
192
|
+
options = ParentOptions.new(1)
|
193
|
+
|
194
|
+
value = ParentOptions.from(options)
|
195
|
+
expect(value.a).to eq(1)
|
196
|
+
expect(value.b).to be_nil
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'works with options with sub object' do
|
200
|
+
sub = SubOptions.new(1)
|
201
|
+
options = ParentOptions.from a: 1, c: sub
|
202
|
+
expect(options).to be_a_kind_of(ParentOptions)
|
203
|
+
expect(options.a).to eq(1)
|
204
|
+
expect(options.b).to be_nil
|
205
|
+
expect(options.c).to be_a_kind_of(SubOptions)
|
206
|
+
expect(options.c.sub_a).to eq(1)
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'works with hash' do
|
210
|
+
options = ParentOptions.from a: 1
|
211
|
+
expect(options).to be_a_kind_of(ParentOptions)
|
212
|
+
expect(options.a).to eq(1)
|
213
|
+
expect(options.b).to be_nil
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'works with hash with sub object' do
|
217
|
+
options = ParentOptions.from a: 1, c: { sub_a: 1 }
|
218
|
+
expect(options).to be_a_kind_of(ParentOptions)
|
219
|
+
expect(options.a).to eq(1)
|
220
|
+
expect(options.b).to be_nil
|
221
|
+
expect(options.c).to be_a_kind_of(SubOptions)
|
222
|
+
expect(options.c.sub_a).to eq(1)
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'works with deep hash' do
|
226
|
+
hash = { b: 1 }
|
227
|
+
options = ParentOptions.from a: hash
|
228
|
+
expect(options.a[:b]).to eq(1)
|
229
|
+
|
230
|
+
hash[:b] = 2
|
231
|
+
expect(options.a[:b]).to eq(1)
|
232
|
+
|
233
|
+
options.a[:b] = 3
|
234
|
+
expect(hash[:b]).to eq(2)
|
235
|
+
expect(options.a[:b]).to eq(3)
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'works with nil' do
|
239
|
+
options = ParentOptions.from(nil)
|
240
|
+
expect(options).to be_a_kind_of(ParentOptions)
|
241
|
+
expect(options.a).to be_nil
|
242
|
+
expect(options.b).to be_nil
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'respects inheritance' do
|
246
|
+
subclass = Class.new(ParentOptions)
|
247
|
+
options = subclass.from(c: { sub_a: 'hello' })
|
248
|
+
expect(options.c).to be_a_kind_of(SubOptions)
|
249
|
+
expect(options.c.sub_a).to eq('hello')
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe '#memoized' do
|
254
|
+
subject(:options_class) { Class.new(ParentOptions) }
|
255
|
+
it 'requires block' do
|
256
|
+
expect { options_class.memoized(:a) }.to raise_error(ArgumentError)
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'accepts block' do
|
260
|
+
options_class.memoized(:a) { :foo }
|
261
|
+
expect(options_class.new.a).to eql(:foo)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
describe '#fetch' do
|
266
|
+
subject { SubOptions.new }
|
267
|
+
|
268
|
+
context 'when the fetched key has no value' do
|
269
|
+
it 'uses falsey default' do
|
270
|
+
expect(subject.fetch(:sub_a, false) { |_| :blah }).to be_falsey
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'accepts block' do
|
274
|
+
expect(subject.fetch(:sub_a) { |k| "yo #{k.inspect}" }).to eq('yo :sub_a')
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'needs a default if key is missing' do
|
278
|
+
expect { subject.fetch(:sub_a) }.to raise_error(Faraday::Options.fetch_error_class)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
context 'when the fetched key has a value' do
|
283
|
+
before do
|
284
|
+
subject.sub_a = 1
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'grabs value' do
|
288
|
+
expect(subject.fetch(:sub_a, false) { |_| :blah }).to eq(1)
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'works with key' do
|
292
|
+
expect(subject.fetch(:sub_a)).to eq(1)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::ProxyOptions do
|
4
|
+
describe '#from' do
|
5
|
+
it 'works with string' do
|
6
|
+
options = Faraday::ProxyOptions.from 'http://user:pass@example.org'
|
7
|
+
expect(options.user).to eq('user')
|
8
|
+
expect(options.password).to eq('pass')
|
9
|
+
expect(options.uri).to be_a_kind_of(URI)
|
10
|
+
expect(options.path).to eq('')
|
11
|
+
expect(options.port).to eq(80)
|
12
|
+
expect(options.host).to eq('example.org')
|
13
|
+
expect(options.scheme).to eq('http')
|
14
|
+
expect(options.inspect).to match('#<Faraday::ProxyOptions uri=')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'works with nil' do
|
18
|
+
options = Faraday::ProxyOptions.from nil
|
19
|
+
expect(options).to be_a_kind_of(Faraday::ProxyOptions)
|
20
|
+
expect(options.inspect).to eq('#<Faraday::ProxyOptions (empty)>')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'works with no auth' do
|
24
|
+
proxy = Faraday::ProxyOptions.from 'http://example.org'
|
25
|
+
expect(proxy.user).to be_nil
|
26
|
+
expect(proxy.password).to be_nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'allows hash access' do
|
31
|
+
proxy = Faraday::ProxyOptions.from 'http://a%40b:pw%20d@example.org'
|
32
|
+
expect(proxy.user).to eq('a@b')
|
33
|
+
expect(proxy[:user]).to eq('a@b')
|
34
|
+
expect(proxy.password).to eq('pw d')
|
35
|
+
expect(proxy[:password]).to eq('pw d')
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Faraday::RequestOptions do
|
4
|
+
subject(:options) { Faraday::RequestOptions.new }
|
5
|
+
|
6
|
+
it 'allows to set the request proxy' do
|
7
|
+
expect(options.proxy).to be_nil
|
8
|
+
|
9
|
+
expect { options[:proxy] = { booya: 1 } }.to raise_error(NoMethodError)
|
10
|
+
|
11
|
+
options[:proxy] = { user: 'user' }
|
12
|
+
expect(options.proxy).to be_a_kind_of(Faraday::ProxyOptions)
|
13
|
+
expect(options.proxy.user).to eq('user')
|
14
|
+
|
15
|
+
options.proxy = nil
|
16
|
+
expect(options.proxy).to be_nil
|
17
|
+
expect(options.inspect).to eq('#<Faraday::RequestOptions (empty)>')
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rack/utils'
|
4
|
+
|
5
|
+
RSpec.describe Faraday::FlatParamsEncoder do
|
6
|
+
it_behaves_like 'a params encoder'
|
7
|
+
|
8
|
+
it 'decodes arrays' do
|
9
|
+
query = 'a=one&a=two&a=three'
|
10
|
+
expected = { 'a' => %w[one two three] }
|
11
|
+
expect(subject.decode(query)).to eq(expected)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'decodes boolean values' do
|
15
|
+
query = 'a=true&b=false'
|
16
|
+
expected = { 'a' => 'true', 'b' => 'false' }
|
17
|
+
expect(subject.decode(query)).to eq(expected)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'encodes boolean values' do
|
21
|
+
params = { a: true, b: false }
|
22
|
+
expect(subject.encode(params)).to eq('a=true&b=false')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'encodes boolean values in array' do
|
26
|
+
params = { a: [true, false] }
|
27
|
+
expect(subject.encode(params)).to eq('a=true&a=false')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'encodes empty array in hash' do
|
31
|
+
params = { a: [] }
|
32
|
+
expect(subject.encode(params)).to eq('a=')
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rack/utils'
|
4
|
+
|
5
|
+
RSpec.describe Faraday::NestedParamsEncoder do
|
6
|
+
it_behaves_like 'a params encoder'
|
7
|
+
|
8
|
+
it 'decodes arrays' do
|
9
|
+
query = 'a[1]=one&a[2]=two&a[3]=three'
|
10
|
+
expected = { 'a' => %w[one two three] }
|
11
|
+
expect(subject.decode(query)).to eq(expected)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'decodes hashes' do
|
15
|
+
query = 'a[b1]=one&a[b2]=two&a[b][c]=foo'
|
16
|
+
expected = { 'a' => { 'b1' => 'one', 'b2' => 'two', 'b' => { 'c' => 'foo' } } }
|
17
|
+
expect(subject.decode(query)).to eq(expected)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'decodes nested arrays rack compat' do
|
21
|
+
query = 'a[][one]=1&a[][two]=2&a[][one]=3&a[][two]=4'
|
22
|
+
expected = Rack::Utils.parse_nested_query(query)
|
23
|
+
expect(subject.decode(query)).to eq(expected)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'decodes nested array mixed types' do
|
27
|
+
query = 'a[][one]=1&a[]=2&a[]=&a[]'
|
28
|
+
expected = Rack::Utils.parse_nested_query(query)
|
29
|
+
expect(subject.decode(query)).to eq(expected)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'decodes nested ignores invalid array' do
|
33
|
+
query = '[][a]=1&b=2'
|
34
|
+
expected = { 'a' => '1', 'b' => '2' }
|
35
|
+
expect(subject.decode(query)).to eq(expected)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'decodes nested ignores repeated array notation' do
|
39
|
+
query = 'a[][][]=1'
|
40
|
+
expected = { 'a' => ['1'] }
|
41
|
+
expect(subject.decode(query)).to eq(expected)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'decodes nested ignores malformed keys' do
|
45
|
+
query = '=1&[]=2'
|
46
|
+
expected = {}
|
47
|
+
expect(subject.decode(query)).to eq(expected)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'decodes nested subkeys dont have to be in brackets' do
|
51
|
+
query = 'a[b]c[d]e=1'
|
52
|
+
expected = { 'a' => { 'b' => { 'c' => { 'd' => { 'e' => '1' } } } } }
|
53
|
+
expect(subject.decode(query)).to eq(expected)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'decodes nested final value overrides any type' do
|
57
|
+
query = 'a[b][c]=1&a[b]=2'
|
58
|
+
expected = { 'a' => { 'b' => '2' } }
|
59
|
+
expect(subject.decode(query)).to eq(expected)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'encodes rack compat' do
|
63
|
+
params = { a: [{ one: '1', two: '2' }, '3', ''] }
|
64
|
+
result = Faraday::Utils.unescape(Faraday::NestedParamsEncoder.encode(params)).split('&')
|
65
|
+
expected = Rack::Utils.build_nested_query(params).split('&')
|
66
|
+
expect(result).to match_array(expected)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'encodes empty string array value' do
|
70
|
+
expected = 'baz=&foo%5Bbar%5D='
|
71
|
+
result = Faraday::NestedParamsEncoder.encode(foo: { bar: '' }, baz: '')
|
72
|
+
expect(result).to eq(expected)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'encodes nil array value' do
|
76
|
+
expected = 'baz&foo%5Bbar%5D'
|
77
|
+
result = Faraday::NestedParamsEncoder.encode(foo: { bar: nil }, baz: nil)
|
78
|
+
expect(result).to eq(expected)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'encodes empty array value' do
|
82
|
+
expected = 'baz%5B%5D&foo%5Bbar%5D%5B%5D'
|
83
|
+
result = Faraday::NestedParamsEncoder.encode(foo: { bar: [] }, baz: [])
|
84
|
+
expect(result).to eq(expected)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'encodes boolean values' do
|
88
|
+
params = { a: true, b: false }
|
89
|
+
expect(subject.encode(params)).to eq('a=true&b=false')
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'encodes boolean values in array' do
|
93
|
+
params = { a: [true, false] }
|
94
|
+
expect(subject.encode(params)).to eq('a%5B%5D=true&a%5B%5D=false')
|
95
|
+
end
|
96
|
+
|
97
|
+
shared_examples 'a wrong decoding' do
|
98
|
+
it do
|
99
|
+
expect { subject.decode(query) }.to raise_error(TypeError) do |e|
|
100
|
+
expect(e.message).to eq(error_message)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when expecting hash but getting string' do
|
106
|
+
let(:query) { 'a=1&a[b]=2' }
|
107
|
+
let(:error_message) { "expected Hash (got String) for param `a'" }
|
108
|
+
it_behaves_like 'a wrong decoding'
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when expecting hash but getting array' do
|
112
|
+
let(:query) { 'a[]=1&a[b]=2' }
|
113
|
+
let(:error_message) { "expected Hash (got Array) for param `a'" }
|
114
|
+
it_behaves_like 'a wrong decoding'
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when expecting nested hash but getting non nested' do
|
118
|
+
let(:query) { 'a[b]=1&a[b][c]=2' }
|
119
|
+
let(:error_message) { "expected Hash (got String) for param `b'" }
|
120
|
+
it_behaves_like 'a wrong decoding'
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'when expecting array but getting hash' do
|
124
|
+
let(:query) { 'a[b]=1&a[]=2' }
|
125
|
+
let(:error_message) { "expected Array (got Hash) for param `a'" }
|
126
|
+
it_behaves_like 'a wrong decoding'
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when expecting array but getting string' do
|
130
|
+
let(:query) { 'a=1&a[]=2' }
|
131
|
+
let(:error_message) { "expected Array (got String) for param `a'" }
|
132
|
+
it_behaves_like 'a wrong decoding'
|
133
|
+
end
|
134
|
+
end
|