faraday 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +1 -1
  3. data/README.md +347 -18
  4. data/lib/faraday/adapter/em_http.rb +99 -142
  5. data/lib/faraday/adapter/em_http_ssl_patch.rb +17 -23
  6. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +15 -18
  7. data/lib/faraday/adapter/em_synchrony.rb +60 -104
  8. data/lib/faraday/adapter/excon.rb +55 -100
  9. data/lib/faraday/adapter/httpclient.rb +39 -61
  10. data/lib/faraday/adapter/net_http.rb +51 -104
  11. data/lib/faraday/adapter/net_http_persistent.rb +27 -48
  12. data/lib/faraday/adapter/patron.rb +35 -54
  13. data/lib/faraday/adapter/rack.rb +12 -28
  14. data/lib/faraday/adapter/test.rb +53 -86
  15. data/lib/faraday/adapter/typhoeus.rb +1 -4
  16. data/lib/faraday/adapter.rb +22 -36
  17. data/lib/faraday/autoload.rb +36 -47
  18. data/lib/faraday/connection.rb +179 -321
  19. data/lib/faraday/error.rb +33 -67
  20. data/lib/faraday/middleware.rb +28 -4
  21. data/lib/faraday/options.rb +186 -35
  22. data/lib/faraday/parameters.rb +197 -4
  23. data/lib/faraday/rack_builder.rb +56 -67
  24. data/lib/faraday/request/authorization.rb +30 -42
  25. data/lib/faraday/request/basic_authentication.rb +7 -14
  26. data/lib/faraday/request/instrumentation.rb +27 -45
  27. data/lib/faraday/request/multipart.rb +48 -79
  28. data/lib/faraday/request/retry.rb +170 -197
  29. data/lib/faraday/request/token_authentication.rb +10 -15
  30. data/lib/faraday/request/url_encoded.rb +23 -41
  31. data/lib/faraday/request.rb +36 -68
  32. data/lib/faraday/response/logger.rb +69 -22
  33. data/lib/faraday/response/raise_error.rb +14 -36
  34. data/lib/faraday/response.rb +16 -23
  35. data/lib/faraday/upload_io.rb +67 -0
  36. data/lib/faraday/utils.rb +245 -28
  37. data/lib/faraday.rb +175 -93
  38. metadata +5 -22
  39. data/lib/faraday/adapter_registry.rb +0 -28
  40. data/lib/faraday/dependency_loader.rb +0 -37
  41. data/lib/faraday/encoders/flat_params_encoder.rb +0 -94
  42. data/lib/faraday/encoders/nested_params_encoder.rb +0 -171
  43. data/lib/faraday/file_part.rb +0 -128
  44. data/lib/faraday/logging/formatter.rb +0 -92
  45. data/lib/faraday/middleware_registry.rb +0 -129
  46. data/lib/faraday/options/connection_options.rb +0 -22
  47. data/lib/faraday/options/env.rb +0 -181
  48. data/lib/faraday/options/proxy_options.rb +0 -28
  49. data/lib/faraday/options/request_options.rb +0 -21
  50. data/lib/faraday/options/ssl_options.rb +0 -59
  51. data/lib/faraday/param_part.rb +0 -53
  52. data/lib/faraday/utils/headers.rb +0 -139
  53. data/lib/faraday/utils/params_hash.rb +0 -61
  54. data/spec/external_adapters/faraday_specs_setup.rb +0 -14
data/lib/faraday/utils.rb CHANGED
@@ -1,12 +1,193 @@
1
- # frozen_string_literal: true
2
-
3
- require 'faraday/utils/headers'
4
- require 'faraday/utils/params_hash'
1
+ require 'thread'
5
2
 
6
3
  module Faraday
7
- # Utils contains various static helper methods.
8
4
  module Utils
9
- module_function
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
10
191
 
11
192
  def build_query(params)
12
193
  FlatParamsEncoder.encode(params)
@@ -16,19 +197,17 @@ module Faraday
16
197
  NestedParamsEncoder.encode(params)
17
198
  end
18
199
 
19
- ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/.freeze
200
+ ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/
20
201
 
21
- def escape(str)
22
- str.to_s.gsub(ESCAPE_RE) do |match|
202
+ def escape(s)
203
+ s.to_s.gsub(ESCAPE_RE) {|match|
23
204
  '%' + match.unpack('H2' * match.bytesize).join('%').upcase
24
- end.tr(' ', '+')
205
+ }.tr(' ', '+')
25
206
  end
26
207
 
27
- def unescape(str)
28
- CGI.unescape str.to_s
29
- end
208
+ def unescape(s) CGI.unescape s.to_s end
30
209
 
31
- DEFAULT_SEP = /[&;] */n.freeze
210
+ DEFAULT_SEP = /[&;] */n
32
211
 
33
212
  # Adapted from Rack
34
213
  def parse_query(query)
@@ -47,18 +226,55 @@ module Faraday
47
226
  attr_writer :default_params_encoder
48
227
  end
49
228
 
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
+
50
266
  # Normalize URI() behavior across Ruby versions
51
267
  #
52
268
  # url - A String or URI.
53
269
  #
54
270
  # Returns a parsed URI.
55
- def URI(url) # rubocop:disable Naming/MethodName
271
+ def URI(url)
56
272
  if url.respond_to?(:host)
57
273
  url
58
274
  elsif url.respond_to?(:to_str)
59
275
  default_uri_parser.call(url)
60
276
  else
61
- raise ArgumentError, 'bad argument (expected URI object or URI string)'
277
+ raise ArgumentError, "bad argument (expected URI object or URI string)"
62
278
  end
63
279
  end
64
280
 
@@ -71,28 +287,27 @@ module Faraday
71
287
 
72
288
  def default_uri_parser=(parser)
73
289
  @default_uri_parser = if parser.respond_to?(:call) || parser.nil?
74
- parser
75
- else
76
- parser.method(:parse)
77
- end
290
+ parser
291
+ else
292
+ parser.method(:parse)
293
+ end
78
294
  end
79
295
 
80
- # Receives a String or URI and returns just
81
- # the path with the query string sorted.
296
+ # Receives a String or URI and returns just the path with the query string sorted.
82
297
  def normalize_path(url)
83
298
  url = URI(url)
84
299
  (url.path.start_with?('/') ? url.path : '/' + url.path) +
85
- (url.query ? "?#{sort_query_params(url.query)}" : '')
300
+ (url.query ? "?#{sort_query_params(url.query)}" : "")
86
301
  end
87
302
 
88
303
  # Recursive hash update
89
304
  def deep_merge!(target, hash)
90
305
  hash.each do |key, value|
91
- target[key] = if value.is_a?(Hash) && target[key].is_a?(Hash)
92
- deep_merge(target[key], value)
93
- else
94
- value
95
- end
306
+ if Hash === value and Hash === target[key]
307
+ target[key] = deep_merge(target[key], value)
308
+ else
309
+ target[key] = value
310
+ end
96
311
  end
97
312
  target
98
313
  end
@@ -102,6 +317,8 @@ module Faraday
102
317
  deep_merge!(source.dup, hash)
103
318
  end
104
319
 
320
+ protected
321
+
105
322
  def sort_query_params(query)
106
323
  query.split('&').sort.join('&')
107
324
  end
data/lib/faraday.rb CHANGED
@@ -1,153 +1,129 @@
1
- # frozen_string_literal: true
2
-
1
+ require 'thread'
3
2
  require 'cgi'
4
3
  require 'set'
5
4
  require 'forwardable'
6
- require 'faraday/middleware_registry'
7
- require 'faraday/dependency_loader'
8
5
 
9
- # This is the main namespace for Faraday.
6
+ # Public: This is the main namespace for Faraday. You can either use it to
7
+ # create Faraday::Connection objects, or access it directly.
10
8
  #
11
- # It provides methods to create {Connection} objects, and HTTP-related
12
- # methods to use directly.
9
+ # Examples
13
10
  #
14
- # @example Helpful class methods for easy usage
15
11
  # Faraday.get "http://faraday.com"
16
12
  #
17
- # @example Helpful class method `.new` to create {Connection} objects.
18
13
  # conn = Faraday.new "http://faraday.com"
19
14
  # conn.get '/'
20
15
  #
21
16
  module Faraday
22
- VERSION = '0.16.0'
23
- METHODS_WITH_QUERY = %w[get head delete connect trace].freeze
24
- METHODS_WITH_BODY = %w[post put patch].freeze
17
+ VERSION = "0.17.0"
25
18
 
26
19
  class << self
27
- # The root path that Faraday is being loaded from.
28
- #
29
- # This is the root from where the libraries are auto-loaded.
30
- #
31
- # @return [String]
20
+ # Public: Gets or sets the root path that Faraday is being loaded from.
21
+ # This is the root from where the libraries are auto-loaded from.
32
22
  attr_accessor :root_path
33
23
 
34
- # Gets or sets the path that the Faraday libs are loaded from.
35
- # @return [String]
24
+ # Public: Gets or sets the path that the Faraday libs are loaded from.
36
25
  attr_accessor :lib_path
37
26
 
38
- # @overload default_adapter
39
- # Gets the Symbol key identifying a default Adapter to use
40
- # for the default {Faraday::Connection}. Defaults to `:net_http`.
41
- # @return [Symbol] the default adapter
42
- # @overload default_adapter=(adapter)
43
- # Updates default adapter while resetting {.default_connection}.
44
- # @return [Symbol] the new default_adapter.
27
+ # Public: Gets or sets the Symbol key identifying a default Adapter to use
28
+ # for the default Faraday::Connection.
45
29
  attr_reader :default_adapter
46
30
 
47
- # Documented below, see default_connection
31
+ # Public: Sets the default Faraday::Connection for simple scripts that
32
+ # access the Faraday constant directly.
33
+ #
34
+ # Faraday.get "https://faraday.com"
48
35
  attr_writer :default_connection
49
36
 
50
- # Tells Faraday to ignore the environment proxy (http_proxy).
51
- # Defaults to `false`.
52
- # @return [Boolean]
37
+ # Public: Tells faraday to ignore the environment proxy (http_proxy).
53
38
  attr_accessor :ignore_env_proxy
54
39
 
55
- # Initializes a new {Connection}.
56
- #
57
- # @param url [String,Hash] The optional String base URL to use as a prefix
58
- # for all requests. Can also be the options Hash. Any of these
59
- # values will be set on every request made, unless overridden
60
- # for a specific request.
61
- # @param options [Hash]
62
- # @option options [String] :url Base URL
63
- # @option options [Hash] :params Hash of unencoded URI query params.
64
- # @option options [Hash] :headers Hash of unencoded HTTP headers.
65
- # @option options [Hash] :request Hash of request options.
66
- # @option options [Hash] :ssl Hash of SSL options.
67
- # @option options [Hash] :proxy Hash of Proxy options.
68
- # @return [Faraday::Connection]
69
- #
70
- # @example With an URL argument
40
+ # Public: Initializes a new Faraday::Connection.
41
+ #
42
+ # url - The optional String base URL to use as a prefix for all
43
+ # requests. Can also be the options Hash.
44
+ # options - The optional Hash used to configure this Faraday::Connection.
45
+ # Any of these values will be set on every request made, unless
46
+ # overridden for a specific request.
47
+ # :url - String base URL.
48
+ # :params - Hash of URI query unencoded key/value pairs.
49
+ # :headers - Hash of unencoded HTTP header key/value pairs.
50
+ # :request - Hash of request options.
51
+ # :ssl - Hash of SSL options.
52
+ # :proxy - Hash of Proxy options.
53
+ #
54
+ # Examples
55
+ #
71
56
  # Faraday.new 'http://faraday.com'
72
- # # => Faraday::Connection to http://faraday.com
73
- #
74
- # @example With an URL argument and an options hash
75
- # Faraday.new 'http://faraday.com', params: { page: 1 }
76
- # # => Faraday::Connection to http://faraday.com?page=1
77
- #
78
- # @example With everything in an options hash
79
- # Faraday.new url: 'http://faraday.com',
80
- # params: { page: 1 }
81
- # # => Faraday::Connection to http://faraday.com?page=1
82
- def new(url = nil, options = {}, &block)
83
- options = default_connection_options.merge(options)
57
+ #
58
+ # # http://faraday.com?page=1
59
+ # Faraday.new 'http://faraday.com', :params => {:page => 1}
60
+ #
61
+ # # same
62
+ #
63
+ # Faraday.new :url => 'http://faraday.com',
64
+ # :params => {:page => 1}
65
+ #
66
+ # Returns a Faraday::Connection.
67
+ def new(url = nil, options = nil)
68
+ block = block_given? ? Proc.new : nil
69
+ options = options ? default_connection_options.merge(options) : default_connection_options
84
70
  Faraday::Connection.new(url, options, &block)
85
71
  end
86
72
 
87
- # @private
88
73
  # Internal: Requires internal Faraday libraries.
89
74
  #
90
- # @param libs [Array] one or more relative String names to Faraday classes.
91
- # @return [void]
75
+ # *libs - One or more relative String names to Faraday classes.
76
+ #
77
+ # Returns nothing.
92
78
  def require_libs(*libs)
93
79
  libs.each do |lib|
94
80
  require "#{lib_path}/#{lib}"
95
81
  end
96
82
  end
97
83
 
98
- alias require_lib require_libs
99
-
100
- # Documented elsewhere, see default_adapter reader
84
+ # Public: Updates default adapter while resetting
85
+ # #default_connection.
86
+ #
87
+ # Returns the new default_adapter.
101
88
  def default_adapter=(adapter)
102
89
  @default_connection = nil
103
90
  @default_adapter = adapter
104
91
  end
105
92
 
106
- def respond_to_missing?(symbol, include_private = false)
93
+ alias require_lib require_libs
94
+
95
+ def respond_to?(symbol, include_private = false)
107
96
  default_connection.respond_to?(symbol, include_private) || super
108
97
  end
109
98
 
110
- private
111
-
99
+ private
112
100
  # Internal: Proxies method calls on the Faraday constant to
113
- # .default_connection.
101
+ # #default_connection.
114
102
  def method_missing(name, *args, &block)
115
- if default_connection.respond_to?(name)
116
- default_connection.send(name, *args, &block)
117
- else
118
- super
119
- end
103
+ default_connection.send(name, *args, &block)
120
104
  end
121
105
  end
122
106
 
123
107
  self.ignore_env_proxy = false
124
- self.root_path = File.expand_path __dir__
125
- self.lib_path = File.expand_path 'faraday', __dir__
108
+ self.root_path = File.expand_path "..", __FILE__
109
+ self.lib_path = File.expand_path "../faraday", __FILE__
126
110
  self.default_adapter = :net_http
127
111
 
128
- # @overload default_connection
129
- # Gets the default connection used for simple scripts.
130
- # @return [Faraday::Connection] a connection configured with
131
- # the default_adapter.
132
- # @overload default_connection=(connection)
133
- # @param connection [Faraday::Connection]
134
- # Sets the default {Faraday::Connection} for simple scripts that
135
- # access the Faraday constant directly, such as
136
- # <code>Faraday.get "https://faraday.com"</code>.
112
+ # Gets the default connection used for simple scripts.
113
+ #
114
+ # Returns a Faraday::Connection, configured with the #default_adapter.
137
115
  def self.default_connection
138
116
  @default_connection ||= Connection.new(default_connection_options)
139
117
  end
140
118
 
141
- # Gets the default connection options used when calling {Faraday#new}.
119
+ # Gets the default connection options used when calling Faraday#new.
142
120
  #
143
- # @return [Faraday::ConnectionOptions]
121
+ # Returns a Faraday::ConnectionOptions.
144
122
  def self.default_connection_options
145
123
  @default_connection_options ||= ConnectionOptions.new
146
124
  end
147
125
 
148
- # Sets the default options used when calling {Faraday#new}.
149
- #
150
- # @param options [Hash, Faraday::ConnectionOptions]
126
+ # Public: Sets the default options used when calling Faraday#new.
151
127
  def self.default_connection_options=(options)
152
128
  @default_connection = nil
153
129
  @default_connection_options = ConnectionOptions.from(options)
@@ -158,9 +134,115 @@ module Faraday
158
134
  Timer = Timeout
159
135
  end
160
136
 
161
- require_libs 'utils', 'options', 'connection', 'rack_builder', 'parameters',
162
- 'middleware', 'adapter', 'request', 'response', 'error',
163
- 'file_part', 'param_part'
137
+ # Public: Adds the ability for other modules to register and lookup
138
+ # middleware classes.
139
+ module MiddlewareRegistry
140
+ # Public: Register middleware class(es) on the current module.
141
+ #
142
+ # mapping - A Hash mapping Symbol keys to classes. Classes can be expressed
143
+ # as fully qualified constant, or a Proc that will be lazily
144
+ # called to return the former.
145
+ #
146
+ # Examples
147
+ #
148
+ # module Faraday
149
+ # class Whatever
150
+ # # Middleware looked up by :foo returns Faraday::Whatever::Foo.
151
+ # register_middleware :foo => Foo
152
+ #
153
+ # # Middleware looked up by :bar returns Faraday::Whatever.const_get(:Bar)
154
+ # register_middleware :bar => :Bar
155
+ #
156
+ # # Middleware looked up by :baz requires 'baz' and returns Faraday::Whatever.const_get(:Baz)
157
+ # register_middleware :baz => [:Baz, 'baz']
158
+ # end
159
+ # end
160
+ #
161
+ # Returns nothing.
162
+ def register_middleware(autoload_path = nil, mapping = nil)
163
+ if mapping.nil?
164
+ mapping = autoload_path
165
+ autoload_path = nil
166
+ end
167
+ middleware_mutex do
168
+ @middleware_autoload_path = autoload_path if autoload_path
169
+ (@registered_middleware ||= {}).update(mapping)
170
+ end
171
+ end
164
172
 
165
- require_lib 'autoload' unless ENV['FARADAY_NO_AUTOLOAD']
173
+ # Public: Lookup middleware class with a registered Symbol shortcut.
174
+ #
175
+ # key - The Symbol key for the registered middleware.
176
+ #
177
+ # Examples
178
+ #
179
+ # module Faraday
180
+ # class Whatever
181
+ # register_middleware :foo => Foo
182
+ # end
183
+ # end
184
+ #
185
+ # Faraday::Whatever.lookup_middleware(:foo)
186
+ # # => Faraday::Whatever::Foo
187
+ #
188
+ # Returns a middleware Class.
189
+ def lookup_middleware(key)
190
+ load_middleware(key) ||
191
+ raise(Faraday::Error.new("#{key.inspect} is not registered on #{self}"))
192
+ end
193
+
194
+ def middleware_mutex(&block)
195
+ @middleware_mutex ||= begin
196
+ require 'monitor'
197
+ Monitor.new
198
+ end
199
+ @middleware_mutex.synchronize(&block)
200
+ end
201
+
202
+ def fetch_middleware(key)
203
+ defined?(@registered_middleware) && @registered_middleware[key]
204
+ end
205
+
206
+ def load_middleware(key)
207
+ value = fetch_middleware(key)
208
+ case value
209
+ when Module
210
+ value
211
+ when Symbol, String
212
+ middleware_mutex do
213
+ @registered_middleware[key] = const_get(value)
214
+ end
215
+ when Proc
216
+ middleware_mutex do
217
+ @registered_middleware[key] = value.call
218
+ end
219
+ when Array
220
+ middleware_mutex do
221
+ const, path = value
222
+ if root = @middleware_autoload_path
223
+ path = "#{root}/#{path}"
224
+ end
225
+ require(path)
226
+ @registered_middleware[key] = const
227
+ end
228
+ load_middleware(key)
229
+ end
230
+ end
231
+ end
232
+
233
+ def self.const_missing(name)
234
+ if name.to_sym == :Builder
235
+ warn "Faraday::Builder is now Faraday::RackBuilder."
236
+ const_set name, RackBuilder
237
+ else
238
+ super
239
+ end
240
+ end
241
+
242
+ require_libs "utils", "options", "connection", "rack_builder", "parameters",
243
+ "middleware", "adapter", "request", "response", "upload_io", "error"
244
+
245
+ if !ENV["FARADAY_NO_AUTOLOAD"]
246
+ require_lib 'autoload'
247
+ end
166
248
  end