Anonymous avatar Anonymous committed 6a2a900

forgot some files for key/value coding support.

Comments (0)

Files changed (2)

pyobjc/Lib/Foundation/test/test_keyvaluecoding.py

+import unittest
+import objc
+
+from Foundation import *
+from PyObjCTools import KeyValueCodingSupport
+
+class StraightPython(KeyValueCodingSupport.KeyValueCoding):
+    foo = 21
+    bar = 42
+    baz = { "bob" : "tail" }
+    _didBar = 0
+    def bar(self):
+        self._didBar = 1
+        return self._bar
+    def setBar(self, aValue):
+        self._bar = aValue
+    def didBar(self): return self._didBar
+
+class PyObjCMix(NSObject):
+    foo = 21
+    bar = 42
+    baz = { "bob" : "tail" }
+    _didBar = 0
+    def bar(self):
+        self._didBar = 1
+        return self._bar
+    def setBar(self, aValue):
+        self._bar = aValue
+    def didBar(self): return self._didBar
+
+class TestKeyValueCoding(unittest.TestCase):
+    def testValueForKey(self):
+        KeyValueCodingSupport.addKeyValueBridgeToClass(PyObjCMix)
+
+        a = StraightPython()
+        b = PyObjCMix.new()
+
+        self.assertEqual(a.valueForKey_("foo"), 21)
+        self.assertEqual(b.valueForKey_("foo"), 21)
+        self.assertEqual(a.didBar(), 0)
+        self.assertEqual(b.didBar(), 0)
+        self.assertEqual(a.valueForKey_("bar"), 42)
+        self.assertEqual(b.valueForKey_("bar"), 42)
+        self.assertEqual(a.didBar(), 1)
+        self.assertEqual(b.didBar(), 1)
+
+if __name__ == '__main__':
+    unittest.main( )

pyobjc/Lib/PyObjCTools/KeyValueCodingSupport.py

+from types import FunctionType
+import objc
+from Foundation import *
+
+### BUG:  If accessing iVar directly and iVar is a callable type, it'll be invoked
+# I don't think there is anything we can do about this because of the way python works
+class BridgedKeyValueMethods(NSObject):
+    def bridgedValueForKey_(self, aKey):
+        try:
+            v = getValueForKey_(self, aKey)
+            return v
+        except KeyError:
+            zuper = super(self.__class__, self)
+            if zuper.respondsToSelector_("valueForKey:"):
+                return zuper.valueForKey_(aKey)
+
+        raise KeyError, aKey
+    bridgedValueForKey_ = objc.selector(bridgedValueForKey_,  argumentTypes="s", returnType="O")
+
+def addKeyValueBridgeToClass(aClass):
+    objc.classAddMethod(aClass, "valueForKey:", BridgedKeyValueMethods.bridgedValueForKey_)
+
+def getValueForKey_(anObject, aKey):
+    upperizedKey = aKey[0].upper() + aKey[1:]
+
+    # Accessor methods
+    possibleMethod = getattr(anObject, "get" + upperizedKey, None)
+    if possibleMethod and type(possibleMethod) is FunctionType:
+        return possibleMethod(anObject)
+    aKeyPossibleMethod = getattr(anObject, aKey, None)
+    if aKeyPossibleMethod and type(aKeyPossibleMethod) is FunctionType:
+        return aKeyPossibleMethod(anObject)
+    possibleIsMethod = getattr(anObject, "is" + upperizedKey, None)
+    if possibleIsMethod and type(possibleIsMethod) is FunctionType:
+        return possibleIsMethod(anObject)
+
+    # direct access to ivar
+    if anObject.accessInstanceVariablesDirectly():
+        possibleValue = getattr(anObject, "_" + aKey, None)
+        if possibleValue is not None: return possibleValue
+        possibleValue = getattr(anObject, "_is" + upperizedKey, None)
+        if possibleValue is not None: return possibleValue
+        possibleValue = getattr(anObject, aKey, None)
+        if possibleValue is not None: return possibleValue
+        possibleValue = getattr(anObject, "is" + upperizedKey, None)
+        if possibleValue is not None: return possibleValue
+
+    raise KeyError, aKey
+
+class KeyValueCoding:
+    """A class that can be mixed into any python class to make it KV compatible on the ObjC side of the bridge."""
+    def accessInstanceVariablesDirectly(self): return 1
+
+    def valueForUndefinedKey_(self, aKey):
+        raise KeyError, aKey
+    
+    def valueForKey_(self, aKey):
+        try:
+            return getValueForKey_(self, aKey)
+        except KeyError:
+            return valueForUndefinedKey_(self, aKey)
+    
+    def valueForKeyPath_(self, aPath):
+        object = self
+        for pathElement in aPath.split('.'):
+            object = object.valueForKey_(pathElement)
+        return object
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.