Skip to content

Commit

Permalink
Refactor Adapter as final endpoints (#846)
Browse files Browse the repository at this point in the history
* Refactors Adapters:
* They're now final endpoints.
* They don't need to call `@app.call` anymore.
* They don't inherit from `Faraday::Middleware` anymore.
  • Loading branch information
iMacTia authored and olleolleolle committed Feb 19, 2019
1 parent 3fbf2d5 commit 6e4a2aa
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 159 deletions.
122 changes: 2 additions & 120 deletions lib/faraday.rb
Expand Up @@ -2,6 +2,8 @@
require 'cgi'
require 'set'
require 'forwardable'
require 'faraday/middleware_registry'
require 'faraday/dependency_loader'

# This is the main namespace for Faraday.
#
Expand Down Expand Up @@ -147,126 +149,6 @@ def self.default_connection_options=(options)
Timer = Timeout
end

# Adds the ability for other modules to register and lookup
# middleware classes.
module MiddlewareRegistry
# Register middleware class(es) on the current module.
#
# @param autoload_path [String] Middleware autoload path
# @param mapping [Hash{Symbol => Module, Symbol, Array<Module, Symbol, String>}] Middleware mapping from a lookup symbol to a reference to the middleware. - Classes can be expressed as:
# - a fully qualified constant
# - a Symbol
# - a Proc that will be lazily called to return the former
# - an array is given, its first element is the constant or symbol,
# and its second is a file to `require`.
# @return [void]
#
# @example Lookup by a constant
#
# module Faraday
# class Whatever
# # Middleware looked up by :foo returns Faraday::Whatever::Foo.
# register_middleware :foo => Foo
# end
# end
#
# @example Lookup by a symbol
#
# module Faraday
# class Whatever
# # Middleware looked up by :bar returns Faraday::Whatever.const_get(:Bar)
# register_middleware :bar => :Bar
# end
# end
#
# @example Lookup by a symbol and string in an array
#
# module Faraday
# class Whatever
# # Middleware looked up by :baz requires 'baz' and returns Faraday::Whatever.const_get(:Baz)
# register_middleware :baz => [:Baz, 'baz']
# end
# end
#
def register_middleware(autoload_path = nil, mapping = nil)
if mapping.nil?
mapping = autoload_path
autoload_path = nil
end
middleware_mutex do
@middleware_autoload_path = autoload_path if autoload_path
(@registered_middleware ||= {}).update(mapping)
end
end

# Unregister a previously registered middleware class.
#
# @param key [Symbol] key for the registered middleware.
def unregister_middleware(key)
@registered_middleware.delete(key)
end

# Lookup middleware class with a registered Symbol shortcut.
#
# @param key [Symbol] key for the registered middleware.
# @return [Class] a middleware Class.
# @raise [Faraday::Error] if given key is not registered
#
# @example
#
# module Faraday
# class Whatever
# register_middleware :foo => Foo
# end
# end
#
# Faraday::Whatever.lookup_middleware(:foo)
# # => Faraday::Whatever::Foo
#
def lookup_middleware(key)
load_middleware(key) ||
raise(Faraday::Error.new("#{key.inspect} is not registered on #{self}"))
end

def middleware_mutex(&block)
@middleware_mutex ||= begin
require 'monitor'
Monitor.new
end
@middleware_mutex.synchronize(&block)
end

def fetch_middleware(key)
defined?(@registered_middleware) && @registered_middleware[key]
end

def load_middleware(key)
value = fetch_middleware(key)
case value
when Module
value
when Symbol, String
middleware_mutex do
@registered_middleware[key] = const_get(value)
end
when Proc
middleware_mutex do
@registered_middleware[key] = value.call
end
when Array
middleware_mutex do
const, path = value
if root = @middleware_autoload_path
path = "#{root}/#{path}"
end
require(path)
@registered_middleware[key] = const
end
load_middleware(key)
end
end
end

require_libs "utils", "options", "connection", "rack_builder", "parameters",
"middleware", "adapter", "request", "response", "upload_io", "error"

Expand Down
11 changes: 9 additions & 2 deletions lib/faraday/adapter.rb
@@ -1,7 +1,10 @@
module Faraday
# Base class for all Faraday adapters. Adapters are
# responsible for fulfilling a Faraday request.
class Adapter < Middleware
class Adapter
extend MiddlewareRegistry
extend DependencyLoader

CONTENT_LENGTH = 'Content-Length'.freeze

register_middleware File.expand_path('../adapter', __FILE__),
Expand Down Expand Up @@ -31,13 +34,14 @@ def inherited(subclass)
self.supports_parallel = false

def initialize(app = nil, opts = {}, &block)
super(app)
@app = lambda { |env| env.response }
@connection_options = opts
@config_block = block
end

def call(env)
env.clear_body if env.needs_body?
env.response = Response.new
end

private
Expand All @@ -50,6 +54,9 @@ def save_response(env, status, body, headers = nil, reason_phrase = nil)
response_headers.update headers unless headers.nil?
yield(response_headers) if block_given?
end

env.response.finish(env) unless env.parallel?
env.response
end
end
end
27 changes: 27 additions & 0 deletions lib/faraday/dependency_loader.rb
@@ -0,0 +1,27 @@
module Faraday
module DependencyLoader
attr_accessor :load_error
private :load_error=

# Executes a block which should try to require and reference dependent libraries
def dependency(lib = nil)
lib ? require(lib) : yield
rescue LoadError, NameError => error
self.load_error = error
end

def new(*)
raise "missing dependency for #{self}: #{load_error.message}" unless loaded?
super
end

def loaded?
load_error.nil?
end

def inherited(subclass)
super
subclass.send(:load_error=, self.load_error)
end
end
end
29 changes: 1 addition & 28 deletions lib/faraday/middleware.rb
@@ -1,34 +1,7 @@
module Faraday
class Middleware
extend MiddlewareRegistry

class << self
attr_accessor :load_error
private :load_error=
end

self.load_error = nil

# Executes a block which should try to require and reference dependent libraries
def self.dependency(lib = nil)
lib ? require(lib) : yield
rescue LoadError, NameError => error
self.load_error = error
end

def self.new(*)
raise "missing dependency for #{self}: #{load_error.message}" unless loaded?
super
end

def self.loaded?
load_error.nil?
end

def self.inherited(subclass)
super
subclass.send(:load_error=, self.load_error)
end
extend DependencyLoader

def initialize(app = nil)
@app = app
Expand Down
121 changes: 121 additions & 0 deletions lib/faraday/middleware_registry.rb
@@ -0,0 +1,121 @@
module Faraday
# Adds the ability for other modules to register and lookup
# middleware classes.
module MiddlewareRegistry
# Register middleware class(es) on the current module.
#
# @param autoload_path [String] Middleware autoload path
# @param mapping [Hash{Symbol => Module, Symbol, Array<Module, Symbol, String>}] Middleware mapping from a lookup symbol to a reference to the middleware. - Classes can be expressed as:
# - a fully qualified constant
# - a Symbol
# - a Proc that will be lazily called to return the former
# - an array is given, its first element is the constant or symbol,
# and its second is a file to `require`.
# @return [void]
#
# @example Lookup by a constant
#
# module Faraday
# class Whatever
# # Middleware looked up by :foo returns Faraday::Whatever::Foo.
# register_middleware :foo => Foo
# end
# end
#
# @example Lookup by a symbol
#
# module Faraday
# class Whatever
# # Middleware looked up by :bar returns Faraday::Whatever.const_get(:Bar)
# register_middleware :bar => :Bar
# end
# end
#
# @example Lookup by a symbol and string in an array
#
# module Faraday
# class Whatever
# # Middleware looked up by :baz requires 'baz' and returns Faraday::Whatever.const_get(:Baz)
# register_middleware :baz => [:Baz, 'baz']
# end
# end
#
def register_middleware(autoload_path = nil, mapping = nil)
if mapping.nil?
mapping = autoload_path
autoload_path = nil
end
middleware_mutex do
@middleware_autoload_path = autoload_path if autoload_path
(@registered_middleware ||= {}).update(mapping)
end
end

# Unregister a previously registered middleware class.
#
# @param key [Symbol] key for the registered middleware.
def unregister_middleware(key)
@registered_middleware.delete(key)
end

# Lookup middleware class with a registered Symbol shortcut.
#
# @param key [Symbol] key for the registered middleware.
# @return [Class] a middleware Class.
# @raise [Faraday::Error] if given key is not registered
#
# @example
#
# module Faraday
# class Whatever
# register_middleware :foo => Foo
# end
# end
#
# Faraday::Whatever.lookup_middleware(:foo)
# # => Faraday::Whatever::Foo
#
def lookup_middleware(key)
load_middleware(key) ||
raise(Faraday::Error.new("#{key.inspect} is not registered on #{self}"))
end

def middleware_mutex(&block)
@middleware_mutex ||= begin
require 'monitor'
Monitor.new
end
@middleware_mutex.synchronize(&block)
end

def fetch_middleware(key)
defined?(@registered_middleware) && @registered_middleware[key]
end

def load_middleware(key)
value = fetch_middleware(key)
case value
when Module
value
when Symbol, String
middleware_mutex do
@registered_middleware[key] = const_get(value)
end
when Proc
middleware_mutex do
@registered_middleware[key] = value.call
end
when Array
middleware_mutex do
const, path = value
if root = @middleware_autoload_path
path = "#{root}/#{path}"
end
require(path)
@registered_middleware[key] = const
end
load_middleware(key)
end
end
end
end
13 changes: 4 additions & 9 deletions lib/faraday/rack_builder.rb
Expand Up @@ -47,7 +47,7 @@ def ==(other)
end
end

def build(app)
def build(app = nil)
klass.new(app, *@args, &@block)
end
end
Expand Down Expand Up @@ -160,19 +160,14 @@ def build_response(connection, request)
def app
@app ||= begin
lock!
to_app(lambda { |env|
response = Response.new
env.response = response
response.finish(env) unless env.parallel?
response
})
to_app
end
end

def to_app(inner_app)
def to_app
# last added handler is the deepest and thus closest to the inner app
# adapter is always the last one
(@handlers + [@adapter]).reverse.inject(inner_app) { |app, handler| handler.build(app) }
(@handlers).reverse.inject(@adapter.build) { |app, handler| handler.build(app) }
end

def ==(other)
Expand Down

0 comments on commit 6e4a2aa

Please sign in to comment.