This module encapsulates the functionality for building interceptor chains.
Methods
Classes and Modules
Class Needle::InterceptorChainBuilder::InterceptedServiceProxyClass Needle::InterceptorChainBuilder::InterceptorChainElement
Class Needle::InterceptorChainBuilder::ProxyObjectChainElement
Constants
InvocationContext | = | Struct.new( :sym, :args, :block, :data ) |
The context of a method invocation. This is used in an interceptor chain to
encapsulate the elements of the current invocation. sym: the name of the
method being invoked args: the argument list being passed to the method
block: the reference to the block attached to the method invocation data: a
hash that may be used by clients for storing arbitrary data in
the context. |
Public Instance methods
This will apply the given interceptors to the given service by first ordering the interceptors based on their relative priorities, and then dynamically modifying the service’s methods so that the chain of interceptors sits in front of each of them.
The modified service is returned.
[ show source ]
# File lib/needle/interceptor-chain.rb, line 103 103: def build( point, service, interceptors ) 104: return service if interceptors.nil? || interceptors.empty? 105: 106: ordered_list = 107: interceptors.sort { |a,b| 108: a.options[:priority] <=> b.options[:priority] } 109: 110: chain = ProxyObjectChainElement.new( service ) 111: 112: ordered_list.reverse.each do |interceptor| 113: factory = interceptor.action.call( point.container ) 114: instance = factory.new( point, interceptor.options ) 115: element = InterceptorChainElement.new( instance ) 116: element.next = chain 117: chain = element 118: end 119: 120: # FIXME: should inherited methods of "Object" be interceptable? 121: methods_to_intercept = ( service.class.instance_methods( true ) - 122: Object.instance_methods + 123: service.class.instance_methods( false ) ).uniq 124: 125: service = InterceptedServiceProxy.new( chain ) 126: singleton = class << service; self; end 127: 128: methods_to_intercept.each do |method| 129: next if method =~ /^__/ 130: 131: if singleton.instance_methods(false).include? method 132: singleton.send( :remove_method, method ) 133: end 134: 135: singleton.class_eval "def \#{method}( *args, &block )\ncontext = InvocationContext.new( :\#{method}, args, block, Hash.new )\n@chain.process_next( context )\nend\n" 136: end 137: 138: # allow the interceptor to intercept methods not explicitly 139: # declared on the reciever. 140: if singleton.instance_methods(false).include? "method_missing" 141: singleton.send( :remove_method, :method_missing ) 142: end 143: 144: singleton.class_eval "def method_missing( sym, *args, &block )\ncontext = InvocationContext.new( sym, args, block, Hash.new )\n@chain.process_next( context )\nend\n" 145: 146: return service 147: end