Move Cacher class to cacher.FirstArg.
authorNeil Moore <neil@s-z.org>
Tue, 27 May 2008 08:00:26 +0000 (04:00 -0400)
committerNeil Moore <neil@s-z.org>
Tue, 27 May 2008 08:00:26 +0000 (04:00 -0400)
cacher.py [new file with mode: 0644]
roguelike.py

diff --git a/cacher.py b/cacher.py
new file mode 100644 (file)
index 0000000..20b6dfe
--- /dev/null
+++ b/cacher.py
@@ -0,0 +1,37 @@
+class FirstArg(type):
+    """Metaclass to cache object creation by a key, which must be the
+    first constructor parameter.  Once an object with a given key has been
+    instantiated, subsequent calls to the constructor using the same first
+    argument will return the same object, even if the other arguments differ.
+
+    Examples / Tests
+    ================
+
+    >>> class MyClass (object):
+    ...     __metaclass__ = cacher.FirstArg
+    ...     def __init__(self, name, extra): self.extra = extra
+    >>> bad = MyClass('bad')
+    Traceback (most recent call last):
+        ....
+    TypeError: __init__() takes exactly 3 arguments (2 given)
+    >>> obj = MyClass('foo', 42)
+    >>> MyClass('foo') is obj
+    True
+    >>> MyClass('foo', None) is obj
+    True
+    >>> MyClass('bar', 18) is obj
+    False
+    >>> MyClass('foo', 'twelve').extra
+    42
+    >>> MyClass('bar').extra
+    18
+    """
+    def __init__(cls, name, bases, cdict):
+        super(FirstArg, cls).__init__(name, bases, cdict)
+        cls.__instcache = {}
+    def __call__( cls, name, *args, **kw ):
+        
+        if name is None or name not in cls.__instcache:
+            cls.__instcache[name] = super(FirstArg, cls).__call__(
+                    name, *args, **kw )
+        return cls.__instcache[name]
index 335c995..e459972 100755 (executable)
@@ -14,35 +14,14 @@ import re
 import os.path
 import cProfile
 
+import cacher
+
 do_profile = False
 cp = curses.color_pair
 
-class Cacher(type):
-    """Metaclass to cache object creation by name.  The name must be the
-    first constructor parameter.
-
-    Usage:
-        class MyClass (object):
-            __metaclass__ = Cacher
-            def __init__(self, name, foo, bar): pass
-
-        bad   = MyClass("bad")          => Not enough arguments
-        good  = MyClass("good", 2, 3)   => OK
-        again = MyClass("good")         => OK (cached)
-        again is good                   => True
-    """
-    def __init__(cls, name, bases, cdict):
-        super(Cacher, cls).__init__(name, bases, cdict)
-        cls.__instcache = {}
-    def __call__( cls, name, *args, **kw ):
-        
-        if name is None or name not in cls.__instcache:
-            cls.__instcache[name] = super(Cacher, cls).__call__(
-                    name, *args, **kw )
-        return cls.__instcache[name]
 
 class Color (object):
-    __metaclass__ = Cacher
+    __metaclass__ = cacher.FirstArg
     colors = {
             'Default':       (curses.COLOR_WHITE,),
             'Bright':        (curses.COLOR_WHITE,curses.A_BOLD),
@@ -130,7 +109,7 @@ class Level (object):
     region of Tiles surrounded by an impassable boundary.  Levels may
     be travelled between via transport points.
     """
-    __metaclass__ = Cacher
+    __metaclass__ = cacher.FirstArg
 
     def stair_unavailable(self, stair):
         if stair in self.unconnected_stairs:
@@ -762,7 +741,7 @@ class Water(Tile):
         return ("~", { 'flowx' : self.flowx, 'flowy' : self.flowy })
 
 class Material(object):
-    __metaclass__ = Cacher
+    __metaclass__ = cacher.FirstArg
 
     def __init__(self, name, adj, attrs):
         self.name = name
@@ -820,7 +799,7 @@ class Material(object):
         return self.attrs
 
 class ItemClass (type):
-    __metaclass__ = Cacher
+    __metaclass__ = cacher.FirstArg
     def __new__(cls, name, properties):
         base = Item
         props = properties.copy()