Hello list,
Two things:
I’ve got a question regarding inheritance and abstract base classes
that I’m hoping somebody can give me some help with. I’m trying to
make some socket-based stuff work based on the descriptions in the
pickaxe book which states that “BasicSocket is an abstract base class
for other socket classes”. It also says “IPSocket is a base class for
sockets using IP as their transport. TCPSocket and UDPSocket are based
on this class”. I’ve successfully implemented the class method on
IPSocket, but when I wanted to make TCPSocket.addr and
TCPSocket.peeraddr work (both methods should be inherited from
IPSocket), I had to write this functionality directly into my
TCPSocketOps class - if I put it into IPSocketOps the methods are not
found. Now I have to implement UDPSocket.addr and UDPSocket.peeraddr
and I don’t want to duplicate the logic in the methods (besides, then
it’s not really inheritance is it?).
To make my question clearer, I’ll paste the code below. The methods in
question are marked with TODO’s - they sit in the TCPSocketOps class
which is marked with RubyClass(“TCPSocket”) instead of inheriting the
methods from RubyClass(“IPSocket”) and I’m questioning whether there
is another way to do this or if that’s really correct. Thanks for your
time. Also, the exception I get when I move the methods to IPSocketOps
is:
System.MissingMethodException: undefined local variable or method
`addr’ for
#Ruby::BuiltIns::TCPSocket:0x0000058:Ruby.Builtins.RubyClass
at Ruby.Builtins.Kernel.MethodMissing(CodeContext context, Object
self, BlockParam block, SymbolId name, Object[] args) in
D:\Projects\IronRuby\trunk\src\IronRuby.Libraries\Builtins\Kernel.cs:line
227
using System;
using System.Collections.Generic;
using System.Text;
using Ruby.Runtime;
using System.Net.Sockets;
using Ruby.Builtins;
using Microsoft.Scripting;
using System.Net;
namespace Ruby.BuiltIns {
[RubyClass("IPSocket")]
public static class IPSocketOps {
[RubyMethod("getaddress", RubyMethodAttributes.PublicSingleton)]
public static string GetAddress(object self, MutableString
hostName) {
return
System.Net.Dns.GetHostEntry(hostName).AddressList[0].ToString();
}
}
[RubyClass("TCPSocket", Inherits = typeof(Object), Extends =
typeof(IPSocket))]
public static class TCPSocketOps {
[RubyMethod("gethostbyname",
RubyMethodAttributes.PublicSingleton)]
public static object GetHostByName(object self, MutableString
hostName) {
RubyArray result = ArrayOps.CreateArray();
System.Net.IPHostEntry hostEntry =
System.Net.Dns.GetHostEntry(hostName);
result.Add(hostName);
result.Add(ArrayOps.CreateArray(hostEntry.Aliases.Length));
foreach (string alias in hostEntry.Aliases)
{
((RubyArray)result[1]).Add(new MutableString(alias));
}
result.Add((int)hostEntry.AddressList[0].AddressFamily);
result.Add(new
MutableString(hostEntry.AddressList[0].ToString()));
return result;
}
[RubyMethod("new", RubyMethodAttributes.PublicSingleton)]
public static TCPSocket/*!*/ CreateSocket(CodeContext/*!*/
context, object self, BlockParam/!/ startRoutine, [NotNull]params
object[]/!/ args) {
return new TCPSocket(args[0], args[1]);
}
[RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
public static TCPSocket/*!*/
CreateSocketAlias_Open(CodeContext/!/ context, object self,
BlockParam/!/ startRoutine, [NotNull]params object[]/!/ args) {
return CreateSocket(context, self, startRoutine, args);
}
// TODO: This should move into IPSocketOps - How does
inheritance work in IronRuby?
[RubyMethod(“addr”, RubyMethodAttributes.PublicInstance)]
public static object GetAddress(IPSocket self) {
return GetAddressFromEndPoint(self.socket.LocalEndPoint);
}
// TODO: This should move into IPSocketOps - How does
inheritance work in IronRuby?
[RubyMethod(“peeraddr”, RubyMethodAttributes.PublicInstance)]
public static object GetPeerAddress(IPSocket self) {
return GetAddressFromEndPoint(self.socket.RemoteEndPoint);
}
public static object GetAddressFromEndPoint(EndPoint endPoint) {
RubyArray result = ArrayOps.CreateArray();
IPEndPoint ep = (IPEndPoint)endPoint;
MutableString addressFamily = null;
switch (ep.AddressFamily) {
// Surely this already exists somewhere in System.Net?
Couldn’t find it though…
case AddressFamily.InterNetwork:
addressFamily = new MutableString(“AF_INET”);
break;
default:
throw new NotImplementedException();
}
result.Add(addressFamily);
result.Add(ep.Port);
result.Add(new
MutableString(System.Net.Dns.GetHostEntry(ep.Address).HostName));
result.Add(new MutableString(ep.Address.ToString()));
return result;
}
}
public class IPSocket {
internal Socket socket;
}
public class TCPSocket : IPSocket {
public TCPSocket(object hostname, object port) {
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
int portNumber = 0;
if (port is int) {
portNumber = (int)port;
}
else if (port is MutableString) {
switch ((MutableString)port) {
case "ftp":
portNumber = 21;
break;
case "http":
portNumber = 80;
break;
default:
throw new NotImplementedException();
}
}
socket.Connect((MutableString)hostname, portNumber);
}
}
}