mirror of
https://github.com/jtgans/g13gui.git
synced 2025-06-20 08:23:50 -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
|
from enum import Enum
|
||||||
|
|
||||||
|
from g13gui.observer.subject import Subject
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
class Observer(object):
|
class Observer(object):
|
||||||
@ -114,12 +41,8 @@ class Observer(object):
|
|||||||
should be the old data (or None).
|
should be the old data (or None).
|
||||||
"""
|
"""
|
||||||
if '_changeTriggers' not in self.__dict__:
|
if '_changeTriggers' not in self.__dict__:
|
||||||
raise NotImplementedError(
|
return
|
||||||
'onSubjectChanged(%s, %s, %s, %s) fired with no '
|
|
||||||
'listeners registered!' %
|
|
||||||
(subject, changeType, key, data))
|
|
||||||
|
|
||||||
found = False
|
|
||||||
triggers = (
|
triggers = (
|
||||||
self._changeTriggers.get((None, Subject.AllKeys)),
|
self._changeTriggers.get((None, Subject.AllKeys)),
|
||||||
self._changeTriggers.get((changeType, Subject.AllKeys)),
|
self._changeTriggers.get((changeType, Subject.AllKeys)),
|
||||||
@ -128,14 +51,8 @@ class Observer(object):
|
|||||||
|
|
||||||
for trigger in triggers:
|
for trigger in triggers:
|
||||||
if trigger:
|
if trigger:
|
||||||
found = True
|
|
||||||
trigger(subject, changeType, key, data)
|
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):
|
class ObserverTestCase(Observer, unittest.TestCase):
|
||||||
def __init__(self, methodName):
|
def __init__(self, methodName):
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import observer
|
|
||||||
|
|
||||||
from builtins import property
|
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):
|
def __hash__(self):
|
||||||
return hash('TestIncorrectObserver')
|
return hash('TestIncorrectObserver')
|
||||||
|
|
||||||
|
|
||||||
class TestSubject(observer.Subject):
|
class TestSubject(Subject):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._value = None
|
self._value = None
|
||||||
|
|
||||||
@ -24,7 +28,7 @@ class TestSubject(observer.Subject):
|
|||||||
self.setProperty('value', value)
|
self.setProperty('value', value)
|
||||||
|
|
||||||
|
|
||||||
class ObserverTestCase(observer.ObserverTestCase):
|
class ObserverTestCase(ObserverTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.subject = TestSubject()
|
self.subject = TestSubject()
|
||||||
|
|
||||||
@ -42,7 +46,7 @@ class ObserverTestCase(observer.ObserverTestCase):
|
|||||||
|
|
||||||
def testSubclassNotificationError(self):
|
def testSubclassNotificationError(self):
|
||||||
testObserver = TestIncorrectObserver()
|
testObserver = TestIncorrectObserver()
|
||||||
self.subject.addChange(observer.ChangeType.ADD, 'foo')
|
self.subject.addChange(ChangeType.ADD, 'foo')
|
||||||
self.subject.registerObserver(testObserver)
|
self.subject.registerObserver(testObserver)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -55,25 +59,25 @@ class ObserverTestCase(observer.ObserverTestCase):
|
|||||||
def testSubclassNotification(self):
|
def testSubclassNotification(self):
|
||||||
self.subject.registerObserver(self)
|
self.subject.registerObserver(self)
|
||||||
|
|
||||||
self.subject.addChange(observer.ChangeType.ADD, 'foo', 'bar')
|
self.subject.addChange(ChangeType.ADD, 'foo', 'bar')
|
||||||
self.subject.notifyChanged()
|
self.subject.notifyChanged()
|
||||||
|
|
||||||
self.assertChangeCount(1)
|
self.assertChangeCount(1)
|
||||||
self.assertChangeNotified(self.subject, observer.ChangeType.ADD, 'foo')
|
self.assertChangeNotified(self.subject, ChangeType.ADD, 'foo')
|
||||||
self.assertChangeDataEquals('bar')
|
self.assertChangeDataEquals('bar')
|
||||||
|
|
||||||
def testSubscribedKeys(self):
|
def testSubscribedKeys(self):
|
||||||
self.subject.registerObserver(self, {'a', 'b'})
|
self.subject.registerObserver(self, {'a', 'b'})
|
||||||
|
|
||||||
self.subject.addChange(observer.ChangeType.ADD, 'a')
|
self.subject.addChange(ChangeType.ADD, 'a')
|
||||||
self.subject.addChange(observer.ChangeType.ADD, 'b')
|
self.subject.addChange(ChangeType.ADD, 'b')
|
||||||
self.subject.addChange(observer.ChangeType.ADD, 'c')
|
self.subject.addChange(ChangeType.ADD, 'c')
|
||||||
self.subject.notifyChanged()
|
self.subject.notifyChanged()
|
||||||
|
|
||||||
self.assertChangeCount(2)
|
self.assertChangeCount(2)
|
||||||
self.assertChangeNotified(self.subject, observer.ChangeType.ADD, 'a')
|
self.assertChangeNotified(self.subject, ChangeType.ADD, 'a')
|
||||||
self.nextChange()
|
self.nextChange()
|
||||||
self.assertChangeNotified(self.subject, observer.ChangeType.ADD, 'b')
|
self.assertChangeNotified(self.subject, ChangeType.ADD, 'b')
|
||||||
self.nextChange()
|
self.nextChange()
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user