Help language development. Donate to The Perl Foundation

Structable cpan:SAMGWISE last updated on 2019-05-31

Structable-0.0.3/

Build Status

NAME

Structable - Runtime validation of associative datastructures

SYNOPSIS

use Structable;

# Define the structure of a record
my $struct = struct-def
    (struct-int    'id_weight'),
    (struct-str    'name_subject'),
    (struct-rat    'weight_subject'),
    (struct-date   'date_measure');

# Conform an acceptable Map to the given structure
say conform($struct,
    { id_weight         => 1
    , name_subject      => 'Foo'
    , weight_subject    => 3.21
    , date_measure      => '2019-01-25'
    }
).ok("Err conforming to struct.").perl;
# output ${:date_measure(Date.new(2019,1,25)), :id_weight(1), :name_subject("Foo"), :weight_subject(3.21)}

# A bad Map of values, something is missing...
{
    my $result = conform($struct,
        { not_the_id        => 2
        , name_subject      => 'Bar'
        , weight_subject    => 1.23
        , date_measure      => '2019-01-25'
        }
    );

    given $result {
        when .is-err {
            .error.say
        }
    }
}
# output: Unable to find value for 'id_weight', keys provided were: 'not_the_id', 'date_measure', 'name_subject', 'weight_subject'

# A good map after some coercion
say conform($struct,
    { id_weight         => "3" #Now it's an Str, just like you commonly find being returned from a parsed JSON document
    , name_subject      => 'Baz'
    , weight_subject    => "7.65"
    , date_measure      => '2019-01-25'
    , Something_extra   => False
    }
).ok("Err conforming to struct").perl;
# output: ${:date_measure(Date.new(2019,1,25)), :id_weight(3), :name_subject("Baz"), :weight_subject(7.65)}
# The conformed values have been coerced into their specified types

# Converting complex types back to a simple structure
say simplify($struct,
    { id_weight         => 3
    , name_subject      => 'Baz'
    , weight_subject    => 7.65
    , date_measure      => Date.new('2019-01-25')
    }
).ok("Err performing simplification with struct").perl;
# output: ${:date_measure("2019-01-25"), :id_weight(3), :name_subject("Baz"), :weight_subject(7.65)}
# The conformed values have been coerced into their specified types

DESCRIPTION

The Structable module provides a mechanism for defining an ordered and typed data defenition.

Validating input like JSON is often a tedious task, howevver with Structable you can create concise definitions which you can apply at runtime. If the input is valid (perhaps with a bit of coercion) then the conformed data will be returned in a Result::Ok object and if there was something wrong a Result::Err will be returned with a helpful error message. This means that you can use conform operations in a stream of values instead of resorting to try/catch constructs to handle your validation errors.

The struct defenition also defines an order, so by grabing a list of keys you can easily iterate over values in a conformed Map in the order you specified.

Custom types

If you need more types than those bundled in this module you can add your own! All members of a Strucatable::Struct are Structable::Type[T], a parametric role. Simply pass your type as the role's type parameter and away you go.

Caveats

Although this module helps provide assurances about the data you are injesting it has not yet been audited and tested to provide any assurances regarding security. Data from an unstrusted source may still be untrustworthy after passing through a conform step provided by this module. Particular caution should be given to the size of payload you are conforming there are no inbuilt mechanisims to prevent this style of abuse in this module.

AUTHOR

Sam Gillespie samgwise@gmail.com

COPYRIGHT AND LICENCE

Copyright 2018 Sam Gillespie

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

sub struct-def

sub struct-def(
    +
) returns Mu

A factory for defining a new C defenition. Each argument must be a C and is checked on execution of this function.

sub conform

sub conform(
    Structable::Struct $s,
    Map $m
) returns Result::Any

This subroutine attempts to conform a Map (such as a Hash) to a given struct. The outcome is returned as a C object. A C holds a filtered version of a hash which adhears to the given struct. A C represents an error and holds an error message describing why the given Map is not conformant to the given Struct.

sub str-to-int

sub str-to-int(
    $val
) returns Result::Any

A simple coercer for mapping a Str of Int to Int If you can call Int on it, it'll be acceptable as an Int. This routine is package scoped and not exported when used.

sub str-to-rat

sub str-to-rat(
    $val
) returns Result::Any

A simple coercer for mapping a Str of Rat to Rat If you can call Int on it, it'll be acceptable as an Int. This routine is package scoped and not exported when used.

sub struct-int

sub struct-int(
    Str:D $name,
    Bool :$optional = Bool::False
) returns Mu

A factory for creating a struct element of type Int. By default this Type element will try and coerce Str values to Int.

sub struct-str

sub struct-str(
    Str:D $name,
    Bool :$optional = Bool::False
) returns Mu

A factory for creating a struct element of type Str No coercion behaviours are defined for this Type

sub struct-rat

sub struct-rat(
    Str:D $name,
    Bool :$optional = Bool::False
) returns Mu

A factory for creating a struct element of type Rat. By default this Type element will try and coerce Str values to Rat.

sub str-to-date

sub str-to-date(
    $val
) returns Result::Any

A simple coercer for mapping a Str containing a date string to a Date object This routine is package scoped and not exported when used.

sub struct-date

sub struct-date(
    Str:D $name,
    Bool :$optional = Bool::False
) returns Mu

A factory for creating a struct element of type Date. Coerces date strings to Dat objects according to inbuild Date object behaviour.

sub str-to-datetime

sub str-to-datetime(
    $val
) returns Result::Any

A simple coercer for mapping a Str containing an ISO time stamp string to a DateTime object This routine is package scoped and not exported when used.

sub struct-datetime

sub struct-datetime(
    Str:D $name,
    Bool :$optional = Bool::False
) returns Mu

A factory for creating a struct element of type DateTime. Coerces date strings to Dat objects according to inbuild Date object behaviour.

sub any-to-str

sub any-to-str(
    $val
) returns Result::Any

A basic simplifier which calls the .Str method to perform simplification This routine is package scoped and not exported when used.

sub simplify

sub simplify(
    Structable::Struct:D $s,
    Map:D $m
) returns Result::Any

Pack a given map according to a given struct. This function is the complement of conform and facilitates packing a map down to a simple map, ready for serialisation to a format such as JSON.