[ANN] Needle 0.5.0

Needle is a new dependency injection (a.k.a. "inversion of control") container for Ruby.

Project Page/Downloads:: http://rubyforge.org/projects/needle
User Manual (work in progress):: http://needle.rubyforge.org
API Documentation:: http://needle.rubyforge.org/api
Needle Wiki:: http://needle.rubyforge.org/wiki/wiki.pl

This release (0.5) is the first public release. Needle is currently considered experimental software. You are encouraged to download it and try it out, but be warned that subsequent releases of Needle may change the API in non-backwards-compatible ways. This trend will continue until the release of Needle 1.0, at which point Needle will be considered "stable".

Please report any bugs. The bug tracker on the project page is a good place to do so, or you can just email me (jgb3@email.byu.edu). Additionally, you might consider taking advantage of the following resources:

Bug Reports:: http://rubyforge.org/tracker/?atid=1642&group_id=410&func=browse
Forums:: http://rubyforge.org/forum/?group_id=410
Mailing List:: http://rubyforge.org/mailman/listinfo/needle-discuss
Feature Requests:: http://rubyforge.org/tracker/?atid=1645&group_id=410&func=browse

== FEATURES

* Type 2 (setter) injection. This means you can satisfy service dependencies by setting properties on the services.

* Type 3 (constructor) injection. This means you can satisfy service dependencies by passing them as parameters to the constructors of the services.

* Service Interceptors. This allows you to specify non-intrusive "interceptor" objects that sit between the client and the service, intercepting all method calls to the service. You can implement some simple AOP-like functionality this way.

* Integrated, highly-configurable logging subsystem, available as a service.

* Service configuration in Ruby (no external configuration files).

* Lifecycle management. Configure services to be singletons or prototypes, and to use either immediate or deferred instantiation.

* Light-weight, and fast (as compared to Copland)

== EXAMPLES

Jim (Weirich)'s originally proposed syntax is still completely valid:

   require 'needle'

   registry = Needle::Registry.new
   registry.register( :foo ) { |c| Struct.new( :value ).new( 5 ) }
   registry.register( :bar ) { |c| Struct.new( :value ).new( c.foo ) }

   bar = registry.bar
   p bar.value #-> 5

Additionally, Eivind Eklund suggested a "domain language" approach that is also available:

   require 'needle'
   registry = Needle::Registry.new

   registry.register! do
     foo { Struct.new( :value ).new( 5 ) }
     bar { Struct.new( :value ).new( foo ) }
   end

   bar = registry.bar
   p bar.value #-> 5

You can also create hierarchical namespaces inside of a registry:

   registry.namespace :level1 do |l1|
     l1.namespace :level2 do |l2|
       l2.register( :foo ) { "hello" }
     end
   end

   p registry.level1.level2.foo #-> "hello"

For more, see the User Manual, and the "examples" subdirectory of the Needle distribution.

== HISTORY

At RubyConf 2004, Jim Weirich approached me (Jamis Buck) after my presentation on Copland and mused aloud, "I wonder what would happen if you started with Ruby's features and evolved a DI container?" I agreed that it would be an interesting exercise.

Jim (being who he is) sent me a rough draft of an article a few days later. This article was one he was going to post on his blog, entitled "Dependency Injection in Ruby" (http://onestepback.org/index.cgi/Tech/Ruby/DependencyInjectionInRuby.rdoc). In it he laid out a bare-bones implementation of DI using some of Ruby's most compelling features, like blocks.

Jim granted me permission to work on his implementation, and Needle was born. Eivind Eklund and Mauricio Fernández were both kind enough to review my additions and offer suggestions.

···

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis