]> git.parisson.com Git - timeside.git/commitdiff
add new core:
authorOlivier Guilyardi <olivier@samalyse.com>
Thu, 26 Nov 2009 19:48:05 +0000 (19:48 +0000)
committerOlivier Guilyardi <olivier@samalyse.com>
Thu, 26 Nov 2009 19:48:05 +0000 (19:48 +0000)
- less intrusive component/interface mechanism
- no need for a component manager
- one can create several instances of a component (no singleton)
- component constructors do not need component manager anymore
- unit test included

newcore.py [new file with mode: 0644]
tests/testnewcore.py [new file with mode: 0644]

diff --git a/newcore.py b/newcore.py
new file mode 100644 (file)
index 0000000..6797923
--- /dev/null
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2009 Olivier Guilyardi <olivier@samalyse.com>
+#
+# This file is part of TimeSide.
+
+# TimeSide is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+
+# TimeSide is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+
+
+# This file defines an object interface mechanism and a way to determine
+# which components implements a given interface
+#
+# For example, the following defines the Music class as implementing the
+# listenable interface.
+#
+# class Listenable(Interface):
+#     pass
+#
+# class Music(Component):
+#    implements(Listenable)
+#
+# Several class can implements a such interface, and it is possible to 
+# discover which class implements it with implementations():
+#
+# list_of_classes = implementations(Listenable)
+#
+# This mechanism support inheritance of both interfaces and components:
+#
+# - all descendants of a class implementing a given interface are also considered
+#   to implement this interface
+# - a class implementing a given interface is also considered to implement all
+#   the ascendants of this interface
+
+__all__ = ['Component', 'implements', 'Interface', 'implementations']
+
+class Interface(object):
+    """Marker base class for interfaces."""
+
+def implements(*interfaces):
+    _implements.extend(interfaces)
+
+def implementations(interface):
+    result = []
+    find_implementations(interface, result)
+    return result
+
+_implementations = []
+_implements = []
+
+class ComponentMeta(type):
+
+    def __new__(cls, name, bases, d):
+        new_class = type.__new__(cls, name, bases, d)
+        if _implements:
+            for i in _implements:
+                _implementations.append((i, new_class))
+        del _implements[:]
+        return new_class
+
+class Component(object):
+    __metaclass__ = ComponentMeta 
+
+def extend_unique(list1, list2):
+    for item in list2:
+        if item not in list1:
+            list1.append(item)
+
+def find_implementations(interface, result):
+    for i, cls in _implementations:
+        if (i == interface):
+            extend_unique(result, [cls])
+            extend_unique(result, cls.__subclasses__())
+
+    subinterfaces = interface.__subclasses__()
+    if subinterfaces:
+        for i in subinterfaces:
+            find_implementations(i, result)
+
diff --git a/tests/testnewcore.py b/tests/testnewcore.py
new file mode 100644 (file)
index 0000000..ccbf003
--- /dev/null
@@ -0,0 +1,86 @@
+
+from timeside.newcore import *
+from sys import stdout
+
+class I1(Interface):
+    pass
+
+class I2(Interface):
+    pass
+
+class I3(Interface):
+    pass
+
+class I4(Interface):
+    pass
+
+class I5(Interface):
+    pass
+
+class I6(I5):
+    pass
+
+class I7(Interface):
+    pass
+
+class I8(Interface):
+    pass
+
+class C1(Component):
+    implements(I1)
+
+class C2(Component):
+    implements(I2, I3)
+
+class C3(Component):
+    implements(I4)
+
+class C4(Component):
+    implements(I4)
+
+class C5(Component):
+    implements(I6)
+
+class C6(Component):
+    implements(I7)
+
+class C7(C6):
+    pass
+
+class C8(Component):
+    implements(I8)
+
+class C9(C8):
+    implements(I8)
+
+def list_equals(list1, list2):
+    if len(list1) != len(list2):
+        return False
+
+    for item in list1:
+        if not item in list2:
+            return False
+
+    for item in list2:
+        if not item in list1:
+            return False
+
+    return True            
+
+def test(desc, actual, expected):
+    stdout.write(desc + ": ")
+    if list_equals(actual, expected):
+        stdout.write("OK\n")
+    else:
+        stdout.write("FAILED\n")
+        stdout.write("actual:   " + str(actual) + "\n")
+        stdout.write("expected: " + str(expected) + "\n")
+    
+
+test("Test a component implementing one interface", implementations(I1), [C1])
+test("Test a component implementing two interfaces (1/2)", implementations(I2), [C2])
+test("Test a component implementing two interfaces (2/2)", implementations(I3), [C2])
+test("Test an interface implemented by two components", implementations(I4), [C3, C4])
+test("Test whether a component implements an interface's parent", implementations(I5), [C5])
+test("Test whether a child component implements the interface implemented by its parent", implementations(I7), [C6, C7])
+test("Test implementation redundancy across descendants", implementations(I8), [C8, C9])