From: Joel VanderWerf Date: 2004-11-15T05:07:02+09:00 Subject: [ANN] MinDI: Minimalist Dependency Injection MinDI is a DI (dependency injection) or IoC (invesion of control) framework for ruby inspired by Jamis Buck's Needle (http://needle.rubyforge.org) and Jim Weirich's article on DI in Ruby (http://onestepback.org/index.cgi/Tech/Ruby/DependencyInjectionInRuby.rdoc). DOWNLOAD MinDI is available at: http://redshift.sourceforge.net/mindi/ Includes examples, tests, and basic docs. It's a proof of concept, but has enough features for production use. DESCRIPTION MinDI is minimalist in that it attempts to map concepts of DI into basic ruby constructs, rather than into a layer of specialized constructs. In particular, classes and modules function as containers and registries, and methods and method definitions function as service points and services. There are some inherent advantages and disadvantages to this approach. Advantages: - Compact implementation. - Compact syntax. - Familiar constructs and idioms, like subclassing, module inclusion, nested classes, protected and private, all apply. - Use of classes and methods as containers and services means you can apply a standard AOP or debugging lib. - Services can take arguments, and this permits multiton services. Disadvantages: - A container's services live in the same namespace as the methods inherited from Kernel and Object, so a service called "dup", for example, will prevent calling Object#dup on the container (except in the implementation of the dup service, which can use super to invoke Object#dup). The MinDI framework itself adds a few methods that could conflict with services (#singleton, #generic, etc.). - No built-in AOP, debugging, or reflection interface. Notes: - Supports threaded, deferred, singleton, and multiton service models (though these are not yet independent choices). Additional service models can be easily added in modules which include Container. The "generic" model can be used like "prototype" in Needle, or for manual service management. - Use mixins to build apps out of groups of services that need to coexist in one name space. - Use a nested class for a group of services when you want them to live in their own namespace. EXAMPLES An example with parametric services: class Point < Struct.new(:x, :y); end class MyContainer extend MinDI::Container # A multiton service: a unique value is generated for # each requested parameter list. point_for_xy { |x,y| Point.new(x,y) } rect_with_width { |w| [point_for(0,0), point_for(w,200)] } end The example from Jim Weirich's article would look like this in MinDI: class JWApplicationContainer extend MinDI::Container logfilename { "logfile.log" } db_user { "jim" } db_password { "secret" } dbi_string { "DBI:Pg:example_data" } app { app = WebApp.new(quotes, authenticator, database) app.logger = logger app.set_error_handler error_handler app } quotes { StockQuotes.new(error_handler, logger) } authenticator { Authenticator.new(database, logger, error_handler) } database { DBI.connect(dbi_string, db_user, db_password) } logger { Logger.new(logfilename) } error_handler { errh = ErrorHandler.new errh.logger = logger errh } end def create_application JWApplicationContainer.new.app end