NAME Data::Processor - Transform Perl Data Structures, Validate Data against a Schema, Produce Data from a Schema, or produce documentation directly from information in the Schema. SYNOPSIS use Data::Processor; my $schema = { section => { description => 'a section with a few members', error_msg => 'cannot find "section" in config', members => { foo => { # value restriction either with a regex.. value => qr{f.*}, description => 'a string beginning with "f"' }, bar => { # ..or with a validator callback. validator => sub { my $self = shift; my $parent = shift; # undef is "no-error" -> success. no strict 'refs'; return undef if $self->{value} == 42; } }, wuu => { optional => 1 } } } }; my $p = Data::Processor->new($schema); my $data = { section => { foo => 'frobnicate', bar => 42, # "wuu" being optional, can be omitted.. } }; my $error_collection = $p->validate($data, verbose=>0); # no errors :-) # in case of errors: # ------------------ # print each error on one line. say $error_collection; # same for my $e ($error_collection->as_array){ say $e; # do more.. } DESCRIPTION Data::Processor is a tool for transforming, verifying, and producing Perl data structures from / against a schema, defined as a Perl data structure. METHODS new my $processor = Data::Processor->new($schema); optional parameters: - indent: count of spaces to insert when printing in verbose mode. Default 4 - depth: level at which to start. Default is 0. - verbose: Set to a true value to print messages during processing. validate Validate the data against a schema. The schema either needs to be present already or be passed as an argument. my $error_collection = $processor->validate($data, verbose=>0); validate_schema check that the schema is valid. This method gets called upon creation of a new Data::Processor object. my $error_collection = $processor->validate_schema(); merge_schema merges another schema into the schema (optionally at a specific node) my $error_collection = $processor->merge_schema($schema_2); merging rules: - merging transformers will result in an error - merge checks if all merged elements match existing elements - non existing elements will be added from merging schema - validators from existing and merging schema get combined transform_data Transform one key in the data according to rules specified as callbacks that themodule calls for you. Transforms the data in-place. my $validator = Data::Processor::Validator->new($schema, data => $data) my $error_string = $processor->transform($key, $schema_key, $value); This is not tremendously useful at the moment, especially because validate() transforms during validation. make_data Writes a data template using the information found in the schema. my $data = $processor->make_data(data=>$data); make_pod Write descriptive pod from the schema. my $pod_string = $processor->make_pod(); SCHEMA REFERENCE Top-level keys and members The schema is described by a nested hash. At the top level, and within a members definition, the keys are the same as the structure you are describing. So for example: my $schema = { coordinates => { members => { x => { description => "the x coordinate", }, y => { description => "the y coordinate", }, } } }; This schema describes a structure which might look like this: { coordinates => { x => 1, y => 2} } Obviously this can be nested all the way down: my $schema = { house => { members => { bungalow => { members => { rooms => { #... } } } } } }; array To have a key point to an array of things, simply use the array key. So: my $schema = { houses => { array => 1, } }; Would describe a structure like: { houses => [] } And of course you can nest within here so: my $schema = { houses => { array => 1, members => { name => {}, windows => { array => 1, } }, }, }; Might describe: { houses => [ { name => 'bob', windows => []}, { name => 'harry', windows => []}, ] } description The description key within a definition describes that value: my $schema = { x => { description => 'The x coordinate' }, }; error_msg The error_msg key can be set to provide extra context for when a value is not found or fails the value test. optional Most values are required by default. To reverse this use the "optional" key: my $schema = { x => { optional => 1, }, y => { # required }, }; regex Treating regular expressions as keys If you set "regex" within a definition then it's key will be treated as a regular expression. my $schema = { 'color_.+' => { regex => 1 }, }; my $data = { color_red => 'red', color_blue => 'blue'}; Data::Processor->new($schema)->validate($data); transformer transform the data for further processing Transformer maps to a sub ref which will be passed the value and the containing structure. Your return value provides the new value. my $schema = { x => { transformer => sub{ my( $value, $section ) = @_; $value = $value + 1; return $value; } } }; my $data = { x => 1 }; my $p = Data::Processor->new($schema); my $val = Data::Processor::Validator->new( $schema, data => $data); $p->transform_data('x', 'x', $val); say $data->{x}; #will print 2 If you wish to provide an error from the transformer you should die with a hash reference with a key of "msg" mapping to your error: my $schema = { x => { transformer => sub{ die { msg => "SOMETHING IS WRONG" }; } }, }; my $p = Data::Processor->new($schema); my $data = { x => 1 }; my $val = Data::Processor::Validator->new( $schema, data => $data); my $error = $p->transform_data('x', 'x', $val); say $error; # will print: error transforming 'x': SOMETHING IS WRONG The transformer is called before any validator, so: my $schema = { x => { transformer => sub{ my( $value, $section ) = @_; return $value + 1; }, validator => sub{ my( $value ) = @_; if( $value < 2 ){ return "too low" } }, }, }; my $p = Data::Processor->new( $schema ); my $data = { x => 1 }; my $errors = $p->validate(); say $errors->count; # will print 0 say $data->{x}; # will print 2 value checking against regular expression To check a value against a regular expression you can use the value key within a definition, mapped to a quoted regex: my $schema = { x => { value => qr{\d+} } }; validator checking more complex values using a callback To conduct extensive checks you can use validator and provide a callback. Your sub will be passed the value and it's container. If you return anything it will be regarded as an error message, so to indicate a valid value you return nothing: my $schema = { bob => { validator => sub{ my( $value, $section ) = @_; if( $value ne 'bob' ){ return "Bob must equal bob!"; } return; }, }, }; my $p = Data::Processor->new($schema); # would validate: $p->validate({ bob => "bob" }); # would fail: $p->validate({ bob => "harry"}); See also Data::Processor::ValidatorFactory Validator objects Validator may also be an object, in this case the object must implement a "validate" method. The "validate" method should return undef if valid, or an error message string if there is a problem. package FiveChecker; sub new { bless {}, shift(); } sub validate{ my( $self, $val ) = @_; $val == 5 or return "I wanted five!"; return; } package main; my $checker = FiveChecker->new; my $schema = ( five => ( validator => $checker, ), ); my $dp = Data::Processor->new($schema); $dp->validate({five => 6}); # fails $dp->validate({five => 5}); # passes You can for example use MooseX::Types and Type::Tiny type constraints that are objects which offer validate methods which work this way. use Types::Standard -all; # ... in schema ... foo => { validator => ArrayRef[Int], description => 'an arrayref of integers' }, AUTHOR Matthias Bloch COPYRIGHT Copyright 2015- Matthias Bloch LICENSE This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.