faraday 0.15.4 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +380 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +16 -344
  5. data/Rakefile +7 -0
  6. data/examples/client_spec.rb +65 -0
  7. data/examples/client_test.rb +79 -0
  8. data/lib/faraday.rb +127 -190
  9. data/lib/faraday/adapter.rb +72 -22
  10. data/lib/faraday/adapter/test.rb +86 -53
  11. data/lib/faraday/adapter/typhoeus.rb +4 -1
  12. data/lib/faraday/adapter_registry.rb +30 -0
  13. data/lib/faraday/autoload.rb +39 -36
  14. data/lib/faraday/connection.rb +320 -183
  15. data/lib/faraday/dependency_loader.rb +37 -0
  16. data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  17. data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
  18. data/lib/faraday/error.rb +123 -37
  19. data/lib/faraday/file_part.rb +128 -0
  20. data/lib/faraday/logging/formatter.rb +105 -0
  21. data/lib/faraday/methods.rb +6 -0
  22. data/lib/faraday/middleware.rb +19 -25
  23. data/lib/faraday/middleware_registry.rb +129 -0
  24. data/lib/faraday/options.rb +39 -194
  25. data/lib/faraday/options/connection_options.rb +22 -0
  26. data/lib/faraday/options/env.rb +181 -0
  27. data/lib/faraday/options/proxy_options.rb +32 -0
  28. data/lib/faraday/options/request_options.rb +22 -0
  29. data/lib/faraday/options/ssl_options.rb +59 -0
  30. data/lib/faraday/param_part.rb +53 -0
  31. data/lib/faraday/parameters.rb +4 -197
  32. data/lib/faraday/rack_builder.rb +77 -65
  33. data/lib/faraday/request.rb +86 -44
  34. data/lib/faraday/request/authorization.rb +44 -30
  35. data/lib/faraday/request/basic_authentication.rb +14 -7
  36. data/lib/faraday/request/instrumentation.rb +45 -27
  37. data/lib/faraday/request/multipart.rb +86 -48
  38. data/lib/faraday/request/retry.rb +198 -169
  39. data/lib/faraday/request/token_authentication.rb +15 -10
  40. data/lib/faraday/request/url_encoded.rb +43 -23
  41. data/lib/faraday/response.rb +27 -23
  42. data/lib/faraday/response/logger.rb +22 -69
  43. data/lib/faraday/response/raise_error.rb +49 -14
  44. data/lib/faraday/utils.rb +38 -247
  45. data/lib/faraday/utils/headers.rb +139 -0
  46. data/lib/faraday/utils/params_hash.rb +61 -0
  47. data/lib/faraday/version.rb +5 -0
  48. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  49. data/spec/faraday/adapter/em_http_spec.rb +49 -0
  50. data/spec/faraday/adapter/em_synchrony_spec.rb +18 -0
  51. data/spec/faraday/adapter/excon_spec.rb +49 -0
  52. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  53. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  54. data/spec/faraday/adapter/patron_spec.rb +18 -0
  55. data/spec/faraday/adapter/rack_spec.rb +8 -0
  56. data/spec/faraday/adapter/test_spec.rb +260 -0
  57. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  58. data/spec/faraday/adapter_registry_spec.rb +28 -0
  59. data/spec/faraday/adapter_spec.rb +55 -0
  60. data/spec/faraday/composite_read_io_spec.rb +80 -0
  61. data/spec/faraday/connection_spec.rb +736 -0
  62. data/spec/faraday/error_spec.rb +60 -0
  63. data/spec/faraday/middleware_spec.rb +52 -0
  64. data/spec/faraday/options/env_spec.rb +70 -0
  65. data/spec/faraday/options/options_spec.rb +297 -0
  66. data/spec/faraday/options/proxy_options_spec.rb +44 -0
  67. data/spec/faraday/options/request_options_spec.rb +19 -0
  68. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  69. data/spec/faraday/params_encoders/nested_spec.rb +142 -0
  70. data/spec/faraday/rack_builder_spec.rb +345 -0
  71. data/spec/faraday/request/authorization_spec.rb +88 -0
  72. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  73. data/spec/faraday/request/multipart_spec.rb +302 -0
  74. data/spec/faraday/request/retry_spec.rb +242 -0
  75. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  76. data/spec/faraday/request_spec.rb +120 -0
  77. data/spec/faraday/response/logger_spec.rb +220 -0
  78. data/spec/faraday/response/middleware_spec.rb +68 -0
  79. data/spec/faraday/response/raise_error_spec.rb +169 -0
  80. data/spec/faraday/response_spec.rb +75 -0
  81. data/spec/faraday/utils/headers_spec.rb +82 -0
  82. data/spec/faraday/utils_spec.rb +56 -0
  83. data/spec/faraday_spec.rb +37 -0
  84. data/spec/spec_helper.rb +132 -0
  85. data/spec/support/disabling_stub.rb +14 -0
  86. data/spec/support/fake_safe_buffer.rb +15 -0
  87. data/spec/support/helper_methods.rb +133 -0
  88. data/spec/support/shared_examples/adapter.rb +105 -0
  89. data/spec/support/shared_examples/params_encoder.rb +18 -0
  90. data/spec/support/shared_examples/request_method.rb +262 -0
  91. data/spec/support/streaming_response_checker.rb +35 -0
  92. data/spec/support/webmock_rack_app.rb +68 -0
  93. metadata +206 -19
  94. data/lib/faraday/adapter/em_http.rb +0 -243
  95. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
  96. data/lib/faraday/adapter/em_synchrony.rb +0 -106
  97. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
  98. data/lib/faraday/adapter/excon.rb +0 -82
  99. data/lib/faraday/adapter/httpclient.rb +0 -128
  100. data/lib/faraday/adapter/net_http.rb +0 -152
  101. data/lib/faraday/adapter/net_http_persistent.rb +0 -68
  102. data/lib/faraday/adapter/patron.rb +0 -95
  103. data/lib/faraday/adapter/rack.rb +0 -58
  104. data/lib/faraday/upload_io.rb +0 -67
@@ -1,15 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
- class Request::TokenAuthentication < Request.load_middleware(:authorization)
3
- # Public
4
- def self.header(token, options = nil)
5
- options ||= {}
6
- options[:token] = token
7
- super(:Token, options)
8
- end
4
+ class Request
5
+ # TokenAuthentication is a middleware that adds a 'Token' header to a
6
+ # Faraday request.
7
+ class TokenAuthentication < load_middleware(:authorization)
8
+ # Public
9
+ def self.header(token, options = nil)
10
+ options ||= {}
11
+ options[:token] = token
12
+ super(:Token, options)
13
+ end
9
14
 
10
- def initialize(app, token, options = nil)
11
- super(app, token, options)
15
+ def initialize(app, token, options = nil)
16
+ super(app, token, options)
17
+ end
12
18
  end
13
19
  end
14
20
  end
15
-
@@ -1,36 +1,56 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
- class Request::UrlEncoded < Faraday::Middleware
3
- CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE
4
+ class Request
5
+ # Middleware for supporting urlencoded requests.
6
+ class UrlEncoded < Faraday::Middleware
7
+ unless defined?(::Faraday::Request::UrlEncoded::CONTENT_TYPE)
8
+ CONTENT_TYPE = 'Content-Type'
9
+ end
4
10
 
5
- class << self
6
- attr_accessor :mime_type
7
- end
8
- self.mime_type = 'application/x-www-form-urlencoded'.freeze
11
+ class << self
12
+ attr_accessor :mime_type
13
+ end
14
+ self.mime_type = 'application/x-www-form-urlencoded'
9
15
 
10
- def call(env)
11
- match_content_type(env) do |data|
12
- params = Faraday::Utils::ParamsHash[data]
13
- env.body = params.to_query(env.params_encoder)
16
+ # Encodes as "application/x-www-form-urlencoded" if not already encoded or
17
+ # of another type.
18
+ #
19
+ # @param env [Faraday::Env]
20
+ def call(env)
21
+ match_content_type(env) do |data|
22
+ params = Faraday::Utils::ParamsHash[data]
23
+ env.body = params.to_query(env.params_encoder)
24
+ end
25
+ @app.call env
14
26
  end
15
- @app.call env
16
- end
17
27
 
18
- def match_content_type(env)
19
- if process_request?(env)
28
+ # @param env [Faraday::Env]
29
+ # @yield [request_body] Body of the request
30
+ def match_content_type(env)
31
+ return unless process_request?(env)
32
+
20
33
  env.request_headers[CONTENT_TYPE] ||= self.class.mime_type
21
34
  yield(env.body) unless env.body.respond_to?(:to_str)
22
35
  end
23
- end
24
36
 
25
- def process_request?(env)
26
- type = request_type(env)
27
- env.body and (type.empty? or type == self.class.mime_type)
28
- end
37
+ # @param env [Faraday::Env]
38
+ #
39
+ # @return [Boolean] True if the request has a body and its Content-Type is
40
+ # urlencoded.
41
+ def process_request?(env)
42
+ type = request_type(env)
43
+ env.body && (type.empty? || (type == self.class.mime_type))
44
+ end
29
45
 
30
- def request_type(env)
31
- type = env.request_headers[CONTENT_TYPE].to_s
32
- type = type.split(';', 2).first if type.index(';')
33
- type
46
+ # @param env [Faraday::Env]
47
+ #
48
+ # @return [String]
49
+ def request_type(env)
50
+ type = env.request_headers[CONTENT_TYPE].to_s
51
+ type = type.split(';', 2).first if type.index(';')
52
+ type
53
+ end
34
54
  end
35
55
  end
36
56
  end
@@ -1,28 +1,28 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
2
4
 
3
5
  module Faraday
6
+ # Response represents an HTTP response from making an HTTP request.
4
7
  class Response
5
8
  # Used for simple response middleware.
6
9
  class Middleware < Faraday::Middleware
7
- def call(env)
8
- @app.call(env).on_complete do |environment|
9
- on_complete(environment)
10
- end
11
- end
12
-
13
10
  # Override this to modify the environment after the response has finished.
14
11
  # Calls the `parse` method if defined
12
+ # `parse` method can be defined as private, public and protected
15
13
  def on_complete(env)
16
- env.body = parse(env.body) if respond_to?(:parse) && env.parse_body?
14
+ return unless respond_to?(:parse, true) && env.parse_body?
15
+
16
+ env.body = parse(env.body)
17
17
  end
18
18
  end
19
19
 
20
20
  extend Forwardable
21
21
  extend MiddlewareRegistry
22
22
 
23
- register_middleware File.expand_path('../response', __FILE__),
24
- :raise_error => [:RaiseError, 'raise_error'],
25
- :logger => [:Logger, 'logger']
23
+ register_middleware File.expand_path('response', __dir__),
24
+ raise_error: [:RaiseError, 'raise_error'],
25
+ logger: [:Logger, 'logger']
26
26
 
27
27
  def initialize(env = nil)
28
28
  @env = Env.from(env) if env
@@ -31,8 +31,6 @@ module Faraday
31
31
 
32
32
  attr_reader :env
33
33
 
34
- def_delegators :env, :to_hash
35
-
36
34
  def status
37
35
  finished? ? env.status : nil
38
36
  end
@@ -54,32 +52,37 @@ module Faraday
54
52
  !!env
55
53
  end
56
54
 
57
- def on_complete
58
- if not finished?
59
- @on_complete_callbacks << Proc.new
55
+ def on_complete(&block)
56
+ if !finished?
57
+ @on_complete_callbacks << block
60
58
  else
61
59
  yield(env)
62
60
  end
63
- return self
61
+ self
64
62
  end
65
63
 
66
64
  def finish(env)
67
- raise "response already finished" if finished?
65
+ raise 'response already finished' if finished?
66
+
68
67
  @env = env.is_a?(Env) ? env : Env.from(env)
69
68
  @on_complete_callbacks.each { |callback| callback.call(@env) }
70
- return self
69
+ self
71
70
  end
72
71
 
73
72
  def success?
74
73
  finished? && env.success?
75
74
  end
76
75
 
76
+ def to_hash
77
+ {
78
+ status: env.status, body: env.body,
79
+ response_headers: env.response_headers
80
+ }
81
+ end
82
+
77
83
  # because @on_complete_callbacks cannot be marshalled
78
84
  def marshal_dump
79
- !finished? ? nil : {
80
- :status => @env.status, :body => @env.body,
81
- :response_headers => @env.response_headers
82
- }
85
+ finished? ? to_hash : nil
83
86
  end
84
87
 
85
88
  def marshal_load(env)
@@ -90,8 +93,9 @@ module Faraday
90
93
  # Useful for applying request params after restoring a marshalled Response.
91
94
  def apply_request(request_env)
92
95
  raise "response didn't finish yet" unless finished?
96
+
93
97
  @env = Env.from(request_env).update(@env)
94
- return self
98
+ self
95
99
  end
96
100
  end
97
101
  end
@@ -1,80 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'forwardable'
4
+ require 'faraday/logging/formatter'
2
5
 
3
6
  module Faraday
4
- class Response::Logger < Response::Middleware
5
- extend Forwardable
6
-
7
- DEFAULT_OPTIONS = { :headers => true, :bodies => false }
8
-
9
- def initialize(app, logger = nil, options = {})
10
- super(app)
11
- @logger = logger || begin
12
- require 'logger'
13
- ::Logger.new($stdout)
14
- end
15
- @filter = []
16
- @options = DEFAULT_OPTIONS.merge(options)
17
- yield self if block_given?
18
- end
19
-
20
- def_delegators :@logger, :debug, :info, :warn, :error, :fatal
21
-
22
- def call(env)
23
- info('request') { "#{env.method.upcase} #{apply_filters(env.url.to_s)}" }
24
- debug('request') { apply_filters( dump_headers env.request_headers ) } if log_headers?(:request)
25
- debug('request') { apply_filters( dump_body(env[:body]) ) } if env[:body] && log_body?(:request)
26
- super
27
- end
28
-
29
- def on_complete(env)
30
- info('response') { "Status #{env.status.to_s}" }
31
- debug('response') { apply_filters( dump_headers env.response_headers ) } if log_headers?(:response)
32
- debug('response') { apply_filters( dump_body env[:body] ) } if env[:body] && log_body?(:response)
33
- end
34
-
35
- def filter(filter_word, filter_replacement)
36
- @filter.push([ filter_word, filter_replacement ])
37
- end
38
-
39
- private
40
-
41
- def dump_headers(headers)
42
- headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
43
- end
44
-
45
- def dump_body(body)
46
- if body.respond_to?(:to_str)
47
- body.to_str
48
- else
49
- pretty_inspect(body)
50
- end
51
- end
52
-
53
- def pretty_inspect(body)
54
- require 'pp' unless body.respond_to?(:pretty_inspect)
55
- body.pretty_inspect
56
- end
57
-
58
- def log_headers?(type)
59
- case @options[:headers]
60
- when Hash then @options[:headers][type]
61
- else @options[:headers]
7
+ class Response
8
+ # Logger is a middleware that logs internal events in the HTTP request
9
+ # lifecycle to a given Logger object. By default, this logs to STDOUT. See
10
+ # Faraday::Logging::Formatter to see specifically what is logged.
11
+ class Logger < Middleware
12
+ def initialize(app, logger = nil, options = {})
13
+ super(app)
14
+ logger ||= begin
15
+ require 'logger'
16
+ ::Logger.new($stdout)
17
+ end
18
+ formatter_class = options.delete(:formatter) || Logging::Formatter
19
+ @formatter = formatter_class.new(logger: logger, options: options)
20
+ yield @formatter if block_given?
62
21
  end
63
- end
64
22
 
65
- def log_body?(type)
66
- case @options[:bodies]
67
- when Hash then @options[:bodies][type]
68
- else @options[:bodies]
23
+ def call(env)
24
+ @formatter.request(env)
25
+ super
69
26
  end
70
- end
71
27
 
72
- def apply_filters(output)
73
- @filter.each do |pattern, replacement|
74
- output = output.to_s.gsub(pattern, replacement)
28
+ def on_complete(env)
29
+ @formatter.response(env)
75
30
  end
76
- output
77
31
  end
78
-
79
32
  end
80
33
  end
@@ -1,21 +1,56 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Faraday
2
- class Response::RaiseError < Response::Middleware
3
- ClientErrorStatuses = 400...600
4
+ class Response
5
+ # RaiseError is a Faraday middleware that raises exceptions on common HTTP
6
+ # client or server error responses.
7
+ class RaiseError < Middleware
8
+ # rubocop:disable Naming/ConstantName
9
+ ClientErrorStatuses = (400...500).freeze
10
+ ServerErrorStatuses = (500...600).freeze
11
+ # rubocop:enable Naming/ConstantName
4
12
 
5
- def on_complete(env)
6
- case env[:status]
7
- when 404
8
- raise Faraday::Error::ResourceNotFound, response_values(env)
9
- when 407
10
- # mimic the behavior that we get with proxy requests with HTTPS
11
- raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
12
- when ClientErrorStatuses
13
- raise Faraday::Error::ClientError, response_values(env)
13
+ def on_complete(env)
14
+ case env[:status]
15
+ when 400
16
+ raise Faraday::BadRequestError, response_values(env)
17
+ when 401
18
+ raise Faraday::UnauthorizedError, response_values(env)
19
+ when 403
20
+ raise Faraday::ForbiddenError, response_values(env)
21
+ when 404
22
+ raise Faraday::ResourceNotFound, response_values(env)
23
+ when 407
24
+ # mimic the behavior that we get with proxy requests with HTTPS
25
+ msg = %(407 "Proxy Authentication Required")
26
+ raise Faraday::ProxyAuthError.new(msg, response_values(env))
27
+ when 409
28
+ raise Faraday::ConflictError, response_values(env)
29
+ when 422
30
+ raise Faraday::UnprocessableEntityError, response_values(env)
31
+ when ClientErrorStatuses
32
+ raise Faraday::ClientError, response_values(env)
33
+ when ServerErrorStatuses
34
+ raise Faraday::ServerError, response_values(env)
35
+ when nil
36
+ raise Faraday::NilStatusError, response_values(env)
37
+ end
14
38
  end
15
- end
16
39
 
17
- def response_values(env)
18
- {:status => env.status, :headers => env.response_headers, :body => env.body}
40
+ def response_values(env)
41
+ {
42
+ status: env.status,
43
+ headers: env.response_headers,
44
+ body: env.body,
45
+ request: {
46
+ method: env.method,
47
+ url_path: env.url.path,
48
+ params: env.params,
49
+ headers: env.request_headers,
50
+ body: env.request_body
51
+ }
52
+ }
53
+ end
19
54
  end
20
55
  end
21
56
  end
data/lib/faraday/utils.rb CHANGED
@@ -1,193 +1,12 @@
1
- require 'thread'
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday/utils/headers'
4
+ require 'faraday/utils/params_hash'
2
5
 
3
6
  module Faraday
7
+ # Utils contains various static helper methods.
4
8
  module Utils
5
- extend self
6
-
7
- # Adapted from Rack::Utils::HeaderHash
8
- class Headers < ::Hash
9
- def self.from(value)
10
- new(value)
11
- end
12
-
13
- def self.allocate
14
- new_self = super
15
- new_self.initialize_names
16
- new_self
17
- end
18
-
19
- def initialize(hash = nil)
20
- super()
21
- @names = {}
22
- self.update(hash || {})
23
- end
24
-
25
- def initialize_names
26
- @names = {}
27
- end
28
-
29
- # on dup/clone, we need to duplicate @names hash
30
- def initialize_copy(other)
31
- super
32
- @names = other.names.dup
33
- end
34
-
35
- # need to synchronize concurrent writes to the shared KeyMap
36
- keymap_mutex = Mutex.new
37
-
38
- # symbol -> string mapper + cache
39
- KeyMap = Hash.new do |map, key|
40
- value = if key.respond_to?(:to_str)
41
- key
42
- else
43
- key.to_s.split('_'). # :user_agent => %w(user agent)
44
- each { |w| w.capitalize! }. # => %w(User Agent)
45
- join('-') # => "User-Agent"
46
- end
47
- keymap_mutex.synchronize { map[key] = value }
48
- end
49
- KeyMap[:etag] = "ETag"
50
-
51
- def [](k)
52
- k = KeyMap[k]
53
- super(k) || super(@names[k.downcase])
54
- end
55
-
56
- def []=(k, v)
57
- k = KeyMap[k]
58
- k = (@names[k.downcase] ||= k)
59
- # join multiple values with a comma
60
- v = v.to_ary.join(', ') if v.respond_to? :to_ary
61
- super(k, v)
62
- end
63
-
64
- def fetch(k, *args, &block)
65
- k = KeyMap[k]
66
- key = @names.fetch(k.downcase, k)
67
- super(key, *args, &block)
68
- end
69
-
70
- def delete(k)
71
- k = KeyMap[k]
72
- if k = @names[k.downcase]
73
- @names.delete k.downcase
74
- super(k)
75
- end
76
- end
77
-
78
- def include?(k)
79
- @names.include? k.downcase
80
- end
81
-
82
- alias_method :has_key?, :include?
83
- alias_method :member?, :include?
84
- alias_method :key?, :include?
85
-
86
- def merge!(other)
87
- other.each { |k, v| self[k] = v }
88
- self
89
- end
90
- alias_method :update, :merge!
91
-
92
- def merge(other)
93
- hash = dup
94
- hash.merge! other
95
- end
96
-
97
- def replace(other)
98
- clear
99
- @names.clear
100
- self.update other
101
- self
102
- end
103
-
104
- def to_hash() ::Hash.new.update(self) end
105
-
106
- def parse(header_string)
107
- return unless header_string && !header_string.empty?
108
-
109
- headers = header_string.split(/\r\n/)
110
-
111
- # Find the last set of response headers.
112
- start_index = headers.rindex { |x| x.match(/^HTTP\//) } || 0
113
- last_response = headers.slice(start_index, headers.size)
114
-
115
- last_response.
116
- tap { |a| a.shift if a.first.index('HTTP/') == 0 }. # drop the HTTP status line
117
- map { |h| h.split(/:\s*/, 2) }.reject { |p| p[0].nil? }. # split key and value, ignore blank lines
118
- each { |key, value|
119
- # join multiple values with a comma
120
- if self[key]
121
- self[key] << ', ' << value
122
- else
123
- self[key] = value
124
- end
125
- }
126
- end
127
-
128
- protected
129
-
130
- def names
131
- @names
132
- end
133
- end
134
-
135
- # hash with stringified keys
136
- class ParamsHash < Hash
137
- def [](key)
138
- super(convert_key(key))
139
- end
140
-
141
- def []=(key, value)
142
- super(convert_key(key), value)
143
- end
144
-
145
- def delete(key)
146
- super(convert_key(key))
147
- end
148
-
149
- def include?(key)
150
- super(convert_key(key))
151
- end
152
-
153
- alias_method :has_key?, :include?
154
- alias_method :member?, :include?
155
- alias_method :key?, :include?
156
-
157
- def update(params)
158
- params.each do |key, value|
159
- self[key] = value
160
- end
161
- self
162
- end
163
- alias_method :merge!, :update
164
-
165
- def merge(params)
166
- dup.update(params)
167
- end
168
-
169
- def replace(other)
170
- clear
171
- update(other)
172
- end
173
-
174
- def merge_query(query, encoder = nil)
175
- if query && !query.empty?
176
- update((encoder || Utils.default_params_encoder).decode(query))
177
- end
178
- self
179
- end
180
-
181
- def to_query(encoder = nil)
182
- (encoder || Utils.default_params_encoder).encode(self)
183
- end
184
-
185
- private
186
-
187
- def convert_key(key)
188
- key.to_s
189
- end
190
- end
9
+ module_function
191
10
 
192
11
  def build_query(params)
193
12
  FlatParamsEncoder.encode(params)
@@ -197,17 +16,27 @@ module Faraday
197
16
  NestedParamsEncoder.encode(params)
198
17
  end
199
18
 
200
- ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/
19
+ def default_space_encoding
20
+ @default_space_encoding ||= '+'
21
+ end
22
+
23
+ class << self
24
+ attr_writer :default_space_encoding
25
+ end
201
26
 
202
- def escape(s)
203
- s.to_s.gsub(ESCAPE_RE) {|match|
204
- '%' + match.unpack('H2' * match.bytesize).join('%').upcase
205
- }.tr(' ', '+')
27
+ ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/.freeze
28
+
29
+ def escape(str)
30
+ str.to_s.gsub(ESCAPE_RE) do |match|
31
+ "%#{match.unpack('H2' * match.bytesize).join('%').upcase}"
32
+ end.gsub(' ', default_space_encoding)
206
33
  end
207
34
 
208
- def unescape(s) CGI.unescape s.to_s end
35
+ def unescape(str)
36
+ CGI.unescape str.to_s
37
+ end
209
38
 
210
- DEFAULT_SEP = /[&;] */n
39
+ DEFAULT_SEP = /[&;] */n.freeze
211
40
 
212
41
  # Adapted from Rack
213
42
  def parse_query(query)
@@ -226,55 +55,18 @@ module Faraday
226
55
  attr_writer :default_params_encoder
227
56
  end
228
57
 
229
- # Stolen from Rack
230
- def normalize_params(params, name, v = nil)
231
- name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
232
- k = $1 || ''
233
- after = $' || ''
234
-
235
- return if k.empty?
236
-
237
- if after == ""
238
- if params[k]
239
- params[k] = Array[params[k]] unless params[k].kind_of?(Array)
240
- params[k] << v
241
- else
242
- params[k] = v
243
- end
244
- elsif after == "[]"
245
- params[k] ||= []
246
- raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
247
- params[k] << v
248
- elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
249
- child_key = $1
250
- params[k] ||= []
251
- raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
252
- if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key)
253
- normalize_params(params[k].last, child_key, v)
254
- else
255
- params[k] << normalize_params({}, child_key, v)
256
- end
257
- else
258
- params[k] ||= {}
259
- raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash)
260
- params[k] = normalize_params(params[k], after, v)
261
- end
262
-
263
- return params
264
- end
265
-
266
58
  # Normalize URI() behavior across Ruby versions
267
59
  #
268
60
  # url - A String or URI.
269
61
  #
270
62
  # Returns a parsed URI.
271
- def URI(url)
63
+ def URI(url) # rubocop:disable Naming/MethodName
272
64
  if url.respond_to?(:host)
273
65
  url
274
66
  elsif url.respond_to?(:to_str)
275
67
  default_uri_parser.call(url)
276
68
  else
277
- raise ArgumentError, "bad argument (expected URI object or URI string)"
69
+ raise ArgumentError, 'bad argument (expected URI object or URI string)'
278
70
  end
279
71
  end
280
72
 
@@ -287,27 +79,28 @@ module Faraday
287
79
 
288
80
  def default_uri_parser=(parser)
289
81
  @default_uri_parser = if parser.respond_to?(:call) || parser.nil?
290
- parser
291
- else
292
- parser.method(:parse)
293
- end
82
+ parser
83
+ else
84
+ parser.method(:parse)
85
+ end
294
86
  end
295
87
 
296
- # Receives a String or URI and returns just the path with the query string sorted.
88
+ # Receives a String or URI and returns just
89
+ # the path with the query string sorted.
297
90
  def normalize_path(url)
298
91
  url = URI(url)
299
- (url.path.start_with?('/') ? url.path : '/' + url.path) +
300
- (url.query ? "?#{sort_query_params(url.query)}" : "")
92
+ (url.path.start_with?('/') ? url.path : "/#{url.path}") +
93
+ (url.query ? "?#{sort_query_params(url.query)}" : '')
301
94
  end
302
95
 
303
96
  # Recursive hash update
304
97
  def deep_merge!(target, hash)
305
98
  hash.each do |key, value|
306
- if Hash === value and Hash === target[key]
307
- target[key] = deep_merge(target[key], value)
308
- else
309
- target[key] = value
310
- end
99
+ target[key] = if value.is_a?(Hash) && target[key].is_a?(Hash)
100
+ deep_merge(target[key], value)
101
+ else
102
+ value
103
+ end
311
104
  end
312
105
  target
313
106
  end
@@ -317,8 +110,6 @@ module Faraday
317
110
  deep_merge!(source.dup, hash)
318
111
  end
319
112
 
320
- protected
321
-
322
113
  def sort_query_params(query)
323
114
  query.split('&').sort.join('&')
324
115
  end