Since scripted queries represent an attempt to automate commonly repeated workflows, it is sensible to provide the opportunity to further eliminate any repetitive code you may end up writing. You may find that your personal use of queries and their results follows a predictable pattern, and you end up writing your code in an almost cookie-cutter style. When that happens, it is time to refactor out the commonalities into reusable chunks of code, ie. as modules.

Webservice::InterMine is designed to incorporate any additions you may want to write in as simply as possible. Being object orientated, it is possible to subclass and reimplement the entire Webservice::InterMine suite. However, a simpler approach is to use roles(1). The Webservice::InterMine modules are written using the Moose MOP system, and you can specify additional roles to be composed into the query or result iterator objects from the constructors.

In the example above we imagine that a user frequently uses YAML(2) to serialise the results data to files. Rather than repeating the same chunk of code in each script, that functionality has been packaged up in a 'role', and then passed to the query constructor:

Now the query has all the extra functionality that the role provides, so here the query knows automatically how to serialise itself to a file in the YAML format.

$query->dump_yaml_to_file($file, as => $format);

Note that the result format is passed along to the results method, so we have exactly the same behaviour here as the default results method - this is simply a wrapper for the frequently repeated chunk of code.

This shows how we can provide a completely new method to ResultIterators to make the production of HTML tables from query results trivial. It also illustrates another advantage of having low level access to the iterator itself, as it allows you to define in great detail how you want your results returned to you.

Combining these two kinds of roles can produce some radically new behaviour:

The Perl API can be dynamically extended using Moose::Roles, with two of the main objects, the query, and the result iterator, allowing roles to be composed onto them when constructed. This can increase code reuse, and thus maintainability and flexibility.