faraday 0.15.4 → 0.16.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 +4 -4
- data/LICENSE.md +1 -1
- data/README.md +18 -344
- data/lib/faraday.rb +93 -175
- data/lib/faraday/adapter.rb +36 -22
- data/lib/faraday/adapter/em_http.rb +142 -99
- data/lib/faraday/adapter/em_http_ssl_patch.rb +23 -17
- data/lib/faraday/adapter/em_synchrony.rb +104 -60
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
- data/lib/faraday/adapter/excon.rb +100 -55
- data/lib/faraday/adapter/httpclient.rb +61 -39
- data/lib/faraday/adapter/net_http.rb +104 -51
- data/lib/faraday/adapter/net_http_persistent.rb +48 -27
- data/lib/faraday/adapter/patron.rb +54 -35
- data/lib/faraday/adapter/rack.rb +28 -12
- data/lib/faraday/adapter/test.rb +86 -53
- data/lib/faraday/adapter/typhoeus.rb +4 -1
- data/lib/faraday/adapter_registry.rb +28 -0
- data/lib/faraday/autoload.rb +47 -36
- data/lib/faraday/connection.rb +321 -179
- data/lib/faraday/dependency_loader.rb +37 -0
- data/lib/faraday/encoders/flat_params_encoder.rb +94 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
- data/lib/faraday/error.rb +67 -33
- data/lib/faraday/file_part.rb +128 -0
- data/lib/faraday/logging/formatter.rb +92 -0
- data/lib/faraday/middleware.rb +4 -28
- data/lib/faraday/middleware_registry.rb +129 -0
- data/lib/faraday/options.rb +35 -186
- 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 +21 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/param_part.rb +53 -0
- data/lib/faraday/parameters.rb +4 -197
- data/lib/faraday/rack_builder.rb +67 -56
- data/lib/faraday/request.rb +68 -36
- data/lib/faraday/request/authorization.rb +42 -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 +198 -169
- data/lib/faraday/request/token_authentication.rb +15 -10
- data/lib/faraday/request/url_encoded.rb +41 -23
- data/lib/faraday/response.rb +23 -16
- data/lib/faraday/response/logger.rb +22 -69
- data/lib/faraday/response/raise_error.rb +36 -14
- data/lib/faraday/utils.rb +28 -245
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- metadata +21 -5
- data/lib/faraday/upload_io.rb +0 -67
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
# ConnectionOptions contains the configurable properties for a Faraday
|
5
|
+
# connection object.
|
6
|
+
class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
|
7
|
+
:parallel_manager, :params, :headers,
|
8
|
+
:builder_class)
|
9
|
+
|
10
|
+
options request: RequestOptions, ssl: SSLOptions
|
11
|
+
|
12
|
+
memoized(:request) { self.class.options_for(:request).new }
|
13
|
+
|
14
|
+
memoized(:ssl) { self.class.options_for(:ssl).new }
|
15
|
+
|
16
|
+
memoized(:builder_class) { RackBuilder }
|
17
|
+
|
18
|
+
def new_builder(block)
|
19
|
+
builder_class.new(&block)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
# @!attribute method
|
5
|
+
# @return [Symbol] HTTP method (`:get`, `:post`)
|
6
|
+
#
|
7
|
+
# @!attribute body
|
8
|
+
# @return [String] The request body that will eventually be converted to a
|
9
|
+
# string.
|
10
|
+
#
|
11
|
+
# @!attribute url
|
12
|
+
# @return [URI] URI instance for the current request.
|
13
|
+
#
|
14
|
+
# @!attribute request
|
15
|
+
# @return [Hash] options for configuring the request.
|
16
|
+
# Options for configuring the request.
|
17
|
+
#
|
18
|
+
# - `:timeout` open/read timeout Integer in seconds
|
19
|
+
# - `:open_timeout` - read timeout Integer in seconds
|
20
|
+
# - `:on_data` - Proc for streaming
|
21
|
+
# - `:proxy` - Hash of proxy options
|
22
|
+
# - `:uri` - Proxy Server URI
|
23
|
+
# - `:user` - Proxy server username
|
24
|
+
# - `:password` - Proxy server password
|
25
|
+
#
|
26
|
+
# @!attribute request_headers
|
27
|
+
# @return [Hash] HTTP Headers to be sent to the server.
|
28
|
+
#
|
29
|
+
# @!attribute ssl
|
30
|
+
# @return [Hash] options for configuring SSL requests
|
31
|
+
#
|
32
|
+
# @!attribute parallel_manager
|
33
|
+
# @return [Object] sent if the connection is in parallel mode
|
34
|
+
#
|
35
|
+
# @!attribute params
|
36
|
+
# @return [Hash]
|
37
|
+
#
|
38
|
+
# @!attribute response
|
39
|
+
# @return [Response]
|
40
|
+
#
|
41
|
+
# @!attribute response_headers
|
42
|
+
# @return [Hash] HTTP headers from the server
|
43
|
+
#
|
44
|
+
# @!attribute status
|
45
|
+
# @return [Integer] HTTP response status code
|
46
|
+
#
|
47
|
+
# @!attribute reason_phrase
|
48
|
+
# @return [String]
|
49
|
+
class Env < Options.new(:method, :request_body, :url, :request,
|
50
|
+
:request_headers, :ssl, :parallel_manager, :params,
|
51
|
+
:response, :response_headers, :status,
|
52
|
+
:reason_phrase, :response_body)
|
53
|
+
|
54
|
+
# rubocop:disable Naming/ConstantName
|
55
|
+
ContentLength = 'Content-Length'
|
56
|
+
StatusesWithoutBody = Set.new [204, 304]
|
57
|
+
SuccessfulStatuses = (200..299).freeze
|
58
|
+
# rubocop:enable Naming/ConstantName
|
59
|
+
|
60
|
+
# A Set of HTTP verbs that typically send a body. If no body is set for
|
61
|
+
# these requests, the Content-Length header is set to 0.
|
62
|
+
MethodsWithBodies = Set.new(Faraday::METHODS_WITH_BODY.map(&:to_sym))
|
63
|
+
|
64
|
+
options request: RequestOptions,
|
65
|
+
request_headers: Utils::Headers, response_headers: Utils::Headers
|
66
|
+
|
67
|
+
extend Forwardable
|
68
|
+
|
69
|
+
def_delegators :request, :params_encoder
|
70
|
+
|
71
|
+
# Build a new Env from given value. Respects and updates `custom_members`.
|
72
|
+
#
|
73
|
+
# @param value [Object] a value fitting Option.from(v).
|
74
|
+
# @return [Env] from given value
|
75
|
+
def self.from(value)
|
76
|
+
env = super(value)
|
77
|
+
if value.respond_to?(:custom_members)
|
78
|
+
env.custom_members.update(value.custom_members)
|
79
|
+
end
|
80
|
+
env
|
81
|
+
end
|
82
|
+
|
83
|
+
# @param key [Object]
|
84
|
+
def [](key)
|
85
|
+
return self[current_body] if key == :body
|
86
|
+
|
87
|
+
if in_member_set?(key)
|
88
|
+
super(key)
|
89
|
+
else
|
90
|
+
custom_members[key]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# @param key [Object]
|
95
|
+
# @param value [Object]
|
96
|
+
def []=(key, value)
|
97
|
+
if key == :body
|
98
|
+
super(current_body, value)
|
99
|
+
return
|
100
|
+
end
|
101
|
+
|
102
|
+
if in_member_set?(key)
|
103
|
+
super(key, value)
|
104
|
+
else
|
105
|
+
custom_members[key] = value
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def current_body
|
110
|
+
!!status ? :response_body : :request_body
|
111
|
+
end
|
112
|
+
|
113
|
+
def body
|
114
|
+
self[:body]
|
115
|
+
end
|
116
|
+
|
117
|
+
def body=(value)
|
118
|
+
self[:body] = value
|
119
|
+
end
|
120
|
+
|
121
|
+
# @return [Boolean] true if status is in the set of {SuccessfulStatuses}.
|
122
|
+
def success?
|
123
|
+
SuccessfulStatuses.include?(status)
|
124
|
+
end
|
125
|
+
|
126
|
+
# @return [Boolean] true if there's no body yet, and the method is in the
|
127
|
+
# set of {MethodsWithBodies}.
|
128
|
+
def needs_body?
|
129
|
+
!body && MethodsWithBodies.include?(method)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Sets content length to zero and the body to the empty string.
|
133
|
+
def clear_body
|
134
|
+
request_headers[ContentLength] = '0'
|
135
|
+
self.body = ''
|
136
|
+
end
|
137
|
+
|
138
|
+
# @return [Boolean] true if the status isn't in the set of
|
139
|
+
# {StatusesWithoutBody}.
|
140
|
+
def parse_body?
|
141
|
+
!StatusesWithoutBody.include?(status)
|
142
|
+
end
|
143
|
+
|
144
|
+
# @return [Boolean] true if there is a parallel_manager
|
145
|
+
def parallel?
|
146
|
+
!!parallel_manager
|
147
|
+
end
|
148
|
+
|
149
|
+
def inspect
|
150
|
+
attrs = [nil]
|
151
|
+
members.each do |mem|
|
152
|
+
if (value = send(mem))
|
153
|
+
attrs << "@#{mem}=#{value.inspect}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
attrs << "@custom=#{custom_members.inspect}" unless custom_members.empty?
|
157
|
+
%(#<#{self.class}#{attrs.join(' ')}>)
|
158
|
+
end
|
159
|
+
|
160
|
+
# @private
|
161
|
+
def custom_members
|
162
|
+
@custom_members ||= {}
|
163
|
+
end
|
164
|
+
|
165
|
+
# @private
|
166
|
+
if members.first.is_a?(Symbol)
|
167
|
+
def in_member_set?(key)
|
168
|
+
self.class.member_set.include?(key.to_sym)
|
169
|
+
end
|
170
|
+
else
|
171
|
+
def in_member_set?(key)
|
172
|
+
self.class.member_set.include?(key.to_s)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# @private
|
177
|
+
def self.member_set
|
178
|
+
@member_set ||= Set.new(members)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
# ProxyOptions contains the configurable properties for the proxy
|
5
|
+
# configuration used when making an HTTP request.
|
6
|
+
class ProxyOptions < Options.new(:uri, :user, :password)
|
7
|
+
extend Forwardable
|
8
|
+
def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=,
|
9
|
+
:path, :path=
|
10
|
+
|
11
|
+
def self.from(value)
|
12
|
+
case value
|
13
|
+
when String
|
14
|
+
value = { uri: Utils.URI(value) }
|
15
|
+
when URI
|
16
|
+
value = { uri: value }
|
17
|
+
when Hash, Options
|
18
|
+
if (uri = value.delete(:uri))
|
19
|
+
value[:uri] = Utils.URI(uri)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
super(value)
|
23
|
+
end
|
24
|
+
|
25
|
+
memoized(:user) { uri&.user && Utils.unescape(uri.user) }
|
26
|
+
memoized(:password) { uri&.password && Utils.unescape(uri.password) }
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
# RequestOptions contains the configurable properties for a Faraday request.
|
5
|
+
class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
|
6
|
+
:timeout, :open_timeout, :write_timeout,
|
7
|
+
:boundary, :oauth, :context, :on_data)
|
8
|
+
|
9
|
+
def []=(key, value)
|
10
|
+
if key && key.to_sym == :proxy
|
11
|
+
super(key, value ? ProxyOptions.from(value) : nil)
|
12
|
+
else
|
13
|
+
super(key, value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def stream_response?
|
18
|
+
on_data.is_a?(Proc)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
# SSL-related options.
|
5
|
+
#
|
6
|
+
# @!attribute verify
|
7
|
+
# @return [Boolean] whether to verify SSL certificates or not
|
8
|
+
#
|
9
|
+
# @!attribute ca_file
|
10
|
+
# @return [String] CA file
|
11
|
+
#
|
12
|
+
# @!attribute ca_path
|
13
|
+
# @return [String] CA path
|
14
|
+
#
|
15
|
+
# @!attribute verify_mode
|
16
|
+
# @return [Integer] Any `OpenSSL::SSL::` constant (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL.html)
|
17
|
+
#
|
18
|
+
# @!attribute cert_store
|
19
|
+
# @return [OpenSSL::X509::Store] certificate store
|
20
|
+
#
|
21
|
+
# @!attribute client_cert
|
22
|
+
# @return [String, OpenSSL::X509::Certificate] client certificate
|
23
|
+
#
|
24
|
+
# @!attribute client_key
|
25
|
+
# @return [String, OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] client key
|
26
|
+
#
|
27
|
+
# @!attribute certificate
|
28
|
+
# @return [OpenSSL::X509::Certificate] certificate (Excon only)
|
29
|
+
#
|
30
|
+
# @!attribute private_key
|
31
|
+
# @return [OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] private key (Excon only)
|
32
|
+
#
|
33
|
+
# @!attribute verify_depth
|
34
|
+
# @return [Integer] maximum depth for the certificate chain verification
|
35
|
+
#
|
36
|
+
# @!attribute version
|
37
|
+
# @return [String, Symbol] SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-ssl_version-3D)
|
38
|
+
#
|
39
|
+
# @!attribute min_version
|
40
|
+
# @return [String, Symbol] minimum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-min_version-3D)
|
41
|
+
#
|
42
|
+
# @!attribute max_version
|
43
|
+
# @return [String, Symbol] maximum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-max_version-3D)
|
44
|
+
class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
|
45
|
+
:cert_store, :client_cert, :client_key,
|
46
|
+
:certificate, :private_key, :verify_depth,
|
47
|
+
:version, :min_version, :max_version)
|
48
|
+
|
49
|
+
# @return [Boolean] true if should verify
|
50
|
+
def verify?
|
51
|
+
verify != false
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Boolean] true if should not verify
|
55
|
+
def disable?
|
56
|
+
!verify?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Faraday
|
4
|
+
# Multipart value used to POST data with a content type.
|
5
|
+
class ParamPart
|
6
|
+
# @param value [String] Uploaded content as a String.
|
7
|
+
# @param content_type [String] String content type of the value.
|
8
|
+
# @param content_id [String] Optional String of this value's Content-ID.
|
9
|
+
#
|
10
|
+
# @return [Faraday::ParamPart]
|
11
|
+
def initialize(value, content_type, content_id = nil)
|
12
|
+
@value = value
|
13
|
+
@content_type = content_type
|
14
|
+
@content_id = content_id
|
15
|
+
end
|
16
|
+
|
17
|
+
# Converts this value to a form part.
|
18
|
+
#
|
19
|
+
# @param boundary [String] String multipart boundary that must not exist in
|
20
|
+
# the content exactly.
|
21
|
+
# @param key [String] String key name for this value.
|
22
|
+
#
|
23
|
+
# @return [Faraday::Parts::Part]
|
24
|
+
def to_part(boundary, key)
|
25
|
+
Faraday::Parts::Part.new(boundary, key, value, headers)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a Hash of String key/value pairs.
|
29
|
+
#
|
30
|
+
# @return [Hash]
|
31
|
+
def headers
|
32
|
+
{
|
33
|
+
'Content-Type' => content_type,
|
34
|
+
'Content-ID' => content_id
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
# The content to upload.
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
attr_reader :value
|
42
|
+
|
43
|
+
# The value's content type.
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
attr_reader :content_type
|
47
|
+
|
48
|
+
# The value's content ID, if given.
|
49
|
+
#
|
50
|
+
# @return [String, nil]
|
51
|
+
attr_reader :content_id
|
52
|
+
end
|
53
|
+
end
|
data/lib/faraday/parameters.rb
CHANGED
@@ -1,198 +1,5 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
extend Forwardable
|
7
|
-
def_delegators :'Faraday::Utils', :escape, :unescape
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.encode(params)
|
11
|
-
return nil if params == nil
|
12
|
-
|
13
|
-
if !params.is_a?(Array)
|
14
|
-
if !params.respond_to?(:to_hash)
|
15
|
-
raise TypeError,
|
16
|
-
"Can't convert #{params.class} into Hash."
|
17
|
-
end
|
18
|
-
params = params.to_hash
|
19
|
-
params = params.map do |key, value|
|
20
|
-
key = key.to_s if key.kind_of?(Symbol)
|
21
|
-
[key, value]
|
22
|
-
end
|
23
|
-
# Useful default for OAuth and caching.
|
24
|
-
# Only to be used for non-Array inputs. Arrays should preserve order.
|
25
|
-
params.sort!
|
26
|
-
end
|
27
|
-
|
28
|
-
# Helper lambda
|
29
|
-
to_query = lambda do |parent, value|
|
30
|
-
if value.is_a?(Hash)
|
31
|
-
value = value.map do |key, val|
|
32
|
-
key = escape(key)
|
33
|
-
[key, val]
|
34
|
-
end
|
35
|
-
value.sort!
|
36
|
-
buffer = ""
|
37
|
-
value.each do |key, val|
|
38
|
-
new_parent = "#{parent}%5B#{key}%5D"
|
39
|
-
buffer << "#{to_query.call(new_parent, val)}&"
|
40
|
-
end
|
41
|
-
return buffer.chop
|
42
|
-
elsif value.is_a?(Array)
|
43
|
-
new_parent = "#{parent}%5B%5D"
|
44
|
-
return new_parent if value.empty?
|
45
|
-
buffer = ""
|
46
|
-
value.each_with_index do |val, i|
|
47
|
-
buffer << "#{to_query.call(new_parent, val)}&"
|
48
|
-
end
|
49
|
-
return buffer.chop
|
50
|
-
elsif value.nil?
|
51
|
-
return parent
|
52
|
-
else
|
53
|
-
encoded_value = escape(value)
|
54
|
-
return "#{parent}=#{encoded_value}"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# The params have form [['key1', 'value1'], ['key2', 'value2']].
|
59
|
-
buffer = ''
|
60
|
-
params.each do |parent, value|
|
61
|
-
encoded_parent = escape(parent)
|
62
|
-
buffer << "#{to_query.call(encoded_parent, value)}&"
|
63
|
-
end
|
64
|
-
return buffer.chop
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.decode(query)
|
68
|
-
return nil if query == nil
|
69
|
-
|
70
|
-
params = {}
|
71
|
-
query.split("&").each do |pair|
|
72
|
-
next if pair.empty?
|
73
|
-
key, value = pair.split("=", 2)
|
74
|
-
key = unescape(key)
|
75
|
-
value = unescape(value.gsub(/\+/, ' ')) if value
|
76
|
-
|
77
|
-
subkeys = key.scan(/[^\[\]]+(?:\]?\[\])?/)
|
78
|
-
context = params
|
79
|
-
subkeys.each_with_index do |subkey, i|
|
80
|
-
is_array = subkey =~ /[\[\]]+\Z/
|
81
|
-
subkey = $` if is_array
|
82
|
-
last_subkey = i == subkeys.length - 1
|
83
|
-
|
84
|
-
if !last_subkey || is_array
|
85
|
-
value_type = is_array ? Array : Hash
|
86
|
-
if context[subkey] && !context[subkey].is_a?(value_type)
|
87
|
-
raise TypeError, "expected %s (got %s) for param `%s'" % [
|
88
|
-
value_type.name,
|
89
|
-
context[subkey].class.name,
|
90
|
-
subkey
|
91
|
-
]
|
92
|
-
end
|
93
|
-
context = (context[subkey] ||= value_type.new)
|
94
|
-
end
|
95
|
-
|
96
|
-
if context.is_a?(Array) && !is_array
|
97
|
-
if !context.last.is_a?(Hash) || context.last.has_key?(subkey)
|
98
|
-
context << {}
|
99
|
-
end
|
100
|
-
context = context.last
|
101
|
-
end
|
102
|
-
|
103
|
-
if last_subkey
|
104
|
-
if is_array
|
105
|
-
context << value
|
106
|
-
else
|
107
|
-
context[subkey] = value
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
dehash(params, 0)
|
114
|
-
end
|
115
|
-
|
116
|
-
# Internal: convert a nested hash with purely numeric keys into an array.
|
117
|
-
# FIXME: this is not compatible with Rack::Utils.parse_nested_query
|
118
|
-
def self.dehash(hash, depth)
|
119
|
-
hash.each do |key, value|
|
120
|
-
hash[key] = dehash(value, depth + 1) if value.kind_of?(Hash)
|
121
|
-
end
|
122
|
-
|
123
|
-
if depth > 0 && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
|
124
|
-
hash.keys.sort.inject([]) { |all, key| all << hash[key] }
|
125
|
-
else
|
126
|
-
hash
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
module FlatParamsEncoder
|
132
|
-
class << self
|
133
|
-
extend Forwardable
|
134
|
-
def_delegators :'Faraday::Utils', :escape, :unescape
|
135
|
-
end
|
136
|
-
|
137
|
-
def self.encode(params)
|
138
|
-
return nil if params == nil
|
139
|
-
|
140
|
-
if !params.is_a?(Array)
|
141
|
-
if !params.respond_to?(:to_hash)
|
142
|
-
raise TypeError,
|
143
|
-
"Can't convert #{params.class} into Hash."
|
144
|
-
end
|
145
|
-
params = params.to_hash
|
146
|
-
params = params.map do |key, value|
|
147
|
-
key = key.to_s if key.kind_of?(Symbol)
|
148
|
-
[key, value]
|
149
|
-
end
|
150
|
-
# Useful default for OAuth and caching.
|
151
|
-
# Only to be used for non-Array inputs. Arrays should preserve order.
|
152
|
-
params.sort!
|
153
|
-
end
|
154
|
-
|
155
|
-
# The params have form [['key1', 'value1'], ['key2', 'value2']].
|
156
|
-
buffer = ''
|
157
|
-
params.each do |key, value|
|
158
|
-
encoded_key = escape(key)
|
159
|
-
value = value.to_s if value == true || value == false
|
160
|
-
if value == nil
|
161
|
-
buffer << "#{encoded_key}&"
|
162
|
-
elsif value.kind_of?(Array)
|
163
|
-
value.each do |sub_value|
|
164
|
-
encoded_value = escape(sub_value)
|
165
|
-
buffer << "#{encoded_key}=#{encoded_value}&"
|
166
|
-
end
|
167
|
-
else
|
168
|
-
encoded_value = escape(value)
|
169
|
-
buffer << "#{encoded_key}=#{encoded_value}&"
|
170
|
-
end
|
171
|
-
end
|
172
|
-
return buffer.chop
|
173
|
-
end
|
174
|
-
|
175
|
-
def self.decode(query)
|
176
|
-
empty_accumulator = {}
|
177
|
-
return nil if query == nil
|
178
|
-
split_query = (query.split('&').map do |pair|
|
179
|
-
pair.split('=', 2) if pair && !pair.empty?
|
180
|
-
end).compact
|
181
|
-
return split_query.inject(empty_accumulator.dup) do |accu, pair|
|
182
|
-
pair[0] = unescape(pair[0])
|
183
|
-
pair[1] = true if pair[1].nil?
|
184
|
-
if pair[1].respond_to?(:to_str)
|
185
|
-
pair[1] = unescape(pair[1].to_str.gsub(/\+/, " "))
|
186
|
-
end
|
187
|
-
if accu[pair[0]].kind_of?(Array)
|
188
|
-
accu[pair[0]] << pair[1]
|
189
|
-
elsif accu[pair[0]]
|
190
|
-
accu[pair[0]] = [accu[pair[0]], pair[1]]
|
191
|
-
else
|
192
|
-
accu[pair[0]] = pair[1]
|
193
|
-
end
|
194
|
-
accu
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
3
|
+
require 'forwardable'
|
4
|
+
require 'faraday/encoders/nested_params_encoder'
|
5
|
+
require 'faraday/encoders/flat_params_encoder'
|