faraday 0.16.0 → 0.17.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 +347 -18
- data/lib/faraday/adapter/em_http.rb +99 -142
- data/lib/faraday/adapter/em_http_ssl_patch.rb +17 -23
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +15 -18
- data/lib/faraday/adapter/em_synchrony.rb +60 -104
- data/lib/faraday/adapter/excon.rb +55 -100
- data/lib/faraday/adapter/httpclient.rb +39 -61
- data/lib/faraday/adapter/net_http.rb +51 -104
- data/lib/faraday/adapter/net_http_persistent.rb +27 -48
- data/lib/faraday/adapter/patron.rb +35 -54
- data/lib/faraday/adapter/rack.rb +12 -28
- data/lib/faraday/adapter/test.rb +53 -86
- data/lib/faraday/adapter/typhoeus.rb +1 -4
- data/lib/faraday/adapter.rb +22 -36
- data/lib/faraday/autoload.rb +36 -47
- data/lib/faraday/connection.rb +179 -321
- data/lib/faraday/error.rb +33 -67
- data/lib/faraday/middleware.rb +28 -4
- data/lib/faraday/options.rb +186 -35
- data/lib/faraday/parameters.rb +197 -4
- data/lib/faraday/rack_builder.rb +56 -67
- data/lib/faraday/request/authorization.rb +30 -42
- data/lib/faraday/request/basic_authentication.rb +7 -14
- data/lib/faraday/request/instrumentation.rb +27 -45
- data/lib/faraday/request/multipart.rb +48 -79
- data/lib/faraday/request/retry.rb +170 -197
- data/lib/faraday/request/token_authentication.rb +10 -15
- data/lib/faraday/request/url_encoded.rb +23 -41
- data/lib/faraday/request.rb +36 -68
- data/lib/faraday/response/logger.rb +69 -22
- data/lib/faraday/response/raise_error.rb +14 -36
- data/lib/faraday/response.rb +16 -23
- data/lib/faraday/upload_io.rb +67 -0
- data/lib/faraday/utils.rb +245 -28
- data/lib/faraday.rb +175 -93
- metadata +5 -22
- data/lib/faraday/adapter_registry.rb +0 -28
- data/lib/faraday/dependency_loader.rb +0 -37
- data/lib/faraday/encoders/flat_params_encoder.rb +0 -94
- data/lib/faraday/encoders/nested_params_encoder.rb +0 -171
- data/lib/faraday/file_part.rb +0 -128
- data/lib/faraday/logging/formatter.rb +0 -92
- data/lib/faraday/middleware_registry.rb +0 -129
- data/lib/faraday/options/connection_options.rb +0 -22
- data/lib/faraday/options/env.rb +0 -181
- data/lib/faraday/options/proxy_options.rb +0 -28
- data/lib/faraday/options/request_options.rb +0 -21
- data/lib/faraday/options/ssl_options.rb +0 -59
- data/lib/faraday/param_part.rb +0 -53
- data/lib/faraday/utils/headers.rb +0 -139
- data/lib/faraday/utils/params_hash.rb +0 -61
- data/spec/external_adapters/faraday_specs_setup.rb +0 -14
data/lib/faraday/error.rb
CHANGED
@@ -1,22 +1,21 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Faraday
|
4
|
-
|
5
|
-
|
2
|
+
class Error < StandardError; end
|
3
|
+
|
4
|
+
class ClientError < Error
|
6
5
|
attr_reader :response, :wrapped_exception
|
7
6
|
|
8
|
-
def initialize(
|
7
|
+
def initialize(ex, response = nil)
|
9
8
|
@wrapped_exception = nil
|
10
9
|
@response = response
|
11
10
|
|
12
|
-
if
|
13
|
-
super(
|
14
|
-
@wrapped_exception =
|
15
|
-
elsif
|
16
|
-
super("the server responded with status #{
|
17
|
-
@response =
|
11
|
+
if ex.respond_to?(:backtrace)
|
12
|
+
super(ex.message)
|
13
|
+
@wrapped_exception = ex
|
14
|
+
elsif ex.respond_to?(:each_key)
|
15
|
+
super("the server responded with status #{ex[:status]}")
|
16
|
+
@response = ex
|
18
17
|
else
|
19
|
-
super(
|
18
|
+
super(ex.to_s)
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
@@ -29,72 +28,39 @@ module Faraday
|
|
29
28
|
end
|
30
29
|
|
31
30
|
def inspect
|
32
|
-
inner =
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
inner = ''
|
32
|
+
if @wrapped_exception
|
33
|
+
inner << " wrapped=#{@wrapped_exception.inspect}"
|
34
|
+
end
|
35
|
+
if @response
|
36
|
+
inner << " response=#{@response.inspect}"
|
37
|
+
end
|
38
|
+
if inner.empty?
|
39
|
+
inner << " #{super}"
|
40
|
+
end
|
36
41
|
%(#<#{self.class}#{inner}>)
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
40
|
-
|
41
|
-
class
|
42
|
-
end
|
43
|
-
|
44
|
-
# Raised by Faraday::Response::RaiseError in case of a 400 response.
|
45
|
-
class BadRequestError < ClientError
|
46
|
-
end
|
47
|
-
|
48
|
-
# Raised by Faraday::Response::RaiseError in case of a 401 response.
|
49
|
-
class UnauthorizedError < ClientError
|
50
|
-
end
|
51
|
-
|
52
|
-
# Raised by Faraday::Response::RaiseError in case of a 403 response.
|
53
|
-
class ForbiddenError < ClientError
|
54
|
-
end
|
55
|
-
|
56
|
-
# Raised by Faraday::Response::RaiseError in case of a 404 response.
|
57
|
-
class ResourceNotFound < ClientError
|
58
|
-
end
|
59
|
-
|
60
|
-
# Raised by Faraday::Response::RaiseError in case of a 407 response.
|
61
|
-
class ProxyAuthError < ClientError
|
62
|
-
end
|
63
|
-
|
64
|
-
# Raised by Faraday::Response::RaiseError in case of a 409 response.
|
65
|
-
class ConflictError < ClientError
|
66
|
-
end
|
45
|
+
class ConnectionFailed < ClientError; end
|
46
|
+
class ResourceNotFound < ClientError; end
|
47
|
+
class ParsingError < ClientError; end
|
67
48
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
# Faraday server error class. Represents 5xx status responses.
|
73
|
-
class ServerError < Error
|
74
|
-
end
|
75
|
-
|
76
|
-
# A unified client error for timeouts.
|
77
|
-
class TimeoutError < ServerError
|
78
|
-
def initialize(exc = 'timeout', response = nil)
|
79
|
-
super(exc, response)
|
49
|
+
class TimeoutError < ClientError
|
50
|
+
def initialize(ex = nil)
|
51
|
+
super(ex || "timeout")
|
80
52
|
end
|
81
53
|
end
|
82
54
|
|
83
|
-
|
84
|
-
class ConnectionFailed < Error
|
55
|
+
class SSLError < ClientError
|
85
56
|
end
|
86
57
|
|
87
|
-
|
88
|
-
class SSLError < Error
|
89
|
-
end
|
58
|
+
class RetriableResponse < ClientError; end
|
90
59
|
|
91
|
-
|
92
|
-
|
60
|
+
[:ClientError, :ConnectionFailed, :ResourceNotFound,
|
61
|
+
:ParsingError, :TimeoutError, :SSLError, :RetriableResponse].each do |const|
|
62
|
+
Error.const_set(const, Faraday.const_get(const))
|
93
63
|
end
|
94
64
|
|
95
|
-
|
96
|
-
#
|
97
|
-
# @see Faraday::Request::Retry
|
98
|
-
class RetriableResponse < Error
|
99
|
-
end
|
65
|
+
|
100
66
|
end
|
data/lib/faraday/middleware.rb
CHANGED
@@ -1,10 +1,34 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Faraday
|
4
|
-
# Middleware is the basic base class of any Faraday middleware.
|
5
2
|
class Middleware
|
6
3
|
extend MiddlewareRegistry
|
7
|
-
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :load_error
|
7
|
+
private :load_error=
|
8
|
+
end
|
9
|
+
|
10
|
+
self.load_error = nil
|
11
|
+
|
12
|
+
# Executes a block which should try to require and reference dependent libraries
|
13
|
+
def self.dependency(lib = nil)
|
14
|
+
lib ? require(lib) : yield
|
15
|
+
rescue LoadError, NameError => error
|
16
|
+
self.load_error = error
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.new(*)
|
20
|
+
raise "missing dependency for #{self}: #{load_error.message}" unless loaded?
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.loaded?
|
25
|
+
load_error.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.inherited(subclass)
|
29
|
+
super
|
30
|
+
subclass.send(:load_error=, self.load_error)
|
31
|
+
end
|
8
32
|
|
9
33
|
def initialize(app = nil)
|
10
34
|
@app = app
|
data/lib/faraday/options.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Faraday
|
4
2
|
# Subclasses Struct with some special helpers for converting from a Hash to
|
5
3
|
# a Struct.
|
@@ -12,7 +10,6 @@ module Faraday
|
|
12
10
|
# Public
|
13
11
|
def each
|
14
12
|
return to_enum(:each) unless block_given?
|
15
|
-
|
16
13
|
members.each do |key|
|
17
14
|
yield(key.to_sym, send(key))
|
18
15
|
end
|
@@ -30,7 +27,7 @@ module Faraday
|
|
30
27
|
new_value = value
|
31
28
|
end
|
32
29
|
|
33
|
-
send("#{key}=", new_value) unless new_value.nil?
|
30
|
+
self.send("#{key}=", new_value) unless new_value.nil?
|
34
31
|
end
|
35
32
|
self
|
36
33
|
end
|
@@ -50,14 +47,10 @@ module Faraday
|
|
50
47
|
# Public
|
51
48
|
def merge!(other)
|
52
49
|
other.each do |key, other_value|
|
53
|
-
self_value = send(key)
|
50
|
+
self_value = self.send(key)
|
54
51
|
sub_options = self.class.options_for(key)
|
55
|
-
new_value =
|
56
|
-
|
57
|
-
else
|
58
|
-
other_value
|
59
|
-
end
|
60
|
-
send("#{key}=", new_value) unless new_value.nil?
|
52
|
+
new_value = (self_value && sub_options && other_value) ? self_value.merge(other_value) : other_value
|
53
|
+
self.send("#{key}=", new_value) unless new_value.nil?
|
61
54
|
end
|
62
55
|
self
|
63
56
|
end
|
@@ -76,10 +69,10 @@ module Faraday
|
|
76
69
|
def fetch(key, *args)
|
77
70
|
unless symbolized_key_set.include?(key.to_sym)
|
78
71
|
key_setter = "#{key}="
|
79
|
-
if
|
72
|
+
if args.size > 0
|
80
73
|
send(key_setter, args.first)
|
81
74
|
elsif block_given?
|
82
|
-
send(key_setter,
|
75
|
+
send(key_setter, Proc.new.call(key))
|
83
76
|
else
|
84
77
|
raise self.class.fetch_error_class, "key not found: #{key.inspect}"
|
85
78
|
end
|
@@ -105,7 +98,6 @@ module Faraday
|
|
105
98
|
# Public
|
106
99
|
def each_key
|
107
100
|
return to_enum(:each_key) unless block_given?
|
108
|
-
|
109
101
|
keys.each do |key|
|
110
102
|
yield(key)
|
111
103
|
end
|
@@ -121,7 +113,6 @@ module Faraday
|
|
121
113
|
# Public
|
122
114
|
def each_value
|
123
115
|
return to_enum(:each_value) unless block_given?
|
124
|
-
|
125
116
|
values.each do |value|
|
126
117
|
yield(value)
|
127
118
|
end
|
@@ -151,9 +142,9 @@ module Faraday
|
|
151
142
|
value = send(member)
|
152
143
|
values << "#{member}=#{value.inspect}" if value
|
153
144
|
end
|
154
|
-
values = values.empty? ? '(empty)' : values.join(
|
145
|
+
values = values.empty? ? ' (empty)' : (' ' << values.join(", "))
|
155
146
|
|
156
|
-
%(#<#{self.class}
|
147
|
+
%(#<#{self.class}#{values}>)
|
157
148
|
end
|
158
149
|
|
159
150
|
# Internal
|
@@ -171,12 +162,8 @@ module Faraday
|
|
171
162
|
@attribute_options ||= {}
|
172
163
|
end
|
173
164
|
|
174
|
-
def self.memoized(key
|
175
|
-
|
176
|
-
raise ArgumentError, '#memoized must be called with a block'
|
177
|
-
end
|
178
|
-
|
179
|
-
memoized_attributes[key.to_sym] = block
|
165
|
+
def self.memoized(key)
|
166
|
+
memoized_attributes[key.to_sym] = Proc.new
|
180
167
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
181
168
|
def #{key}() self[:#{key}]; end
|
182
169
|
RUBY
|
@@ -188,7 +175,7 @@ module Faraday
|
|
188
175
|
|
189
176
|
def [](key)
|
190
177
|
key = key.to_sym
|
191
|
-
if
|
178
|
+
if method = self.class.memoized_attributes[key]
|
192
179
|
super(key) || (self[key] = instance_eval(&method))
|
193
180
|
else
|
194
181
|
super
|
@@ -196,7 +183,7 @@ module Faraday
|
|
196
183
|
end
|
197
184
|
|
198
185
|
def symbolized_key_set
|
199
|
-
@symbolized_key_set ||= Set.new(keys.map
|
186
|
+
@symbolized_key_set ||= Set.new(keys.map { |k| k.to_sym })
|
200
187
|
end
|
201
188
|
|
202
189
|
def self.inherited(subclass)
|
@@ -207,16 +194,180 @@ module Faraday
|
|
207
194
|
|
208
195
|
def self.fetch_error_class
|
209
196
|
@fetch_error_class ||= if Object.const_defined?(:KeyError)
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
197
|
+
::KeyError
|
198
|
+
else
|
199
|
+
::IndexError
|
200
|
+
end
|
214
201
|
end
|
215
202
|
end
|
216
|
-
end
|
217
203
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
204
|
+
class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
|
205
|
+
:timeout, :open_timeout, :write_timeout, :boundary, :oauth, :context)
|
206
|
+
|
207
|
+
def []=(key, value)
|
208
|
+
if key && key.to_sym == :proxy
|
209
|
+
super(key, value ? ProxyOptions.from(value) : nil)
|
210
|
+
else
|
211
|
+
super(key, value)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
|
217
|
+
:cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth,
|
218
|
+
:version, :min_version, :max_version)
|
219
|
+
|
220
|
+
def verify?
|
221
|
+
verify != false
|
222
|
+
end
|
223
|
+
|
224
|
+
def disable?
|
225
|
+
!verify?
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
class ProxyOptions < Options.new(:uri, :user, :password)
|
230
|
+
extend Forwardable
|
231
|
+
def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=, :path, :path=
|
232
|
+
|
233
|
+
def self.from(value)
|
234
|
+
case value
|
235
|
+
when String
|
236
|
+
value = {:uri => Utils.URI(value)}
|
237
|
+
when URI
|
238
|
+
value = {:uri => value}
|
239
|
+
when Hash, Options
|
240
|
+
if uri = value.delete(:uri)
|
241
|
+
value[:uri] = Utils.URI(uri)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
super(value)
|
245
|
+
end
|
246
|
+
|
247
|
+
memoized(:user) { uri && uri.user && Utils.unescape(uri.user) }
|
248
|
+
memoized(:password) { uri && uri.password && Utils.unescape(uri.password) }
|
249
|
+
end
|
250
|
+
|
251
|
+
class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
|
252
|
+
:parallel_manager, :params, :headers, :builder_class)
|
253
|
+
|
254
|
+
options :request => RequestOptions, :ssl => SSLOptions
|
255
|
+
|
256
|
+
memoized(:request) { self.class.options_for(:request).new }
|
257
|
+
|
258
|
+
memoized(:ssl) { self.class.options_for(:ssl).new }
|
259
|
+
|
260
|
+
memoized(:builder_class) { RackBuilder }
|
261
|
+
|
262
|
+
def new_builder(block)
|
263
|
+
builder_class.new(&block)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
class Env < Options.new(:method, :body, :url, :request, :request_headers,
|
268
|
+
:ssl, :parallel_manager, :params, :response, :response_headers, :status,
|
269
|
+
:reason_phrase)
|
270
|
+
|
271
|
+
ContentLength = 'Content-Length'.freeze
|
272
|
+
StatusesWithoutBody = Set.new [204, 304]
|
273
|
+
SuccessfulStatuses = 200..299
|
274
|
+
|
275
|
+
# A Set of HTTP verbs that typically send a body. If no body is set for
|
276
|
+
# these requests, the Content-Length header is set to 0.
|
277
|
+
MethodsWithBodies = Set.new [:post, :put, :patch, :options]
|
278
|
+
|
279
|
+
options :request => RequestOptions,
|
280
|
+
:request_headers => Utils::Headers, :response_headers => Utils::Headers
|
281
|
+
|
282
|
+
extend Forwardable
|
283
|
+
|
284
|
+
def_delegators :request, :params_encoder
|
285
|
+
|
286
|
+
# Public
|
287
|
+
def self.from(value)
|
288
|
+
env = super(value)
|
289
|
+
if value.respond_to?(:custom_members)
|
290
|
+
env.custom_members.update(value.custom_members)
|
291
|
+
end
|
292
|
+
env
|
293
|
+
end
|
294
|
+
|
295
|
+
# Public
|
296
|
+
def [](key)
|
297
|
+
if in_member_set?(key)
|
298
|
+
super(key)
|
299
|
+
else
|
300
|
+
custom_members[key]
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# Public
|
305
|
+
def []=(key, value)
|
306
|
+
if in_member_set?(key)
|
307
|
+
super(key, value)
|
308
|
+
else
|
309
|
+
custom_members[key] = value
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Public
|
314
|
+
def success?
|
315
|
+
SuccessfulStatuses.include?(status)
|
316
|
+
end
|
317
|
+
|
318
|
+
# Public
|
319
|
+
def needs_body?
|
320
|
+
!body && MethodsWithBodies.include?(method)
|
321
|
+
end
|
322
|
+
|
323
|
+
# Public
|
324
|
+
def clear_body
|
325
|
+
request_headers[ContentLength] = '0'
|
326
|
+
self.body = ''
|
327
|
+
end
|
328
|
+
|
329
|
+
# Public
|
330
|
+
def parse_body?
|
331
|
+
!StatusesWithoutBody.include?(status)
|
332
|
+
end
|
333
|
+
|
334
|
+
# Public
|
335
|
+
def parallel?
|
336
|
+
!!parallel_manager
|
337
|
+
end
|
338
|
+
|
339
|
+
def inspect
|
340
|
+
attrs = [nil]
|
341
|
+
members.each do |mem|
|
342
|
+
if value = send(mem)
|
343
|
+
attrs << "@#{mem}=#{value.inspect}"
|
344
|
+
end
|
345
|
+
end
|
346
|
+
if !custom_members.empty?
|
347
|
+
attrs << "@custom=#{custom_members.inspect}"
|
348
|
+
end
|
349
|
+
%(#<#{self.class}#{attrs.join(" ")}>)
|
350
|
+
end
|
351
|
+
|
352
|
+
# Internal
|
353
|
+
def custom_members
|
354
|
+
@custom_members ||= {}
|
355
|
+
end
|
356
|
+
|
357
|
+
# Internal
|
358
|
+
if members.first.is_a?(Symbol)
|
359
|
+
def in_member_set?(key)
|
360
|
+
self.class.member_set.include?(key.to_sym)
|
361
|
+
end
|
362
|
+
else
|
363
|
+
def in_member_set?(key)
|
364
|
+
self.class.member_set.include?(key.to_s)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
# Internal
|
369
|
+
def self.member_set
|
370
|
+
@member_set ||= Set.new(members)
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
data/lib/faraday/parameters.rb
CHANGED
@@ -1,5 +1,198 @@
|
|
1
|
-
|
1
|
+
require "forwardable"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
module Faraday
|
4
|
+
module NestedParamsEncoder
|
5
|
+
class << self
|
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
|