[Ironruby-core] Inheritance question

Peter Bacon Darwin bacondarwin at googlemail.com
Thu Dec 20 11:30:35 EST 2007


I think you are getting too carried away with the various conventions around
extending .NET types for use by the DLR.
If you are simply wanting to wrap the underlying System.Net.Sockets.Socket
class (rather than extend it) then you don't need to have both IPSocket and
IPSocketOps classes and so on.  It is enough to have an abstract non-static
class IPSocket and a concrete class TCPSocket, which derives directly from
IPSocket.  Everything then works.  See the code below.

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 abstract class IPSocket {
        internal Socket socket;

        [RubyMethod("getaddress", RubyMethodAttributes.PublicSingleton)]
        public static string GetAddress(object self, MutableString hostName)
{
            return
System.Net.Dns.GetHostEntry(hostName).AddressList[0].ToString();
        }

 
       [RubyMethod("addr", RubyMethodAttributes.PublicInstance)]
        public static object GetAddress(IPSocket self) {
            return GetAddressFromEndPoint(self.socket.LocalEndPoint);
        }

 
       [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;
        }
    }

    [RubyClass("TCPSocket")]
    public class TCPSocket : IPSocket {

        [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);
        }

        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);
        }
    }
}



More information about the Ironruby-core mailing list