all: refactor hooks binding process
authorDmitry Selyutin <ghostmansd@gmail.com>
Tue, 13 Jun 2023 21:52:38 +0000 (00:52 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Tue, 13 Jun 2023 21:52:38 +0000 (00:52 +0300)
src/mdis/dispatcher.py
src/mdis/visitor.py
src/mdis/walker.py

index a40a1c14d2d6055bc7af8b1d07f956fd105deb64..be8e42e3e0f2ba1bdadb46853b95190982d3d27b 100644 (file)
@@ -1,37 +1,45 @@
+import inspect as _inspect
+import operator as _operator
+
 from . import core as _core
 
 
 class DispatcherMeta(type):
-    @classmethod
-    def dispatch(metacls, typeid=object):
-        module = typeid.__module__
-        qualname = typeid.__qualname__
-        if module == "builtins":
-            return qualname
-        return f"{module}.{qualname}".replace(".", "_")
-
     def __new__(metacls, name, bases, ns):
         hooks = {}
 
         for (key, value) in tuple(ns.items()):
-            if isinstance(value, _core.CallHook):
-                hook = ns.pop(key)
-                for typeid in hook.typeids:
-                    site = metacls.dispatch(typeid)
-                    hooks[typeid] = (hook, site)
-
-        for (typeid, (hook, site)) in tuple(hooks.items()):
+            if not isinstance(value, _core.CallHook):
+                continue
+            hook = ns.pop(key)
+            for typeid in hook.typeids:
+                if typeid in hooks:
+                    raise ValueError(f"conflicting hook: {typeid!r}")
+                hooks[typeid] = hook
+            site = hook.call.__name__
             ns[site] = hook
 
         return super().__new__(metacls, name, bases, ns)
 
+    def __init__(cls, name, bases, ns):
+        hooks = {}
+        for hook in map(_operator.itemgetter(1), _inspect.getmembers(cls,
+                predicate=lambda member: isinstance(member, _core.CallHook))):
+            for typeid in hook.typeids:
+                hooks[typeid] = hook
+        cls.__hooks = hooks
+        return super().__init__(name, bases, ns)
+
+    def dispatch(cls, typeid=object):
+        return cls.__hooks.get(typeid)
+
 
 class Dispatcher(metaclass=DispatcherMeta):
     def __call__(self, instance):
-        nil = object()
         for typeid in instance.__class__.__mro__:
-            site = self.__class__.dispatch(typeid)
-            call = getattr(self, site, nil)
-            if call is not nil:
-                return call(self, instance)
-        return getattr(self, self.__class__.dispatch())
+            hook = self.__class__.dispatch(typeid=typeid)
+            if hook is not None:
+                break
+        if hook is None:
+            hook = self.__class__.dispatch()
+        return hook(dispatcher=self, instance=instance)
index bbdc04249d315f776f06841711ecd2cdb5cf3920..2b2843344201c55242357e42603939a178dc3575 100644 (file)
@@ -5,9 +5,7 @@ from . import dispatcher as _dispatcher
 
 
 class VisitorMeta(_dispatcher.DispatcherMeta):
-    @classmethod
-    def dispatch(metacls, typeid):
-        return ("visit_" + super().dispatch(typeid))
+    pass
 
 
 class Visitor(_dispatcher.Dispatcher, metaclass=VisitorMeta):
index c60d71a47f3d1adf05a11c6d7eb7f68177c49a17..3adb93c5d3cbf2f71b3a3f090f1ede1dd8886e14 100644 (file)
@@ -3,9 +3,7 @@ from . import dispatcher as _dispatcher
 
 
 class WalkerMeta(_dispatcher.DispatcherMeta):
-    @classmethod
-    def dispatch(metacls, typeid):
-        return ("walk_" + super().dispatch(typeid))
+    pass
 
 
 class Walker(_dispatcher.Dispatcher, metaclass=WalkerMeta):