Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Seeking advice

Reply
Thread Tools

Seeking advice

 
 
Alex Rothbard
Guest
Posts: n/a
 
      04-05-2011
Hi. I am writing a library that will have the ability to access a server
by many different "transports" (JSON over HTTP, Thrift, etc). Depending
on which transport the user chooses, different files and classes will
need to be loaded.

A complete implementation of a transport requires that three classes
(such as the 'Grid' class below) be implemented from their respective
base class. Additionally, if the user wants to use JSON over HTTP, they
shouldn't need to depend on the thrift gem and vice versa. These
transport classes are used by other classes within the library, and
should never be used directly by the user.

What is the best way to allow the user of the library to specify a
transport at runtime? Could I wrap all my implemented transport classes
in a module and do something like this?:

def initialize(transport)
@t = transport
@grid = @t::Grid.new
end

where "transport" could be "MyProject::Transport::Thrift".

Is this a good idea? Is there a better way?

--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      04-05-2011
On Tue, Apr 5, 2011 at 3:22 PM, Alex Rothbard <(E-Mail Removed)> wrote:
> Hi. I am writing a library that will have the ability to access a server
> by many different "transports" (JSON over HTTP, Thrift, etc). Depending
> on which transport the user chooses, different files and classes will
> need to be loaded.
>
> A complete implementation of a transport requires that three classes
> (such as the 'Grid' class below) be implemented from their respective
> base class. Additionally, if the user wants to use JSON over HTTP, they
> shouldn't need to depend on the thrift gem and vice versa. These
> transport classes are used by other classes within the library, and
> should never be used directly by the user.
>
> What is the best way to allow the user of the library to specify a
> transport at runtime? Could I wrap all my implemented transport classes
> in a module and do something like this?:
>
> def initialize(transport)
> =A0@t =3D transport
> =A0@grid =3D @t::Grid.new
> end
>
> where "transport" could be "MyProject::Transport::Thrift".
>
> Is this a good idea? Is there a better way?


I'd go for factory pattern.

def initialize(transport)
@t =3D transport
@grid =3D @t.grid
@grid =3D @t.grid.new # alternative
end

All transports must implement the particular set of methods of course.

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

 
Reply With Quote
 
 
 
 
Johnny Morrice
Guest
Posts: n/a
 
      04-05-2011
On Tue, 5 Apr 2011 22:22:17 +0900
Alex Rothbard <(E-Mail Removed)> wrote:

> What is the best way to allow the user of the library to specify a
> transport at runtime?


Use factory pattern

The user should call something like

MyProject::Transport::ThriftFactory.build

Then they don't need to find the transport themselves.
But it should be obvious what ThriftFactory returns.

The following might be how you would do it, up to you really

# I don't know what this is about, so I'm calling your class Foo here
class Foo

# My Foo transports all the data to the yard
def initialize(transport)
@t = transport
@grid = @t::Grid.new
end

end

# Factory to build the Foo which uses the Thrift Transporter
class ThriftFactory

# Users can make Foos that transport with Thrift without having to
# find the Thrift themselves
def build
Foo.new MyProject::Transport::Thrift
end

end



 
Reply With Quote
 
Johnny Morrice
Guest
Posts: n/a
 
      04-05-2011
On Tue, Apr 5, 2011 at 3:22 PM, Alex Rothbard <(E-Mail Removed)> 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 <(E-Mail Removed)> 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.

Have I missed the point? More importantly, have you made the code win?

Cheers
Johnny

 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      04-05-2011
On Tue, Apr 5, 2011 at 4:44 PM, Johnny Morrice <(E-Mail Removed)> wrot=
e:
> On Tue, Apr 5, 2011 at 3:22 PM, Alex Rothbard <(E-Mail Removed)> 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 <(E-Mail Removed)> wrote:
>> def initialize(transport)
>> =A0@t =3D transport
>> =A0@grid =3D @t.grid
>> =A0@grid =3D @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. =A0The 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. =A0The 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::CarrierPi=
geon
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 =3D 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 =3D> "foo.bar.com") do |grid|
56 grid.send("basic message")
57 end
58
59 CarrierPigeon.open(:destination =3D> "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? =A0More importantly, have you made the code win?


I'm not sure what "win" means in this context...

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

 
Reply With Quote
 
Alex Rothbard
Guest
Posts: n/a
 
      04-05-2011
The factory design pattern is sort of what I want, but not exactly.
Remember that there are three different classes (services) that need to
take advantage of a transport. The library is broken down like this:

There is a high level class that represents a user's overall account.
The user uses this class only. This account class needs to access three
different "services" (classes): the grid, the archive, and the
transaction service. All three services need to communicate with the
remote server using a transport.

In the example above, the transport is providing methods for accessing
the grid, but I am thinking of it in another way: the
grid/archive/transaction classes should provide methods which correspond
to the API on the remote server, and those classes then use the selected
transport to send it across.

In short, I have a server library which offers up three sets of APIs
(one for each service), and I want to be able to allow the end user to
easily choose which transport the client library uses when accessing
these services.

--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Jesús Gabriel y Galán
Guest
Posts: n/a
 
      04-06-2011
On Tue, Apr 5, 2011 at 8:30 PM, Alex Rothbard <(E-Mail Removed)> wrote:
> The factory design pattern is sort of what I want, but not exactly.
> Remember that there are three different classes (services) that need to
> take advantage of a transport. The library is broken down like this:
>
> There is a high level class that represents a user's overall account.
> The user uses this class only. This account class needs to access three
> different "services" (classes): the grid, the archive, and the
> transaction service. All three services need to communicate with the
> remote server using a transport.
>
> In the example above, the transport is providing methods for accessing
> the grid, but I am thinking of it in another way: the
> grid/archive/transaction classes should provide methods which correspond
> to the API on the remote server, and those classes then use the selected
> transport to send it across.
>
> In short, I have a server library which offers up three sets of APIs
> (one for each service), and I want to be able to allow the end user to
> easily choose which transport the client library uses when accessing
> these services.


Then something like:

class Grid
TRANSPORTS = {:json => JsonTransport, :thrift => ThriftTransport}

def initialize transport, params
@transport = TRANSPORTS[transport]
# ... initialize the transport with params if required or whatever
end

def method_xxx param1, param2
@transport.call_remote_method(xx, param1, param2) # the
transport defines how to call remote methods, I guess
end
end

grid = Grid.new :json, {:url => "http://my.json.service"}
grid.method_xxx ("a", "b")

If you don't want the client to know about transport params, you can
hide the configuration inside the Grid class, or read it from a file
or something.

Jesus.

 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      04-06-2011
On Tue, Apr 5, 2011 at 8:30 PM, Alex Rothbard <(E-Mail Removed)> wrote:
> The factory design pattern is sort of what I want, but not exactly.
> Remember that there are three different classes (services) that need to
> take advantage of a transport. The library is broken down like this:


I'm not convinced we are actually that far away from what you want.

> There is a high level class that represents a user's overall account.
> The user uses this class only. This account class needs to access three
> different "services" (classes): the grid, the archive, and the
> transaction service. All three services need to communicate with the
> remote server using a transport.


Do all three services need their own implementation of each transport
(i.e. thrift for grid, thrift for archive, thrift for TX) or do you
only need / want a single transport implementation per service?

> In the example above, the transport is providing methods for accessing
> the grid, but I am thinking of it in another way: the


Well, that's just a name. You can replace it by "connection".

> grid/archive/transaction classes should provide methods which correspond
> to the API on the remote server, and those classes then use the selected
> transport to send it across.
>
> In short, I have a server library which offers up three sets of APIs
> (one for each service), and I want to be able to allow the end user to
> easily choose which transport the client library uses when accessing
> these services.


It would be important to know when the user must decide about the
transport. Do you want to have him do it initially when he opens his
account? Do you want to allow for later changes of the transport? Or
do you even want to use a different transport per interaction? Also,
how do you want your transports to work: should they be connection
oriented or message oriented? This will determine whether you need
something like a connection object you must store somewhere.

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Seeking advice - should I use server.transfer after a custom event fires? bill ASP .Net 3 04-13-2006 02:25 PM
Seeking advice on Aironet 1232 config for visitor and staff access Ned Cisco 3 09-25-2005 07:21 PM
Seeking wireless LAN advice Ray Wireless Networking 8 08-11-2004 09:42 PM
Seeking advice on what to buy for Win98/XP home network... Sunny Side Wireless Networking 7 07-31-2004 01:47 AM
Seeking advice from employed MCSDs Rana Ian MCSD 5 10-04-2003 08:53 AM



Advertisments