Now that's cool
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!)