Hello dear monks!
I regularly met the problem of arbitrary data structures validation, which comes in form either hierarchical config or JSON data. The substantial idea, I got from one of Perl books (I think, this is Hight Order Perl) is the following: the programming languages have tendency to be declarative (i.e. declaring/describing the result, but not the way, how to archive it) but they'll never completely be so, because it seems to be possible only in some local areas.
When such a local area is been invented, then an extremely useful micro-language will appear. For example, well known regular expressions for the area of arbitrary text data matching/extraction. Another successful example I know is the XPath (or XPointer?) technology for nodes matching in XML documents.
The last one seems to be very successful in addressing data nodes, that a lot modules appeared, that try to mimic XPath behaviour: Data::DPath, Data::SPath, Data::PathSimple, Class::XPath.
Well, XML seems to be not too modern, too heavyweight, too enterprisish. So, the minor brother, not overcumbered with namespaces and processing instructions, appeared. It is JSON. The related data extractions/matching technology appeared a bit later; this is JSON pointer: JSON::Pointer, Mojo::JSON::Pointer.
So, my intention was to develop module, which takes the best from the two worlds: declarative data path selection (a-la JSON Pointer and XPath, but not as simple as the first, and (yet) not as complex and feature-rich as the second), and from the perl (closures, flexibility, application agnosticism, DWIM and DRY principles).
Here come a few snipplets, from which you can judge about the module
use Data::DynamicValidator qw/validator/; my $data = { ports => [2222] }; my $errors = validator($data)->( on => '/ports/*', should => sub { @_ > 0 }, because => 'At least one port should be defined at "ports" section', )->errors; if(!@$errors){ say "all ok"; } else { say $_->reason for(@$errors); }
So, it generally, it uses triplets: on (specifies data path), should (specifies testing perl closure for the results of data path selection), and because (defines human-readable string for administrator to say/describe him the errors in a config, or for HTTP client developer, that something is missing in JSON input data).
A bit more complex example. Say, you want to check that all declared ports should be available for the application at startup. So, you should do the following:
use Net::EmptyPort qw(check_port); my $errors = validator($data)->( on => '/ports/*', should => sub { @_ > 0 }, because => 'At least one port should be defined at "ports" section', each => sub { my $port = $_->value; shift->report_error("The port $port is not available for usage") if(!check_port($port)); } )->errors;
The more complex examples are available in metacpan.
Constructive critique and suggestions are more then welcome!
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Announcing Data::DynamicValidator
by Anonymous Monk on Feb 21, 2014 at 01:28 UTC |