Adding a bit
[apertium.git] / apertium-tools / apertium-tolk / simplegeneric.py
blob6a67aed88507598c715e9a830a8736c508b18404
1 __all__ = ["generic"]
3 from types import ClassType, InstanceType
4 classtypes = type, ClassType
6 def generic(func):
7 """Create a simple generic function"""
9 _sentinel = object()
11 def _by_class(*args, **kw):
12 cls = args[0].__class__
13 for t in type(cls.__name__, (cls,object), {}).__mro__:
14 f = _gbt(t, _sentinel)
15 if f is not _sentinel:
16 return f(*args, **kw)
17 else:
18 return func(*args, **kw)
20 _by_type = {object: func, InstanceType: _by_class}
21 _gbt = _by_type.get
23 def when_type(t):
24 """Decorator to add a method that will be called for type `t`"""
25 if not isinstance(t, classtypes):
26 raise TypeError(
27 "%r is not a type or class" % (t,)
29 def decorate(f):
30 if _by_type.setdefault(t,f) is not f:
31 raise TypeError(
32 "%r already has method for type %r" % (func, t)
34 return f
35 return decorate
42 _by_object = {}
43 _gbo = _by_object.get
45 def when_object(o):
46 """Decorator to add a method that will be called for object `o`"""
47 def decorate(f):
48 if _by_object.setdefault(id(o), (o,f))[1] is not f:
49 raise TypeError(
50 "%r already has method for object %r" % (func, o)
52 return f
53 return decorate
56 def dispatch(*args, **kw):
57 f = _gbo(id(args[0]), _sentinel)
58 if f is _sentinel:
59 for t in type(args[0]).__mro__:
60 f = _gbt(t, _sentinel)
61 if f is not _sentinel:
62 return f(*args, **kw)
63 else:
64 return func(*args, **kw)
65 else:
66 return f[1](*args, **kw)
68 dispatch.__name__ = func.__name__
69 dispatch.__dict__ = func.__dict__.copy()
70 dispatch.__doc__ = func.__doc__
71 dispatch.__module__ = func.__module__
73 dispatch.when_type = when_type
74 dispatch.when_object = when_object
75 dispatch.default = func
76 dispatch.has_object = lambda o: id(o) in _by_object
77 dispatch.has_type = lambda t: t in _by_type
78 return dispatch
83 def test_suite():
84 import doctest
85 return doctest.DocFileSuite(
86 'README.txt',
87 optionflags=doctest.ELLIPSIS|doctest.REPORT_ONLY_FIRST_FAILURE,