diff --git a/zutil/rcache.py b/zutil/rcache.py new file mode 100644 index 0000000..f6351fd --- /dev/null +++ b/zutil/rcache.py @@ -0,0 +1,60 @@ +# +# Copyright (c) 2010 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 simple mechanism for caching values in the request. + +$Id$ +""" + + +INVALID = object() + + +def caching(self, method, id): + annot = self.request.annotations + item = annot.setdefault('cybertools.util.rcache', {}) + value = item.get(id, INVALID) + if value is INVALID: + value = method() + item[id] = value + return value + + +def requestCache(method): + def _cache(self): + return caching(self, method, method.__name__) + return _cache + +rcache = requestCache + + +class requestCacheProperty(object): + + def __init__(self, func): + self.func = func + + def __get__(self, inst, class_): + if inst is None: + return self + id = self.func.__name__ + value = caching(inst, self.func, id) + inst.__dict__[id] = value + return value + +rcacheproperty = requestCacheProperty diff --git a/zutil/rcache.txt b/zutil/rcache.txt new file mode 100644 index 0000000..0b52698 --- /dev/null +++ b/zutil/rcache.txt @@ -0,0 +1,69 @@ +============ +Data Caching +============ + +$Id$ + + >>> from cybertools.zutil.rcache import rcache, rcacheproperty + + >>> class View(object): + ... def __init__(self, context, request): + ... self.context = context + ... self.request = request + ... + ... @rcache + ... def calculate(): + ... print 'calculating' + ... return 42 + ... + ... @rcacheproperty + ... def value(): + ... print 'calculating' + ... return 43 + + >>> from zope.publisher.browser import TestRequest + >>> request = TestRequest() + +When we first call the calculation method it gets executed. + + >>> v1 = View(None, request) + >>> v1.calculate() + calculating + 42 + +Subsequent calls just fetch the value from the cache. + + >>> v1.calculate() + 42 + +Even if we create a new view object (with the same request as before) the +value is just taken from the cache. + + >>> v2 = View(None, request) + >>> v2.calculate() + 42 + +Let's now have a look at the case where the result of the calculation is +stored immediately in the view. + + >>> v1.value + calculating + 43 + >>> v1.value + 43 + + >>> v2.value + 43 + +If we associate a new request with the view the calculation is done again +when using the method. + + >>> v1.request = TestRequest() + >>> v1.calculate() + calculating + 42 + +If we use the property the value is taken direktly from the instance. + + >>> v1.value + 43 diff --git a/zutil/tests.py b/zutil/tests.py index 2107bfb..535ee8e 100755 --- a/zutil/tests.py +++ b/zutil/tests.py @@ -19,7 +19,8 @@ def test_suite(): #unittest.makeSuite(Test), # we don't need this #doctest.DocTestSuite(cybertools.zutil.property, optionflags=flags), DocFileSuite('jeep.txt', optionflags=flags), - )) + doctest.DocFileSuite('rcache.txt', optionflags=flags), + )) if __name__ == '__main__': unittest.main(defaultTest='test_suite')