1__all__ = ['classAddMethod', 'Category'] 2 3from objc._objc import selector, classAddMethods, objc_class, ivar 4 5from types import FunctionType, MethodType 6 7def classAddMethod(cls, name, method): 8 """ 9 Add a single method to a class. 'name' is the ObjC selector 10 """ 11 if isinstance(method, selector): 12 sel = selector(method.callable, 13 selector=name, 14 signature=method.signature, 15 isClassMethod=method.isClassMethod) 16 else: 17 sel = selector(method, selector=name) 18 19 return classAddMethods(cls, [sel]) 20 21 22# 23# Syntactic support for categories 24# 25 26class _CategoryMeta(type): 27 """ 28 Meta class for categories. 29 """ 30 __slots__ = () 31 _IGNORENAMES = ('__module__', '__name__', '__doc__') 32 def _newSubclass(cls, name, bases, methods): 33 return type.__new__(cls, name, bases, methods) 34 _newSubclass = classmethod(_newSubclass) 35 36 def __new__(cls, name, bases, methods): 37 if len(bases) != 1: 38 raise TypeError("Cannot have multiple inheritance with Categories") 39 40 c = bases[0].real_class 41 42 if c.__name__ != name: 43 raise TypeError("Category name must be same as class name") 44 45 46 m = [ x[1] for x in methods.iteritems() if x[0] not in cls._IGNORENAMES and isinstance(x[1], (FunctionType, MethodType, selector, classmethod))] 47 vars = [ x for x in methods.iteritems() if x[0] not in cls._IGNORENAMES and not isinstance(x[1], (FunctionType, MethodType, selector, classmethod))] 48 for k, v in vars: 49 if isinstance(v, ivar): 50 raise TypeError("Cannot add instance variables in a Category") 51 52 classAddMethods(c, m) 53 for k, v in vars: 54 setattr(c, k, v) 55 return c 56 57def Category(cls): 58 """ 59 Create a category on ``cls``. 60 61 Usage: 62 class SomeClass (Category(SomeClass)): 63 def method(self): 64 pass 65 66 ``SomeClass`` is an existing class that will be rebound to the same 67 value. The side-effect of this class definition is that the methods 68 in the class definition will be added to the existing class. 69 """ 70 if not isinstance(cls, objc_class): 71 raise TypeError, "Category can only be used on Objective-C classes" 72 retval = _CategoryMeta._newSubclass('Category', (), dict(real_class=cls)) 73 return retval 74