From: Jamis Buck Date: 2004-11-14T07:55:05+09:00 Subject: Re: [ANN] Copland to Needle article on RubyGarden (LONG) Joel VanderWerf wrote: > 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. Yay! :) > > 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. Excellent approach, Joel. You've hit the nail right on the head. DI is nothing new--most of us have been doing something at least similar to it for a long time. It's like any of the design patterns--it's not that they are new, so much as they've been given a name so that they can be communicated better. As far as the DI frameworks are concerned (like Needle and Copland), they don't let you do anything you couldn't before. They just make it so that you don't have to reimplement a DI framework yourself for every project you create. Plus, they are tested and stable, so you can focus on your application logic instead of your own custom DI infrastructure. > 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] Hmm. I wouldn't call this a service model so much as a factory service. In fact, I have a new favorite way of doing this kind of thing, as of this morning. To complicate things a bit, suppose that the Printer class needs to be dependency injected (with a logger instance, for example), and the following approach really shines: reg.define do |b| b.printer do |ctr,info| logger = ctr[:logs].get( info ) lambda { |kind| Printer.new( logger, kind ) } end b.code_printer { |ctr,| ctr.printer.call( :monochrome ) } b.image_printer { |ctr,| ctr.printer.call( :color ) } end I've actually incorporated this approach into various places in the upcoming new release of Net::SSH, and it works beautifully. > 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. Excellent write-up, Joel. You ought to publish this somewhere on a website...although the fact that you posted it _here_ means it will be archived in the ruby-talk archives, which is probably good enough. Thanks! - Jamis -- Jamis Buck jgb3@email.byu.edu http://www.jamisbuck.org/jamis