mirror of
https://github.com/jtgans/g13gui.git
synced 2025-06-20 00:14:09 -04:00
observer: Finish migrating Subject
This commit is contained in:
parent
9a9f504995
commit
0a0ecfc9bc
@ -4,80 +4,7 @@ import unittest
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class ChangeType(Enum):
|
||||
ADD = 0
|
||||
REMOVE = 1
|
||||
MODIFY = 2
|
||||
|
||||
|
||||
class Subject(object):
|
||||
"""Simple class to handle the subject-side of the Observer pattern."""
|
||||
|
||||
AllKeys = ''
|
||||
|
||||
def registerObserver(self, observer, subscribedKeys=AllKeys):
|
||||
"""Registers an Observer class as an observer of this object"""
|
||||
if subscribedKeys != Subject.AllKeys:
|
||||
subscribedKeys = frozenset(subscribedKeys)
|
||||
if '_observers' not in self.__dict__:
|
||||
self._observers = {observer: subscribedKeys}
|
||||
else:
|
||||
self._observers[observer] = subscribedKeys
|
||||
|
||||
def removeObserver(self, observer):
|
||||
"""Removes an observer from this object"""
|
||||
if '_observers' in self.__dict__:
|
||||
if observer in self._observers:
|
||||
del self._observers[observer]
|
||||
|
||||
def addChange(self, type, key, data=None):
|
||||
"""Schedules a change notification for transmitting later.
|
||||
|
||||
type[ChangeType]: the type of change that occurred.
|
||||
key[string]: a required name for what field changed.
|
||||
data[object]: an optional context-dependent object, dict, or
|
||||
None, specifying what changed. In the case of an ADD or MODIFY,
|
||||
whatChanged should be the new data. In the case of a DELETE, it should
|
||||
be the old data (or None).
|
||||
"""
|
||||
if '_changes' not in self.__dict__:
|
||||
self._changes = [(type, key, data)]
|
||||
else:
|
||||
self._changes.append((type, key, data))
|
||||
|
||||
def clearChanges(self):
|
||||
"""Removes all scheduled changes from the change buffer."""
|
||||
self._changes = []
|
||||
|
||||
def notifyChange(self):
|
||||
raise NotImplementedError('Use Subject.notifyChanged instead')
|
||||
|
||||
def notifyChanged(self):
|
||||
"""Notifies all observers of scheduled changes in the change buffer.
|
||||
|
||||
This method actually does the work of iterating through all observers
|
||||
and all changes and delivering them to the Observer's onSubjectChanged
|
||||
method.
|
||||
|
||||
It is safe to call this if there are no changes to send in the buffer,
|
||||
or there are no observers to send changes to. Note that calling this
|
||||
when no observers are registered will still flush the change buffer.
|
||||
"""
|
||||
if '_observers' in self.__dict__ and '_changes' in self.__dict__:
|
||||
for observer, subscribedKeys in self._observers.items():
|
||||
for type, key, data in self._changes:
|
||||
if subscribedKeys == Subject.AllKeys or key in subscribedKeys:
|
||||
observer.onSubjectChanged(self, type, key, data)
|
||||
|
||||
self._changes = []
|
||||
|
||||
def setProperty(self, propertyName, value, notify=True):
|
||||
propertyName = '_' + propertyName
|
||||
self.__dict__[propertyName] = value
|
||||
self.addChange(ChangeType.MODIFY, propertyName, value)
|
||||
if notify:
|
||||
self.notifyChanged()
|
||||
from g13gui.observer.subject import Subject
|
||||
|
||||
|
||||
class Observer(object):
|
||||
@ -114,12 +41,8 @@ class Observer(object):
|
||||
should be the old data (or None).
|
||||
"""
|
||||
if '_changeTriggers' not in self.__dict__:
|
||||
raise NotImplementedError(
|
||||
'onSubjectChanged(%s, %s, %s, %s) fired with no '
|
||||
'listeners registered!' %
|
||||
(subject, changeType, key, data))
|
||||
return
|
||||
|
||||
found = False
|
||||
triggers = (
|
||||
self._changeTriggers.get((None, Subject.AllKeys)),
|
||||
self._changeTriggers.get((changeType, Subject.AllKeys)),
|
||||
@ -128,14 +51,8 @@ class Observer(object):
|
||||
|
||||
for trigger in triggers:
|
||||
if trigger:
|
||||
found = True
|
||||
trigger(subject, changeType, key, data)
|
||||
|
||||
if not found:
|
||||
raise NotImplementedError(
|
||||
'onSubjectChanged(%s, %s, %s, %s) fired without a listener!'
|
||||
% (subject, changeType, key, data))
|
||||
|
||||
|
||||
class ObserverTestCase(Observer, unittest.TestCase):
|
||||
def __init__(self, methodName):
|
||||
|
@ -1,17 +1,21 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
import observer
|
||||
|
||||
from builtins import property
|
||||
|
||||
from g13gui.observer.observer import Observer
|
||||
from g13gui.observer.observer import ObserverTestCase
|
||||
from g13gui.observer.subject import Subject
|
||||
from g13gui.observer.subject import ChangeType
|
||||
|
||||
class TestIncorrectObserver(observer.Observer):
|
||||
|
||||
class TestIncorrectObserver(Observer):
|
||||
def __hash__(self):
|
||||
return hash('TestIncorrectObserver')
|
||||
|
||||
|
||||
class TestSubject(observer.Subject):
|
||||
class TestSubject(Subject):
|
||||
def __init__(self):
|
||||
self._value = None
|
||||
|
||||
@ -24,7 +28,7 @@ class TestSubject(observer.Subject):
|
||||
self.setProperty('value', value)
|
||||
|
||||
|
||||
class ObserverTestCase(observer.ObserverTestCase):
|
||||
class ObserverTestCase(ObserverTestCase):
|
||||
def setUp(self):
|
||||
self.subject = TestSubject()
|
||||
|
||||
@ -42,7 +46,7 @@ class ObserverTestCase(observer.ObserverTestCase):
|
||||
|
||||
def testSubclassNotificationError(self):
|
||||
testObserver = TestIncorrectObserver()
|
||||
self.subject.addChange(observer.ChangeType.ADD, 'foo')
|
||||
self.subject.addChange(ChangeType.ADD, 'foo')
|
||||
self.subject.registerObserver(testObserver)
|
||||
|
||||
try:
|
||||
@ -55,25 +59,25 @@ class ObserverTestCase(observer.ObserverTestCase):
|
||||
def testSubclassNotification(self):
|
||||
self.subject.registerObserver(self)
|
||||
|
||||
self.subject.addChange(observer.ChangeType.ADD, 'foo', 'bar')
|
||||
self.subject.addChange(ChangeType.ADD, 'foo', 'bar')
|
||||
self.subject.notifyChanged()
|
||||
|
||||
self.assertChangeCount(1)
|
||||
self.assertChangeNotified(self.subject, observer.ChangeType.ADD, 'foo')
|
||||
self.assertChangeNotified(self.subject, ChangeType.ADD, 'foo')
|
||||
self.assertChangeDataEquals('bar')
|
||||
|
||||
def testSubscribedKeys(self):
|
||||
self.subject.registerObserver(self, {'a', 'b'})
|
||||
|
||||
self.subject.addChange(observer.ChangeType.ADD, 'a')
|
||||
self.subject.addChange(observer.ChangeType.ADD, 'b')
|
||||
self.subject.addChange(observer.ChangeType.ADD, 'c')
|
||||
self.subject.addChange(ChangeType.ADD, 'a')
|
||||
self.subject.addChange(ChangeType.ADD, 'b')
|
||||
self.subject.addChange(ChangeType.ADD, 'c')
|
||||
self.subject.notifyChanged()
|
||||
|
||||
self.assertChangeCount(2)
|
||||
self.assertChangeNotified(self.subject, observer.ChangeType.ADD, 'a')
|
||||
self.assertChangeNotified(self.subject, ChangeType.ADD, 'a')
|
||||
self.nextChange()
|
||||
self.assertChangeNotified(self.subject, observer.ChangeType.ADD, 'b')
|
||||
self.assertChangeNotified(self.subject, ChangeType.ADD, 'b')
|
||||
self.nextChange()
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user