diff --git a/lib/faraday.rb b/lib/faraday.rb index 0f9dfd367..03153f8e7 100644 --- a/lib/faraday.rb +++ b/lib/faraday.rb @@ -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. # @@ -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}] 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" diff --git a/lib/faraday/adapter.rb b/lib/faraday/adapter.rb index 78cbf1026..11147fec4 100644 --- a/lib/faraday/adapter.rb +++ b/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__), @@ -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 @@ -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 diff --git a/lib/faraday/dependency_loader.rb b/lib/faraday/dependency_loader.rb new file mode 100644 index 000000000..c46960207 --- /dev/null +++ b/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 diff --git a/lib/faraday/middleware.rb b/lib/faraday/middleware.rb index c45d51ade..c1468bd37 100644 --- a/lib/faraday/middleware.rb +++ b/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 diff --git a/lib/faraday/middleware_registry.rb b/lib/faraday/middleware_registry.rb new file mode 100644 index 000000000..26625e7d7 --- /dev/null +++ b/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}] 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 diff --git a/lib/faraday/rack_builder.rb b/lib/faraday/rack_builder.rb index d6fb077a5..7c3448a22 100644 --- a/lib/faraday/rack_builder.rb +++ b/lib/faraday/rack_builder.rb @@ -47,7 +47,7 @@ def ==(other) end end - def build(app) + def build(app = nil) klass.new(app, *@args, &@block) end end @@ -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)