From bc83147047a9b5dc56064eeabab1d5397f6cda29 Mon Sep 17 00:00:00 2001 From: helmutm Date: Fri, 2 Mar 2007 18:58:44 +0000 Subject: [PATCH] added jeep module, a general purpose class for objects acting like a list, a dictionary and a normal object with attributes git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1606 fd906abe-77d9-0310-91a1-e0d9ade77398 --- util/jeep.py | 70 ++++++++++++++++++++++++++++++++++++++++ util/jeep.txt | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ util/tests.py | 1 + 3 files changed, 160 insertions(+) create mode 100644 util/jeep.py create mode 100644 util/jeep.txt diff --git a/util/jeep.py b/util/jeep.py new file mode 100644 index 0000000..a2a9601 --- /dev/null +++ b/util/jeep.py @@ -0,0 +1,70 @@ +# +# Copyright (c) 2007 Helmut Merz helmutm@cy55.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +A general purpose (thus 'Jeep') class that provides most of the interfaces +of sequences and dictionaries and in addition allows attribute access to +the dictionary entries. + +$Id$ +""" + +_notfound = object() + +class Jeep(object): + + _attributes = ('_sequence',) + + def __init__(self, init=None): + self._sequence = [] + if init is not None: + for attr, value in init: + setattr(self, attr, value) + + def __iter__(self): + for key in self._sequence: + yield key + + def __setattr__(self, attr, value): + if not attr in self._attributes: + if getattr(self, attr, _notfound) is _notfound: + self._sequence.append(attr) + object.__setattr__(self, attr, value) + + def __getitem__(self, key): + if type(key) is int: + return getattr(self, self._sequence[key]) + value = getattr(self, key, _notfound) + if value is _notfound: + raise KeyError(key) + return value + + def __setitem__(self, key, value): + setattr(self, key, value) + + def keys(self): + return list(self) + + def values(self): + return [self[k] for k in self] + + def items(self): + return [(k, self[k]) for k in self] + + def get(self, key, default=None): + return getattr(self, key, default) diff --git a/util/jeep.txt b/util/jeep.txt new file mode 100644 index 0000000..46095e5 --- /dev/null +++ b/util/jeep.txt @@ -0,0 +1,89 @@ +============================== +Jeep - a General Purpose Class +============================== + +$Id$ + + >>> from cybertools.util.jeep import Jeep + >>> jeep = Jeep() + + >>> jeep.first = 'first value' + >>> jeep.second = 'second value' + + >>> jeep.first + 'first value' + +In addition to the usual access via dot notation all attributes can be +accessed via dictionary notation: + +The third type of interface provided by Jeep objects is the sequence or +iterator interface. Converting a jeep object to a list iterates over the +keys: + + >>> list(jeep) + ['first', 'second'] + +Direct index access to certain entries gives the corresponding value, +not the key: + + >>> jeep[1] + 'second value' + +Changing Jeep Objects +--------------------- + +Assignment by dictionary or attribute access appends the newly assigned +attribute: + + >>> jeep['third'] = 'third value' + >>> jeep.third + 'third value' + + >>> list(jeep) + ['first', 'second', 'third'] + +Assigning a new value to an already existing attribute does not change the +order but only changes the attribute's value + + >>> jeep.second = 'new second value' + >>> list(jeep) + ['first', 'second', 'third'] + >>> jeep[1] + 'new second value' + +More Dictionary Methods +----------------------- + + >>> jeep.keys() + ['first', 'second', 'third'] + + >>> jeep.values() + ['first value', 'new second value', 'third value'] + + >>> jeep.items() + [('first', 'first value'), ('second', 'new second value'), ('third', 'third value')] + + >>> jeep.get('second') + 'new second value' + + >>> jeep.get('fourth', 'default') + 'default' + + >>> jeep.get('fourth') is None + True + + >>> jeep['fourth'] + Traceback (most recent call last): + ... + KeyError: 'fourth' + + >>> dict(jeep) + {'second': 'new second value', 'third': 'third value', 'first': 'first value'} + +Constructors +------------ + + >>> jeep2 = Jeep((('f', '1st'), ('s', '2nd'), ('t', '3rd'))) + >>> list(jeep2) + ['f', 's', 't'] + diff --git a/util/tests.py b/util/tests.py index 70833fd..194b1f7 100755 --- a/util/tests.py +++ b/util/tests.py @@ -21,6 +21,7 @@ def test_suite(): doctest.DocFileSuite('adapter.txt', optionflags=flags), doctest.DocFileSuite('defer.txt', optionflags=flags), doctest.DocFileSuite('property.txt', optionflags=flags), + doctest.DocFileSuite('jeep.txt', optionflags=flags), )) if __name__ == '__main__':