This post originated from an RSS feed registered with Ruby Buzz
by Jamis Buck.
Original Post: Now that’s cool…
Feed Title: the buckblogs here
Feed URL: http://weblog.jamisbuck.org/blog.cgi/programming/index.rss
Feed Description: Jamis Buck's corner of the blogging universe. Mostly about ruby, but includes ramblings on a variety of topics.
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!)