@@ 0,0 1,14 @@
+_METHS = {}
+
+from gf import dispatch as mm
+
+def method(*types):
+ "a method decorator on top of David Mertz's GF package"
+ def _wrap(meth):
+ name = meth.__name__
+ gf = _METHS.get(name)
+ if gf is None:
+ gf = _METHS[name] = mm.GF()
+ gf.add_rule(types, meth)
+ return gf
+ return _wrap
@@ 0,0 1,51 @@
+def proximity(klass, mro):
+ return mro.index(klass)
+
+def lexicographic_mro(signature, matches):
+ "Use dispatch ranking similar to CLOS"
+ # Schwartzian transform to weight match sigs, left-to-right"
+ mros = [klass.mro() for klass in signature]
+ for (sig,func,nm),i in zip(matches,xrange(1000)):
+ matches[i] = (map(proximity, sig, mros), matches[i])
+ matches.sort()
+ return map(lambda t:t[1], matches)
+
+#-- GF class
+class GF(object):
+ def __init__(self, table=(), order=lexicographic_mro):
+ self.table = []
+ for rule in table:
+ self.add_rule(*rule)
+ self.order = order
+
+ def __call__(self, *args):
+ signature = [o.__class__ for o in args]
+ linearization = self.linearize_table(signature)
+ return linearization[0][0](*args)
+
+ def add_rule(self, signature, func):
+ self.table.append((signature, func, 0))
+
+ def next_method(self):
+ func, _ = self.linearization[self.pos]
+ self.pos +=1
+ result = func(*self.args)
+ self.pos -= 1
+ return result
+
+ def linearize_table(self, sig):
+ from operator import mul
+ len_match = lambda (s,f,nm): len(s) == len(sig)
+ typ_match = lambda (s,f,nm): reduce(mul, map(issubclass, sig, s))
+ all_match = lambda x: len_match(x) and typ_match(x)
+ table = filter(all_match, self.table)
+ if not table:
+ def nomatch(*a):
+ raise TypeError, \
+ "%s instance: no defined call signature <%s> for args (%s)" % \
+ (self.__class__.__name__,
+ ",".join([str(o) for o in sig]),
+ a)
+ return [(nomatch,0)]
+ return map(lambda l:l[1:], self.order(sig, table))
+
@@ 0,0 1,21 @@
+import unittest
+from gf import method
+from gf.dispatch import GF
+
+class TestGF(unittest.TestCase):
+
+ def test_method(self):
+ @method(int, int)
+ def foo(a, b):
+ return a+b
+ @method(str, str)
+ def foo(a, b):
+ return a+b
+
+ self.assertEquals(foo(1, 2), 3)
+ self.assertEquals(foo('a', 'b'), 'ab')
+ self.assertRaises(TypeError, foo, 1, 'b')
+
+if __name__ == '__main__':
+ unittest.main()
+