From: Brian Candler Date: 2009-08-27T16:18:33+09:00 Subject: Re: Rack must not dictate how to create a middleware > With current Builder you just write: > > use M1 > use M2 > use M3 > run App > > The whole point is that it encapsulates the following pattern for you: [correction] a = App b = M3.new(a) c = M2.new(b) d = M1.new(c) run d Anyway, there's nothing magic about the method 'new'. You could write: module Mine def self.new(app) @app = app self end def self.call(env) ... @app.call(env) end end Or even this: nextapp = nil mymid = lambda { |env| puts "Got #{env}"; nextapp.call(env) } class << mymid; self; end.class_eval { define_method(:new) { |na| nextapp = na; mymid } } That is, you can make your code conform to the middleware API simply by implementing a 'new' method which sets the next app in the chain, and returns the object to be called. You can make a wrapper for this pattern if you are using it frequently. But I still assert that middleware written as a singleton is pretty useless. The whole point of Rack is that you can have a complex branching tree of request handling, and each node in the tree "knows" where to forward the request next. Having a node which can only ever forward to one place makes it impossible to plug in somewhere else. I cannot think of any realistic example where this makes sense. Certainly there may be middleware objects which share some underlying singleton object (e.g. a logger), but the middleware object itself should not be a singleton, because it's responsible for storing the next hop. class LoggerMiddleware @logger = Logger.new # *this* is the singleton object def self.log(*args) @logger.log(args.inspect) end def initialize(app) @app = app end def call(env) resp = @app.call(env) self.class.log(env, resp) resp end end -- Posted via http://www.ruby-forum.com/.