NAME
    Validation::Class::Document - Data Validation for Hierarchical Data

VERSION
    version 0.000016

SYNOPSIS
        package MyApp::Person;

        use Validation::Class::Document;

        my $person = MyApp::Person->new;

        # rules

        my $schema = {
            'id'                        => {mixin => [':num'], max_length => 4},
            'name'                      => {mixin => [':str'], min_length => 2},
            'title'                     => {mixin => [':str'], min_length => 5},
            'company.name'              => {mixin => [':str'], min_length => 2},
            'company.tags.@'            => {mixin => [':str'], min_length => 2},
            'company.super*.name'       => {mixin => [':str'], min_length => 2},
            'company.super*.rating.@.*' => {mixin => [':str'], },
        };

        # data

        my $data = {
            "id"      => "1234-ABC",
            "name"    => "Anita Campbell-Green",
            "title"   => "Designer",
            "company" => {
                "name"       => "House of de Vil",
                "supervisor" => {
                    "name"   => "Cruella de Vil",
                    "rating" => [
                        {   "support"  => -9,
                            "guidance" => -9
                        }
                    ]
                },
                "tags" => [
                    "evil",
                    "cruelty",
                    "dogs"
                ]
            },
        };

        unless ($person->validate_document($schema => $data)) {
            warn $person->errors_to_string if $person->error_count;
        }

DESCRIPTION
    Validation::Class::Document inherits all functionality from
    Validation::Class and implements additional abilities documented as
    follows.

    This module allows you to validate hierarchical structures using the
    Validation::Class framework. This is an experimental yet highly
    promising approach toward the consistent processing of nested
    structures. The current interface is not expected to change. This module
    was inspired by MooseX::Validation::Doctypes. Gone are the days of data
    submitted to an application in key/value form and especially in regards
    to the increasing demand for communication between applications,
    serializing and transmitting structured data over a network connection.
    Note! All matching data points will be validated forcefully (i.e.
    matching data points are required to have a value defined).

OVERVIEW
    Validation::Class::Document exports the document (or dom) keyword which
    allows you to pre-define/configure your path matching rules for your
    data structure. The "path matching rules", which is actually a custom
    object notation, referred to as the document notation, can be thought of
    as a kind-of simplified regular expression which is executed against the
    flattened data structure. The following are a few general use-cases:

        # given this JSON data structure
        {
            "id": "1234-A",
            "name": {
                "first_name" : "Bob",
                "last_name"  : "Smith",
             },
            "title": "CIO",
            "friends" : [],
        }

        # select id to validate against the string rules
        document 'foobar'  =>
            { 'id' => 'string' };

        # select name -> first_name/last_name to validate against the string rules
        document 'foobar'  =>
            {'name.first_name' => 'string', 'name.last_name' => 'string'};

        # or
        document 'foobar'  =>
            {'name.*_name' => 'string'};

        # select each element in friends to validate against the string rules
        document 'foobar'  =>
            { 'friends.@'  => 'string' };

        # or select an element of a hashref in each element in friends to validate
        document 'foobar'  =>
            { 'friends.@.name' => 'string' };

    The document declaration's keys should follow the aforementioned
    document notation schema and it's values should be strings which
    correspond to the names of fields (or other document declarations) that
    will be used to preform the data validation. It is possible to combine
    document declarations to validate hierarchical data that contains data
    structures matching one or more document patterns. The following is an
    example of what that might look like.

        package MyApp::Person;

        use Validation::Class::Document;

        # data validation rule
        field  'name' => {
            mixin      => [':str'],
            pattern    => qr/^[A-Za-z ]+$/,
            max_length => 20,
        };

        # data validation map / document notation schema
        document 'friend' => {
            'name' => 'name'
        };

        # data validation map / document notation schema
        document 'person' => {
            'name' => 'name',
            'friends.@' => 'friend'
        };

        package main;

        my $data = {
            "name"   => "Anita Campbell-Green",
            "friends" => [
                { "name" => "Horace" },
                { "name" => "Skinner" },
                { "name" => "Alonzo" },
                { "name" => "Frederick" },
            ],
        };

        my $person = MyApp::Person->new;

        unless ($person->validate_document(person => $data)) {
            warn $person->errors_to_string if $person->error_count;
        }

    Alternatively, the following is a more verbose data validation class
    using traditional styling and configuration.

        package MyApp::Person;

        use Validation::Class::Document;

        field  'id' => {
            mixin      => [':str'],
            filters    => ['numeric'],
            max_length => 2,
        };

        field  'name' => {
            mixin      => [':str'],
            pattern    => qr/^[A-Za-z ]+$/,
            max_length => 20,
        };

        field  'rating' => {
            mixin      => [':str'],
            pattern    => qr/^\-?\d+$/,
        };

        field  'tag' => {
            mixin      => [':str'],
            pattern    => qr/^(?!evil)\w+/,
            max_length => 20,
        };

        document 'person' => {
            'id'                             => 'id',
            'name'                           => 'name',
            'company.name'                   => 'name',
            'company.supervisor.name'        => 'name',
            'company.supervisor.rating.@.*'  => 'rating',
            'company.tags.@'                 => 'name'
        };

        package main;

        my $data = {
            "id"      => "1234-ABC",
            "name"    => "Anita Campbell-Green",
            "title"   => "Designer",
            "company" => {
                "name"       => "House of de Vil",
                "supervisor" => {
                    "name"   => "Cruella de Vil",
                    "rating" => [
                        {   "support"  => -9,
                            "guidance" => -9
                        }
                    ]
                },
                "tags" => [
                    "evil",
                    "cruelty",
                    "dogs"
                ]
            },
        };

        my $person = MyApp::Person->new;

        unless ($person->validate_document(person => $data)) {
            warn $person->errors_to_string if $person->error_count;
        }

METHODS
  validate_document
    The validate_document method (or document_validates) is used to validate
    the specified hierarchical data against the specified document
    declaration. This is extremely valuable for validating serialized
    messages passed between machines. This method requires two arguments,
    the name of the document declaration to be used, and the data to be
    validated which should be submitted in the form of a hashref. The
    following is an example of this technique:

        my $boolean = $self->validate_document(foobar => $data);

    Additionally, you may submit options in the form of a hashref to further
    control the validation process. The following is an example of this
    technique:

        # the prune option removes non-matching parameters (nodes)
        my $boolean = $self->validate_document(foobar => $data, { prune => 1 });

    Additionally, to support the validation of ad-hoc specifications, you
    may pass this method two hashrefs, the first being the document notation
    schema, and the second being the hierarchical data you wish to validate.

AUTHOR
    Al Newkirk <anewkirk@ana.io>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2013 by Al Newkirk.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.

