Tawny OWL, my library for building ontologies (n.d.a) is now reaching a nice stage of maturity; it is possible to build ontologies, reason over them and so forth. We have already started to use the programmable nature of Tawny, trivially with disjoints (n.d.b) as well as allowing the ontology developer to choose the identifiers that they use to interact with the concepts (n.d.c) However, I wanted to explore further the usefulness of a programmatic environment.

One standard facility present in most languages is a test harness, and Clojure is no exception in this regard. Tawny already comes with a set of predicates for testing superclasses, both asserting and inferred, which provides a good basis for unit testing. So, this example using my test Pizza ontology shows a nice example, essentially testing definitions for CheesyPizza — these should in both a positive and negative definition.

(deftest CheesyShort
  (is (r/isuperclass? p/FourCheesePizza p/CheesyPizza))
  (is (r/isuperclass? p/MargheritaPizza p/CheesyPizza))
   (not (r/isuperclass? p/MargheritaPizza p/FourCheesePizza))))

While ths is nice, it is not enough in some cases where I wanted to test that things that do not happen. For this I introduce a new macro, with-probe-entities which adds “probe classes” into the ontology — that is a class which is there only for the purpose of a test. In this case, I test the definition of VegetarianPizza to see whether MargheritaPizza reasons correctly as a subclass. Additionally, though, I also check to see whether a subclass of VegetarianPizza and CajunPizza — which contains sausage — is inconsistent. This test could be more specific, as it tests for general coherency, although I do check for this independently. The with-probe-entities macro cleans up after itself. All entities (which can be of any kind and not just classes) are removed from the ontology afterwards; so independence of testing is not compromised).

(deftest VegetarianPizza
   (r/isuperclass? p/MargheritaPizza p/VegetarianPizza))

      [c (o/owlclass "probe"
                     :subclass p/VegetarianPizza p/CajunPizza)]

Of course, a natural consequence of the addition of tests is the desire to run
them frequenty; more over, the desire to run them in a clean environment. The
solution to this turns out to be simple. https://travis-ci.org/[Travis-CI]
integrates nicely with github -- so the addition of a simple YAML file of this
form enables a Continuous Integration, of both the Pizza ontology and the
environment (such as Tawny, for instance).

language: clojure
lein: lein2
  - openjdk7

The output of this process is
https://travis-ci.org/phillord/tawny-pizza[available] for all to read, along
with the tests for my mavenized version of
https://travis-ci.org/phillord/hermit-maven[Hermit], and also
https://travis-ci.org/phillord/tawny-owl[tawny] itself. This is not the first
time that ontologies have been continuously integrated
kurl:bio-ontologies.knowledgeblog.org/405[]; however, the nice advantage of
this is that I have not had to install anything. It even works against
external ontologies: so we have both
https://travis-ci.org/phillord/tawny-go[GO] and
https://travis-ci.org/phillord/tawny-obi[OBI]. Currently, these work against
static versions of GO and OBI. I could automate this process from the
respective repositories of these projects, by pulling with git-svn and pushing
again to github.

All in all, though, the process of recasting ontology building as a
programming task is turning out to be an interesting experience. Much of the
tooling that enables collaborative ontology building just works. It holds much
promise for the future.