Skip to content

Commit

Permalink
add Faraday.register_middleware
Browse files Browse the repository at this point in the history
Allows 3rd-party libraries to register named shortcuts to resolve to
fully qualified constant names for specific middleware.

Usage:
  Faraday.register_middleware :aloha => MyModule::Aloha
  Faraday.register_middleware :response, :boom => MyModule::Boom
  Faraday.register_middleware :lazy => lambda { MyModule::LazyLoaded }

Those shortcuts are then available in Builder:
  builder.use :aloha
  builder.response :boom
  • Loading branch information
mislav committed Jan 2, 2012
1 parent 6124a6a commit a81b705
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 16 deletions.
47 changes: 41 additions & 6 deletions lib/faraday.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,28 @@ def self.default_connection
@default_connection ||= Connection.new
end

module AutoloadHelper
def register_lookup_modules(mods)
(@lookup_module_index ||= {}).update(mods)
module MiddlewareRegistry
# Internal: Register middleware class(es) on the current module.
#
# mapping - A Hash mapping Symbol keys to classes. See
# Faraday.register_middleware for more details.
def register_middleware(mapping)
(@registered_middleware ||= {}).update(mapping)
end

def lookup_module(key)
return if !@lookup_module_index
const_get @lookup_module_index[key] || key
# Internal: Lookup middleware class with a registered Symbol shortcut.
#
# Returns a middleware Class.
def lookup_middleware(key)
unless defined? @registered_middleware and found = @registered_middleware[key]
raise "#{key.inspect} is not registered on #{self}"
end
found = @registered_middleware[key] = found.call if found.is_a? Proc
found.is_a?(Module) ? found : const_get(found)
end
end

module AutoloadHelper
def autoload_all(prefix, options)
if prefix =~ /^faraday(\/|$)/i
prefix = File.join(Faraday.root_path, prefix)
Expand All @@ -68,6 +80,29 @@ def all_loaded_constants

extend AutoloadHelper

# Public: register middleware classes under a short name.
#
# type - A Symbol specifying the kind of middleware (default: :middleware)
# mapping - A Hash mapping Symbol keys to classes. Classes can be expressed
# as fully qualified constant, or a Proc that will be lazily called
# to return the former.
#
# Examples
#
# Faraday.register_middleware :aloha => MyModule::Aloha
# Faraday.register_middleware :response, :boom => MyModule::Boom
#
# # shortcuts are now available in Builder:
# builder.use :aloha
# builder.response :boom
#
# Returns nothing.
def self.register_middleware type, mapping = nil
type, mapping = :middleware, type if mapping.nil?
component = self.const_get(type.to_s.capitalize)
component.register_middleware(mapping)
end

autoload_all "faraday",
:Middleware => 'middleware',
:Builder => 'builder',
Expand Down
3 changes: 2 additions & 1 deletion lib/faraday/adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ class Adapter < Middleware
CONTENT_LENGTH = 'Content-Length'.freeze

extend AutoloadHelper
extend MiddlewareRegistry

autoload_all 'faraday/adapter',
:ActionDispatch => 'action_dispatch',
Expand All @@ -13,7 +14,7 @@ class Adapter < Middleware
:Excon => 'excon',
:Test => 'test'

register_lookup_modules \
register_middleware \
:action_dispatch => :ActionDispatch,
:test => :Test,
:net_http => :NetHttp,
Expand Down
10 changes: 7 additions & 3 deletions lib/faraday/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,13 @@ def locked?
end

def use(klass, *args)
raise_if_locked
block = block_given? ? Proc.new : nil
@handlers << self.class::Handler.new(klass, *args, &block)
if klass.is_a? Symbol
use_symbol(Faraday::Middleware, klass, *args, &block)
else
raise_if_locked
@handlers << self.class::Handler.new(klass, *args, &block)
end
end

def request(key, *args)
Expand Down Expand Up @@ -144,7 +148,7 @@ def raise_if_locked

def use_symbol(mod, key, *args)
block = block_given? ? Proc.new : nil
use(mod.lookup_module(key), *args, &block)
use(mod.lookup_middleware(key), *args, &block)
end

def assert_index(index)
Expand Down
2 changes: 2 additions & 0 deletions lib/faraday/middleware.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module Faraday
class Middleware
extend MiddlewareRegistry

class << self
attr_accessor :load_error, :supports_parallel_requests
alias supports_parallel_requests? supports_parallel_requests
Expand Down
3 changes: 2 additions & 1 deletion lib/faraday/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module Faraday
#
class Request < Struct.new(:path, :params, :headers, :body, :options)
extend AutoloadHelper
extend MiddlewareRegistry

autoload_all 'faraday/request',
:UrlEncoded => 'url_encoded',
Expand All @@ -20,7 +21,7 @@ class Request < Struct.new(:path, :params, :headers, :body, :options)
:BasicAuthentication => 'basic_authentication',
:TokenAuthentication => 'token_authentication'

register_lookup_modules \
register_middleware \
:url_encoded => :UrlEncoded,
:multipart => :Multipart,
:retry => :Retry,
Expand Down
3 changes: 2 additions & 1 deletion lib/faraday/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ def on_complete(env)

extend Forwardable
extend AutoloadHelper
extend MiddlewareRegistry

autoload_all 'faraday/response',
:RaiseError => 'raise_error',
:Logger => 'logger'

register_lookup_modules \
register_middleware \
:raise_error => :RaiseError,
:logger => :Logger

Expand Down
4 changes: 2 additions & 2 deletions test/adapters/live_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
module Adapters
class LiveTest < Faraday::TestCase
adapters = if ENV['ADAPTER']
ENV['ADAPTER'].split(':').map { |name| Faraday::Adapter.lookup_module name.to_sym }
ENV['ADAPTER'].split(':').map { |name| Faraday::Adapter.lookup_middleware name.to_sym }
else
loaded_adapters = Faraday::Adapter.all_loaded_constants
loaded_adapters -= [Faraday::Adapter::ActionDispatch]
Expand Down Expand Up @@ -217,7 +217,7 @@ def create_connection(adapter, options = {})

def real_adapter_for(adapter)
if adapter == :default
Faraday::Adapter.lookup_module(Faraday.default_adapter)
Faraday::Adapter.lookup_middleware(Faraday.default_adapter)
else
adapter
end
Expand Down
45 changes: 43 additions & 2 deletions test/middleware_stack_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ def setup
end

def test_sets_default_adapter_if_none_set
default_middleware = Faraday::Request.lookup_module :url_encoded
default_adapter_klass = Faraday::Adapter.lookup_module Faraday.default_adapter
default_middleware = Faraday::Request.lookup_middleware :url_encoded
default_adapter_klass = Faraday::Adapter.lookup_middleware Faraday.default_adapter
assert @builder[0] == default_middleware
assert @builder[1] == default_adapter_klass
end
Expand Down Expand Up @@ -94,12 +94,48 @@ def test_handler_comparison
assert_equal @builder.handlers.first, Faraday::Builder::Handler.new(Apple)
end

def test_unregistered_symbol
err = assert_raise(RuntimeError) { build_stack :apple }
assert_equal ":apple is not registered on Faraday::Middleware", err.message
end

def test_registered_symbol
Faraday.register_middleware :apple => Apple
begin
build_stack :apple
assert_handlers %w[Apple]
ensure
unregister_middleware Faraday::Middleware, :apple
end
end

def test_registered_symbol_with_proc
Faraday.register_middleware :apple => lambda { Apple }
begin
build_stack :apple
assert_handlers %w[Apple]
ensure
unregister_middleware Faraday::Middleware, :apple
end
end

def test_registered_symbol_with_type
Faraday.register_middleware :request, :orange => Orange
begin
build_stack {|b| b.request :orange }
assert_handlers %w[Orange]
ensure
unregister_middleware Faraday::Request, :orange
end
end

private

# make a stack with test adapter that reflects the order of middleware
def build_stack(*handlers)
@builder.build do |b|
handlers.each { |handler| b.use(*handler) }
yield b if block_given?

b.adapter :test do |stub|
stub.get '/' do |env|
Expand All @@ -115,4 +151,9 @@ def assert_handlers(list)
echoed_list.shift if echoed_list.first == ''
assert_equal list, echoed_list
end

def unregister_middleware(component, key)
# TODO: unregister API?
component.instance_variable_get('@registered_middleware').delete(key)
end
end

0 comments on commit a81b705

Please sign in to comment.