views:

43

answers:

2

I'm writing a Ruby class that extends TCPSocket. Assume it looks something like this:

class FooSocket < TCPSocket
    def hello
        puts 'hello'
    end
end

I have a TCPServer listening for incoming connections

server = TCPServer.new 1234
socket = server.accept

When my server finally accepts a connection, it will return a TCPSocket. However, I want a FooSocket so that I can call socket.hello.

How can I change TCPSocket into a FooSocket?

I could duck-punch the methods and attributes I want directly onto the TCPSocket class, but I'm using it elsewhere and so I don't want to do that.

Probably the easiest solution is to write a class that encapsulates a TCPSocket, and just pass the socket returned by accept as a param. However, I'm interested to know how to do it through inheritance—I've been trying to bend my mind around it but can't figure it out.

Thanks in advance.

A: 

You would need to override accept in the TCPServer class to return a FooSocket instead of a TCPSocket, either via reopening the class, or subclassing and using that. Your idea of dressing up an instance of TCPSocket after it's been returned by accept is cleaner I think.

x1a4
+1  A: 

I think that the easiest way to do that would be to make FooSocket a module, and then extend it into your TCPSockets that need the special methods. Here are some examples of how this could be used:

module FooSocket
  def hello
    self.puts 'hello' # could also be written without the 'self',
  end                 # but it is clearer this way because it may
end                   # be mistaken for the Kernel method.

server = TCPServer.new 1234
socket = server.accept.extend FooSocket

You could also easily override TCPServer to return one of these:

class TCPServer
  alias old_accept accept
  def accept
    old_accept.extend FooSocket
  end
end

If you didn't want to override standard classes, you could define a singleton class on your server (which is what I would do) because you will most likely only have one server. To do this, replace the line class TCPServer in the above example with class << server.

Adrian