Chad Fowler wrote:
> For those not subscribed to RubyGarden's rss feed[1], Jamis Buck has
> written a new feature piece discussing his journey from
> dependency-injection-novice to two-time-IoC-frameworker.  He also
> discusses the (unusual) decision to start over on a framework that is
> less than a year old and demonstrates the differences between these
> two frameworks (Copland and Needle).  Big thanks go to Jamis for his
> fascinating contribution.
> 
> The article is available on RubyGarden's front page or at:
> http://rubygarden.org/index.cgi/Libraries/copland-to-needle.rdoc
> 
> Request: If you'd like to write an article or tutorial or conduct an
> interview to be published on RubyGarden.org, please send me an email
> directly.  I'm working to establish a rhythm of new content releases,
> so if you're interested in contributing I would love to hear from you.
> 
> Thanks,
> Chad Fowler
> 
> [1] http://rubygarden.org/index.cgi/index.rss

Jamis Buck's and Jim Weirich's articles are great. I could never get
through the Java-oriented discussion of this subject, and now that the
subject is presented for rubyists a dim bulb is finally going on in my
head.

What really helps me think about this is to reduce it to some simple,
standard Ruby idioms, which don't provide as many features as Needle,
but are close enough to code that I've actually written to make it all
seem meaningful.

Let's take Jim's example[1], which is clear, rubified, and explicit
about DI constructs, and translate it into some concrete,
mundane ruby code without those constructs. Here's the original:

   def create_application
     container = DI::Container.new
     container.register(:logfilename) { "logfile.log" }
     container.register(:db_user) { "jim" }
     container.register(:db_password) { "secret" }
     container.register(:dbi_string) { "DBI:Pg:example_data" }

     container.register(:app) { |c|
       app = WebApp.new(c.quotes, c.authenticator, c.database)
       app.logger = c.logger
       app.set_error_handler c.error_handler
       app
     }

     container.register(:quotes) { |c|
       StockQuotes.new(c.error_handler, c.logger)
     }

     container.register(:authenticator) { |c|
       Authenticator.new(c.database, c.logger, c.error_handler)
     }

     container.register(:database) { |c|
       DBI.connect(c.dbi_string, c.db_user, c.db_password)
     }

     container.register(:logger) { |c| Logger.new(c.logfilename) }
     container.register(:error_handler) { |c|
       errh = ErrorHandler.new
       errh.logger = c.logger
       errh
     }
   end

And here's a rewrite that functions in about the same way, but without
being explicit about containers and services.

   class Application
     def logfilename
       @logfilename ||= "logfile.log"
     end

     def db_user
       @db_user ||= "jim"
     end

     def db_password
       @db_password ||= "secret"
     end

     def dbi_string
       @dbi_string ||= "DBI:Pg:example_data"
     end

     def app
       @app ||= WebApp.new(quotes, authenticator, database)
     end

     def quotes
       @quotes ||= StockQuotes.new(error_handler, logger)
     end

     def authenticator
       @authenticator ||=
         Authenticator.new(database, logger, error_handler)
     end

     def database
       @database ||= DBI.connect(dbi_string, db_user, db_password)
     end

     def logger
       @logger ||= Logger.new(logfilename)
     end

     def error_handler
       @errh ||= (
         ErrorHandler.new
         @errh.logger = logger
         @errh
       )
     end
   end

   def create_application
     Application.new
   end

So we're using the Application class itself as the container, and
we're using the instance methods of this class as the service points.
The methods return the services, and also store them in instance
variables. A service is registered using "def". Instead of using the
block parameter to pass the container to the service definitions, you
just use self. The familiar ||= idiom provides the singleton service
model.

It's quick and dirty, and it obscures the conceptual structure, but if
you're familiar with ruby, you can see immediately what is going on.
You've probably even written code a little like this. Why would you
want to "upgrade" your code to a more explicit form of DI? There are
several disadvantages to this implicit DI style, aside from the
implicitness itself:

- It doesn't help much with things like interceptors, although you
   could bring in your favorite AOP library.

- It mixes your service namespace with the namespace inherited from
   Object and Kernel: maybe you want a service called "dup" or "puts",
   but then you cannot call the Object and Kernel implementation of
   these methods from within methods of the Application class.

- Reflection must be done using standard ruby reflection on classes,
   so you have to, for example, filter out methods that are not really
   services.

OTOH, you can use class inheritance and module inclusion to build
trees of container definitions in a very natural and familiar way,
emulating some of the functionality of Needle:

   module LoggingServices
     def logger; ...; end
   end

   module GUIServices
   end

   module DatabaseServices
   end

   class MyServiceContainer
     include LoggingServices
     include GUIServices
     include DatabaseServices

     def app
       MyApp.new(logger, gui, database)
     end
   end

The other service models besides the singleton model are also easy to
implement with quick and dirty ruby code:

- Threaded:

   def per_thread_logger
     @per_thread_logger ||= {}
     @per_thread_logger[Thread.current] ||= Logger.new
   end

- Prototype:

   def gui_button
     MyButtonClass.new
   end

- Deferred (ok, this one gets a little messy, and the details should
   be abstracted away by some fancy metaprogramming):

   def big_resource
     @big_resource || big_resource_proxy
   end

   def big_resource_proxy
     @big_resource_proxy ||= (
       proxy = [proc {|br| @big_resource = br}]
       def proxy.method_missing(*args, &block)
         big_resource = BigResource.new
         at(0).call(big_resource)
         big_resource.send(*args, &block)
       end
       proxy
     )
   end
   private :big_resource_proxy

There are other service models that are very easy to construct with
methods, but I'm not aware of an equivalent construct in Needle:

   def printer(kind)
     @printers ||= {}
     @printers[kind] = Printer.new(kind)
   end

   def printer_for_code_files
     @printer_for_code_files ||= printer(:monochrome)
   end

   def printer_for_images
     @printer_for_images ||= printer(:color)
   end

It might be possible to do the above in Needle using Pipelines.[2]

Namespaces, if I understand the Needle docs correctly, work something
like this:

   class PictureApp
     class ColorNamespace
       def red; PrimaryColor(:red); end
       def green; PrimaryColor(:green); end
       def yellow; @yellow ||= red+green; end
     end

     def colors
       @colors ||= ColorNamespace.new
     end

     def picture
       @picture ||= Picture.new(:background => colors.yellow)
     end
   end

Alternately, if you want color instances to shared by all PictureApps,
you might want to define the colors service like this:

     def colors
       @@colors ||= ColorNamespace.new
     end

I hope there aren't too many inaccuracies in the above, and that this
helps other folks move from older ruby idioms to the new idioms
that Needle gives us.

--

[1] 
http://onestepback.org/index.cgi/Tech/Ruby/DependencyInjectionInRuby.rdoc

[2] Anybody know? Or are parameterized services a misuse of the DI
     pattern?