Every now and then for the past couple weeks, I've been working on a
Cocoa replacement for the
EOQualifier class in the
Enterprise Objects Framework. A
qualifier in EOF lets you specify some criteria, and then check an object against the criteria to see if it matches.
You create a qualifier by specifying a string like
(foo = bar) and (baz like 'qu?x'). This qualifier is actually three qualifiers: a key comparison qualifier checking whether the object's "foo" property matches its "bar" property, a key-value qualifier checking whether the object's "baz" property matches the string "qu?x" (with a filename-style ? wildcard), and an and qualifier matching those two.
Because Objective-C is a truly dynamic language with real support for object introspection, qualifiers can use key-value coding to apply a qualifier to
any object descended from NSObject. Objects don't have to be instances of a particular class, or implement a particular interface to be qualifiable.
To create and evaluate a qualifier, you do something like this:
- (BOOL)fooIsReallyFoo:(id)object
{
BDQualifier *q;
q = [BDQualifier qualifierWithQualifierFormat:@"foo = 'foo'"];
// This qualifier sees if an arbitrary object has a property
// named "foo" and checks to see if its value is a string
// containing "foo".
return [q evaluateWithObject:object];
}(Obviously the "BDQualifier" above is my replacement for EOQualifier. The "BD" comes from the name of my company,
bDistributed.com.)
You can do other cool things too, like filter an array based on a qualifier and get a new array of only objects matching the qualifier. You can have variables in qualifiers that are replaced by values in a dictionary; this is useful for creating database query templates, like "(parentMessageID = $parentMessageID) and (score > $articleScoreThreshold)". Since qualifiers are broken down into objects that can themselves be interrogated, it's possible to do things like create a qualifier and then generate SQL from it to query a database. (This is how they're used in EOF.)
So, why did I title this post "Test-Driven Development" when I'm raving about the coolness of qualifiers and my mad skillz? Because I've started using test-driven development to get this up and running. I wrote the bulk of it a few weeks ago, just off the cuff. Then a couple weeks ago I started trying to make it actually build. Recently I wrote a parser for qualifier format strings using lex & yacc. Getting
that working properly was entertaining. So a couple days ago I finally started integrating everything together, and trying to get qualifier evaluation working. I had set up this project to use the Open Source
OCUnit unit testing framework for Cocoa from
Sen:te, but hadn't written any test cases yet. While waiting for Gnomedex events to start, I actually wrote a few test cases.
I was able to get a whole lot done once I had a half dozen test cases. I'm starting to get pretty close to declaring this working and putting it out there for the rest of the world to use. I didn't think I was nearly this close before I started using the Test-Driven Development "write a test case, make the test case work, repeat until new test cases tend to pass immediately." I'd recommend everyone take a look at it.