From 2026320ae442a3e50fe5549e96333d7446a59d7f Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Mon, 8 Aug 2016 20:09:35 +0900 Subject: [PATCH] basic rings and storage --- .gitignore | 14 +++++++++ cachain/__init__.py | 0 cachain/ingredient.py | 73 +++++++++++++++++++++++++++++++++++++++++++ cachain/storage.py | 22 +++++++++++++ tests/__init__.py | 0 tests/test_cachain.py | 26 +++++++++++++++ 6 files changed, 135 insertions(+) create mode 100644 .gitignore create mode 100644 cachain/__init__.py create mode 100644 cachain/ingredient.py create mode 100644 cachain/storage.py create mode 100644 tests/__init__.py create mode 100644 tests/test_cachain.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..69ef6aa --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ + +dist +.env +*.pyc +*.egg-info +MANIFEST + +.cache +.eggs +.idea +.tox +.ropeproject +/build +setup.cfg diff --git a/cachain/__init__.py b/cachain/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cachain/ingredient.py b/cachain/ingredient.py new file mode 100644 index 0000000..cc1bd5c --- /dev/null +++ b/cachain/ingredient.py @@ -0,0 +1,73 @@ + + +class Key(object): + + def __init__(self, key): + self.key = key + + def build(self, args): + raise NotImplementedError + + +class FormatKey(Key): + + def build(self, args): + return self.key.format(**args) + + +class CallableKey(Key): + + def build(self, args): + return self.key(**args) + + +class Ring(object): + + def __init__(self, storage, key): + self.storage = storage + if not isinstance(key, Key): + if isinstance(key, (str, unicode)): + key = FormatKey(key) + elif callable(key): + key = CallableKey(key) + else: + raise TypeError + self.key = key + + @staticmethod + def _key_args(args, kwargs): + if args and kwargs: + raise TypeError + if args and len(args) > 1: + raise TypeError + if args: + key = args[0] + else: + key = kwargs + return key + + def get(self, *args, **kwargs): + key_args = self._key_args(args, kwargs) + return self.get_by_key(key_args) + + def get_by_key(self, key_args): + built_key = self.key.build(key_args) + return self.storage.get(built_key) + + def set(self, _value, *args, **kwargs): + key_args = self._key_args(args, kwargs) + if callable(_value): + _value = _value(**key_args) + return self.set_by_key(_value, key_args) + + def set_by_key(self, value, key_args): + built_key = self.key.build(key_args) + return self.storage.set(built_key, value) + + def get_or_set(self, _value, *args, **kwargs): + key_args = self._key_args(args, kwargs) + value = self.get_by_key(key_args) + if value is None: + value = _value(**key_args) + self.set_by_key(value, key_args) + return value diff --git a/cachain/storage.py b/cachain/storage.py new file mode 100644 index 0000000..f1c0c36 --- /dev/null +++ b/cachain/storage.py @@ -0,0 +1,22 @@ + + +class Storage(object): + + def get(self, key): + raise NotImplementedError + + def set(self, key, value, expire=None): + raise NotImplementedError + + +class DictStorage(Storage): + + def __init__(self, storage): + self.storage = storage + + def get(self, key): + return self.storage.get(key) + + def set(self, key, value, expire=None): + assert expire is None, 'expire is not supported' + return self.storage.update({key: value}) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cachain.py b/tests/test_cachain.py new file mode 100644 index 0000000..99227cb --- /dev/null +++ b/tests/test_cachain.py @@ -0,0 +1,26 @@ + +from cachain.storage import DictStorage +from cachain.ingredient import Ring + + +import pytest + + +@pytest.fixture +def fx_ring(): + storage = DictStorage({}) + ring = Ring(storage, 'user_id:{user_id}') + return ring + + +def test_ring_get_set(fx_ring): + assert fx_ring.get({'user_id': 1}) is None + fx_ring.set(lambda user_id: 100, {'user_id': 1}) + + +def test_ring_get_or_set(fx_ring): + assert fx_ring.get({'user_id': 1}) is None + assert fx_ring.get_or_set(lambda user_id: 100, {'user_id': 1}) == 100 + assert fx_ring.get({'user_id': 1}) == 100 + +