Add Enum and Eiffel examples using new-style classes.
diff --git a/Demo/newmetaclasses/Eiffel.py b/Demo/newmetaclasses/Eiffel.py
new file mode 100644
index 0000000..c9944fe
--- /dev/null
+++ b/Demo/newmetaclasses/Eiffel.py
@@ -0,0 +1,145 @@
+"""Support Eiffel-style preconditions and postconditions."""
+
+from new import function
+
+class EiffelBaseMetaClass(type):
+
+    def convert_methods(cls, dict):
+        """Replace functions in dict with EiffelMethod wrappers.
+
+        The dict is modified in place.
+
+        If a method ends in _pre or _post, it is removed from the dict
+        regardless of whether there is a corresponding method.
+        """
+        # find methods with pre or post conditions
+        methods = []
+        prenpost = []
+        for k, v in dict.iteritems():
+            if k.endswith('_pre') or k.endswith('_post'):
+                assert isinstance(v, function)
+                prenpost.append(k)
+            elif isinstance(v, function):
+                methods.append(k)
+        for m in methods:
+            pre = dict.get("%s_pre" % m)
+            post = dict.get("%s_post" % m)
+            if pre or post:
+                dict[k] = cls.make_eiffel_method(dict[m], pre, post)
+
+    convert_methods = classmethod(convert_methods)
+
+    def make_eiffel_method(func, pre, post):
+        def method(self, *args, **kwargs):
+            if pre:
+                pre(self, *args, **kwargs)
+            x = func(self, *args, **kwargs)
+            if post:
+                post(self, x, *args, **kwargs)
+            return x
+
+        if func.__doc__:
+            method.__doc__ = func.__doc__
+
+        return method
+    
+    make_eiffel_method = staticmethod(make_eiffel_method)
+
+class EiffelMetaClass1(EiffelBaseMetaClass):
+    # an implementation of the "eiffel" meta class that uses nested functions
+
+    def __new__(meta, name, bases, dict):
+        meta.convert_methods(dict)
+        return super(EiffelMetaClass1, meta).__new__(meta, name, bases, dict)
+
+class EiffelMethodWrapper:
+
+    def __init__(self, inst, descr):
+        self._inst = inst
+        self._descr = descr
+
+    def __call__(self, *args, **kwargs):
+        return self._descr.callmethod(self._inst, args, kwargs)
+        
+
+class EiffelDescriptor(object):
+
+    def __init__(self, func, pre, post):
+        self._func = func
+        self._pre = pre
+        self._post = post
+        
+        self.__name__ = func.__name__
+        self.__doc__ = func.__doc__
+
+    def __get__(self, obj, cls):
+        return EiffelMethodWrapper(obj, self)
+
+    def callmethod(self, inst, args, kwargs):
+        if self._pre:
+            self._pre(inst, *args, **kwargs)
+        x = self._func(inst, *args, **kwargs)
+        if self._post:
+            self._post(inst, x, *args, **kwargs)
+        return x
+
+class EiffelMetaClass2(EiffelMetaClass1):
+    # an implementation of the "eiffel" meta class that uses descriptors
+
+    make_eiffel_method = EiffelDescriptor
+
+def _test(metaclass):
+    class Eiffel:
+        __metaclass__ = metaclass
+
+    class Test(Eiffel):
+
+        def m(self, arg):
+            """Make it a little larger"""
+            return arg + 1
+
+        def m2(self, arg):
+            """Make it a little larger"""
+            return arg + 1
+
+        def m2_pre(self, arg):
+            assert arg > 0
+
+        def m2_post(self, result, arg):
+            assert result > arg
+
+    class Sub(Test):
+        def m2(self, arg):
+            return arg**2
+        def m2_post(self, Result, arg):
+            super(Sub, self).m2_post(Result, arg)
+            assert Result < 100
+
+    t = Test()
+    t.m(1)
+    t.m2(1)
+    try:
+        t.m2(0)
+    except AssertionError:
+        pass
+    else:
+        assert False
+
+    s = Sub()
+    try:
+        s.m2(1)
+    except AssertionError:
+        pass # result == arg
+    else:
+        assert False
+    try:
+        s.m2(10)
+    except AssertionError:
+        pass # result ==  100
+    else:
+        assert False
+
+if __name__ == "__main__":
+    _test(EiffelMetaClass1)
+    _test(EiffelMetaClass2)
+
diff --git a/Demo/newmetaclasses/Enum.py b/Demo/newmetaclasses/Enum.py
new file mode 100644
index 0000000..8a00b59
--- /dev/null
+++ b/Demo/newmetaclasses/Enum.py
@@ -0,0 +1,178 @@
+"""Enumeration metaclass."""
+
+class EnumMetaclass(type):
+    """Metaclass for enumeration.
+
+    To define your own enumeration, do something like
+
+    class Color(Enum):
+        red = 1
+        green = 2
+        blue = 3
+
+    Now, Color.red, Color.green and Color.blue behave totally
+    different: they are enumerated values, not integers.
+
+    Enumerations cannot be instantiated; however they can be
+    subclassed.
+    """
+
+    def __init__(cls, name, bases, dict):
+        super(EnumMetaclass, cls).__init__(name, bases, dict)
+        cls._members = []
+        for attr in dict.keys():
+            if not (attr.startswith('__') and attr.endswith('__')):
+                enumval = EnumInstance(name, attr, dict[attr])
+                setattr(cls, attr, enumval)
+                cls._members.append(attr)
+
+    def __getattr__(cls, name):
+        if name == "__members__":
+            return cls._members
+        raise AttributeError, name
+
+    def __repr__(cls):
+        s1 = s2 = ""
+        enumbases = [base.__name__ for base in cls.__bases__
+                     if isinstance(base, EnumMetaclass) and not base is Enum]
+        if enumbases:
+            s1 = "(%s)" % ", ".join(enumbases)
+        enumvalues = ["%s: %d" % (val, getattr(cls, val))
+                      for val in cls._members]
+        if enumvalues:
+            s2 = ": {%s}" % ", ".join(enumvalues)
+        return "%s%s%s" % (cls.__name__, s1, s2)
+
+class FullEnumMetaclass(EnumMetaclass):
+    """Metaclass for full enumerations.
+
+    A full enumeration displays all the values defined in base classes.
+    """
+
+    def __init__(cls, name, bases, dict):
+        super(FullEnumMetaclass, cls).__init__(name, bases, dict)
+        for obj in cls.__mro__:
+            if isinstance(obj, EnumMetaclass):
+                for attr in obj._members:
+                    # XXX inefficient
+                    if not attr in cls._members:
+                        cls._members.append(attr)
+
+class EnumInstance(int):
+    """Class to represent an enumeration value.
+
+    EnumInstance('Color', 'red', 12) prints as 'Color.red' and behaves
+    like the integer 12 when compared, but doesn't support arithmetic.
+
+    XXX Should it record the actual enumeration rather than just its
+    name?
+    """
+
+    def __new__(cls, classname, enumname, value):
+        return int.__new__(cls, value)
+
+    def __init__(self, classname, enumname, value):
+        self.__classname = classname
+        self.__enumname = enumname
+
+    def __repr__(self):
+        return "EnumInstance(%s, %s, %d)" % (self.__classname, self.__enumname,
+                                             self)
+
+    def __str__(self):
+        return "%s.%s" % (self.__classname, self.__enumname)
+
+class Enum:
+    __metaclass__ = EnumMetaclass
+
+class FullEnum:
+    __metaclass__ = FullEnumMetaclass
+
+def _test():
+
+    class Color(Enum):
+        red = 1
+        green = 2
+        blue = 3
+
+    print Color.red
+
+    print `Color.red`
+    print Color.red == Color.red
+    print Color.red == Color.blue
+    print Color.red == 1
+    print Color.red == 2
+
+    class ExtendedColor(Color):
+        white = 0
+        orange = 4
+        yellow = 5
+        purple = 6
+        black = 7
+
+    print ExtendedColor.orange
+    print ExtendedColor.red
+
+    print Color.red == ExtendedColor.red
+
+    class OtherColor(Enum):
+        white = 4
+        blue = 5
+
+    class MergedColor(Color, OtherColor):
+        pass
+
+    print MergedColor.red
+    print MergedColor.white
+
+    print Color
+    print ExtendedColor
+    print OtherColor
+    print MergedColor
+
+def _test2():
+
+    class Color(FullEnum):
+        red = 1
+        green = 2
+        blue = 3
+
+    print Color.red
+
+    print `Color.red`
+    print Color.red == Color.red
+    print Color.red == Color.blue
+    print Color.red == 1
+    print Color.red == 2
+
+    class ExtendedColor(Color):
+        white = 0
+        orange = 4
+        yellow = 5
+        purple = 6
+        black = 7
+
+    print ExtendedColor.orange
+    print ExtendedColor.red
+
+    print Color.red == ExtendedColor.red
+
+    class OtherColor(FullEnum):
+        white = 4
+        blue = 5
+
+    class MergedColor(Color, OtherColor):
+        pass
+
+    print MergedColor.red
+    print MergedColor.white
+
+    print Color
+    print ExtendedColor
+    print OtherColor
+    print MergedColor
+
+if __name__ == '__main__':
+    _test()
+    _test2()
+