Now that's cool

Posted by Jamis on November 13, 2004 @ 04:44 AM

Christian Neukirchen asked me a question this morning on IRC. He wanted to know if there was a way to pass parameters to a service’s constructor (in Needle) at the moment the service was requested. This is particularly useful for prototype services, where each request of the service returns a new instance—often, you will want to pass some context-specific data to the constructor of that service.

The short answer is “no”, you can’t really do specifically that in Needle. When I’ve needed something like that, I’ve usually split the constructor in two—creating an “injectible” constructor, and a separate #init method that must be invoked manually after obtaining the service handle in order to pass in the context-specific stuff:

  class Foo
    def initialize( bar )
      @bar = bar
    end

    def init( baz )
      @baz = baz
      do_initialization
      ...
      self
    end
  end

  registry.define.foo( :model => :prototype ) { |c,| Foo.new( c[:bar] ) }

  foo1 = registry.foo.init( "hello" )
  foo2 = registry.foo.init( "world" )

It works, but it is clunky.

This morning, I found a better way, thanks to the power of Ruby’s closures. Ladies and gentlemen, consider the following:

  class Foo
    def initialize( bar, baz )
      @bar = bar
      @baz = baz
      do_initialization
      ...
    end
  end

  registry.define.foo( :model => :prototype ) do |c,|
    lambda { |baz| Foo.new( c[:bar], baz ) }
  end

  foo1 = registry.foo.call( "hello" )
  foo2 = registry.foo.call( "world" )

I love closures! True, the invocation to #call is still a bit clunky, but there’s not really a way to get around it. Besides, if you think about it, what you’ve done is turned the foo service (above) into a factory, which accepts parameters and returns object instances tailored according to those parameters.

I’ve already reworked portions of the Net::SSH rewrite to take advantage of this approach—it’s really slick.

(Oh, and speaking of Net::SSH…connections and channels work! You can now execute processes remotely and respond to events. Remaining to finish: the port forwarding manager, the process manager, and the SFTP subsystem. Whew!)

Posted in Tips & Tricks

Be the first to leave a comment on this article. Tell us your thoughts using the form below!

: (leave url/email »)
: