In developing Strophe.j and ojspec (more coming on that soon), I ran into the need for a couple of utility classes. To collect these utility classes, I've created a github repository named OJUtils. Currently the two classes in there are BlankSlate and DelegateProxy.
BlankSlate is an equivalent to the BlankSlate class in Ruby: it provides the absolute minimum necessary for an Objective-J class to function correctly. This makes it ideal for use in proxying scenarios when you want as few methods interfering with proxying as possible. I use it in ojspec to set up a mocking framework. BlankSlate has 3 class methods and 5 instance methods, and nothing else. These are:
- + alloc -- A basic alloc method that correctly sets up a bare bones object.
- + initialize -- A blank implementation that is necessary for correct functioning in the Objective-J world.
- + load -- Likewise a blank implementation necessary for correct functionality in Objective-J.
- - description -- A barebones implementation that displays the class name with the hash.
- - methodSignatureForSelector: -- An implementation that always returns null (thus never calling forwardInvocation:)
- - forward:: -- A full implementation taken basically verbatim from CPObject. Calls forwardInvocation: when an unknown method is called but has a non-null methodSignatureForSelector:.
- - forwardInvocation: -- Invokes doesNotRecognizeSelector: immediately.
- - doesNotRecognizeSelector: -- Raises a CPInvalidArgumentException immediately.
No other methods are defined, so a proxy class can easily use forwardInvocation: to proxy almost all method calls successfully.
Something like BlankSlate is likely to go into Cappuccino itself soon (I'm hoping to have time to move this over there) -- possibly based on NSProxy concepts.
There is an oft-seen pattern in the Cappuccino codebase when invoking something on a delegate:
It seemed annoying to do this every time, and thus during the creation of Strophe.j was born DelegateProxy. DelegateProxy acts as a simple wrapper around your delegate on which you can invoke any method you want with the knowledge that it will only be forwarded to the delegate if the delegate can handle it. If it can't, then the method call will be silently ignored without causing any errors. This means that code like the above turns into a simple:
DelegateProxy itself is a super-simple class, and relies on BlankSlate to provide a very basic starting point. All you need to do is ensure that you keep a reference to a DelegateProxy wrapped around your delegate instead of keeping your delegate itself.
Creating a new DelegateProxy is as simple as:
And that's it, you're ready to just do method invocations without worrying about respondsToSelector checks!