Rework of Oracle
rmorshea opened this issue · comments
Ryan Morshead commented
Proposed rework of the Oracle
model type that was recently removed due to bugs:
import functools
from spectate import mvc
class MetaOracle(type):
def __init__(self, name, bases, attrs):
if "_model_capture_types" in attrs:
class_to_key = functools.cmp_to_key(lambda t1, t2: -1 if issubclass(t1, t2) else 1)
class_key_from_item = lambda i: class_to_key(i[1])
self._model_capture_order = tuple(sorted(self._model_capture_types.items(), key=class_key_from_item))
class Oracle(mvc.Object, metaclass=MetaOracle):
_model_capture_types = {
"_capture_dict": mvc.Dict,
"_capture_object": mvc.Object,
"_capture_list": mvc.List,
}
def _capture_model_events(self, model, path=()):
mvc.view(model)(lambda *args, **kwargs: self._capture(path=path, *args, **kwargs))
def _capture(self, value, events, path):
for method, model_type in self._model_capture_order:
if isinstance(value, model_type):
super()._notify_model_views(tuple(
getattr(self, method)(value, e, path)
for e in events
))
break
else:
raise TypeError("Oracle has no capture type %r" % value)
def _capture_object(self, value, event, path):
path += (event.attr,)
if isinstance(event.new, mvc.Model):
self._capture_model_events(event.new, path)
return event["path": path]
def _capture_dict(self, value, event, path):
path += (event.key,)
if isinstance(event.new, mvc.Model):
self._capture_model_events(event.new, path)
return event["path": path]
def _capture_list(self, value, event, path):
path += (event.index,)
if isinstance(event.new, mvc.Model):
self._capture_model_events(event.new, path)
return event["path": path]
def _capture_set(self, value, event, path):
# We don't need to capture the contents of a set because
# anything stored in it must be hashable and thus not mutable
return event["path": path]
def _notify_model_views(self, events):
self._capture(self, events, path=())
Ryan Morshead commented
closed by #33