Saturday, January 30, 2010

Regular expressions for non-string complex data?

Introduction


RawDev is a sustainable framework that is build from the ground with unit tests. Before I get deeper into unit testing I want to introduce to you a helper library that makes validating any data structure (simple scalar or complex array structure) easy. This library is a key building block to assert functionality in RawDev's unit testing but its use does not end there. Other uses I can think of are: debugging, (non-string) validation. Perhaps you can think of more uses. As you might expect this library is also fully extendable and ample examples are available in the download.

Synopsis


<?php

$expected = 'Hello World';
$value = 'Hello World';

$obj = new RMatch($expected);
$obj->match($value);

?>

This is a silly example that you could do much simpler for scalar values. But stick with it. The RMatch utility library simply expects a $expected value (or definition) to which it then compares the target $value.

Array example

<?php
$expected = array('person' => array('name' => 'Jane', 'spouse' => array('name' => 'John', 'address' => array('city' => 'Philadelphia'))));
$value = array('person' => array('name' => 'Jane', 'spouse' => array('name' => 'John', 'address' => array('city' => 'New York'))));

$value = $expected;
RMatch::construct('RMatch', $expected)->match($value); #fluid interface
?>
This is getting more interesting because not only does RMatch compare the two arrays it also suggests where the error occurs. RMatch is equipped to compare arrays, objects and scalars. You can tell RMatch what exact flavor of matching you seek (e.g. scalar type checking). You can also do things like: check if these three attributes of an array or object match, ignore other attributes. Finally, you can extend RMatch with your own definiting of matching.

Your own matching algorithm


It is easy to extend RMatch with your own matching algorithm. In the example below, I briefly illustrate how to implement a "like match" (just like in SQL)

<?php

class RLikeMatch extends RMatch {
function matchScalar($expected, $value, $path) {
if (!preg_match("/".str_replace($expected, "%", ".*?")."/", $value)) {
throw new RException('nonlike_match_scalar', 'Value [%s] does not like-match expected value [%s] for item [%s].', $value, $expected, $path);
}
}
}

RMatch::construct('RLikeMatch', 'dog%')->match('dog person');

?>

Conclusion

The RMatch library is modular, powerful, lean and easy to use. Although it's initial use was to help assert any test result for unit testing, it can be used in many other situations such as validation and debugging. Although you are likely just to use the defaults, it is easy to change the algorithm on which complex structures are matched. In addition, any part of a complex tree is extendible to have it's own custom match capability.


Future

Using this library reminded me a lot of doing regular expressions on arrays. This idea could be expanded more in the future. A simple syntax could describe definitions such as the count, order, required, etc.

Links

RMatch API Documentation
Download RawDev

No comments:

Post a Comment