From: Robert Klemme Date: 2011-04-06T00:23:55+09:00 Subject: Re: Seeking advice On Tue, Apr 5, 2011 at 4:44 PM, Johnny Morrice wrote: > On Tue, Apr 5, 2011 at 3:22 PM, Alex Rothbard wrote: >> A complete implementation of a transport requires that three classes >> (such as the 'Grid' class below) be implemented from their respective >> base class. > >> These transport classes are used by other classes within the >> library, and should never be used directly by the user. > > I interpreted this to mean that the base grid class would not be part > of the interface presented to the user either. Is this correct? > > On Tue, 5 Apr 2011 22:39:33 +0900 > Robert Klemme wrote: >> def initialize(transport) >>  @t = transport >>  @grid = @t.grid >>  @grid = @t.grid.new # alternative >> end > > Cus the way Robert saw it was that the transport should be the factory > for the grid, and the user will see the grid.  The transport, which is > the factory for the grid, is fed to the object. > > But the way I saw it was that the transport should be created by the > factory and so the user should see no grid at all.  The factory > feeds the transport to the object. We probably need more context. In an attempt to create a bigger example: $ ./TrueGrit.rb sending "basic message" across TheLibrary::JasonTransport closing TheLibrary::JasonTransport waiting for two weeks to transmit "basic message" via TheLibrary::CarrierPigeon TheLibrary::CarrierPigeon is flying home $ cat -n TrueGrit.rb 1 #!/bin/env ruby19 2 3 module TheLibrary 4 5 class BaseTransport 6 def self.open(*params) 7 grid = new(*params) 8 9 if block_given? 10 begin 11 yield grid 12 ensure 13 grid.close 14 end 15 else 16 grid 17 end 18 end 19 end 20 21 class JasonTransport < BaseTransport 22 def send(msg) 23 printf "sending %p across %p\n", msg, self.class 24 end 25 26 def close 27 printf "closing %p\n", self.class 28 end 29 end 30 31 class ThriftTransport < BaseTransport 32 def send(msg) 33 printf "sending %p across %p\n", msg, self.class 34 end 35 36 def close 37 printf "%p says, man I'm glad I get home\n", self.class 38 end 39 end 40 41 class CarrierPigeon < BaseTransport 42 def send(msg) 43 printf "waiting for two weeks to transmit %p via %p\n", msg, self.class 44 end 45 46 def close 47 printf "%p is flying home\n", self.class 48 end 49 end 50 51 end 52 53 include TheLibrary; 54 55 JasonTransport.open(:host => "foo.bar.com") do |grid| 56 grid.send("basic message") 57 end 58 59 CarrierPigeon.open(:destination => "Stockholm") do |grid| 60 grid.send("basic message") 61 end $ It really does not matter what method #new of the factory returns (or whether it's called "new" at all). Basically one needs a defined interface (note that I left some flexibility in there in order to be able to provide different configurations depending on transport used). Also, the approach with open is just an example how to do this in the same manner as File and IO and other classes work which use a block for safe resource deallocation. > Have I missed the point?  More importantly, have you made the code win? I'm not sure what "win" means in this context... Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/