Quick Navigator

Search Site

Unix VPS
A - Starter
B - Basic
C - Preferred
D - Commercial
MPS - Dedicated
Previous VPSs
* Sign Up! *

Contact Us
Online Help
Domain Status
Man Pages

Virtual Servers

Topology Map

Server Agreement
Year 2038

USA Flag



Man Pages

Manual Reference Pages  -  DATA::RX::MANUAL::CUSTOMTYPES (3)

.ds Aq ’


Data::Rx::Manual::CustomTypes - overview of making new checkers



version 0.200007


The easiest way to create a custom type plugin is to subclass Data::Rx::CommonType::EasyNew.

  package My::Type::Foo;
  use parent Data::Rx::CommonType::EasyNew;

  sub type_uri {,EXAMPLE:rx/foo,

  sub guts_from_arg {
    my ($class, $arg, $rx) = @_;

    # get and validate arguments from $arg

    return {
        # the "guts" for this object
        # these might be validator objects using CPAN modules
        # or using $rx->make_schema() etc.

  sub assert_valid {
    my ($self, $value) = @_;

    # check the value, and either return 1 for success
    # or die on failure


and later...

  use Data::Rx;
  use My::Type::Foo;

  my $rx = Data::Rx->new({
    sort_keys => 1,
    prefix => {
      example =>,EXAMPLE:rx/,
    type_plugins => [qw(

  my $schema = $rx->make_schema(/example/foo);

  $schema->assert_valid( $some_value );


Data::Rx ships with a variety of core validators — single <>, collection <>, and combination <> types, which can be combined in surprisingly powerful ways. However the core language is deliberately limited to known cross-platform features, and there are things that you simply cannot represent with it. However, you can create custom type plugins in any implementation, including Data::Rx in Perl.


These examples are worked fully in the examples/ directory. In this man page, we will just look at interesting features of each type plugin, for clarity.

    W3C DateTime - using Perl and CPAN in checks

We might want to validate dates in the W3CDTF format, which look like 2003-02-15T13:50:05-05:00. We could of course write this with a regular expression, but let’s take an even better approach and dash to the CPAN, where we find an existing module, DateTime::Format::W3CDTF.

Our parser, then, will instantiate one of these objects, and return it with guts_from_arg to be stashed away.

  use DateTime::Format::W3CDTF;

  sub guts_from_arg {
    my ($class, $arg, $rx) = @_;

    return {
      dt => DateTime::Format::W3CDTF->new,

We can then test this in the assert_valid routine by returning true if the date format matches:

  sub assert_valid {
    my ($self, $value) = @_;

    return 1 if $value && eval {
      $self->{dt}->parse_datetime( $value  );

If it doesn’t, then we should return an error, and to make sure that we act like a good citizen in the Rx ecosystem, let’s use Data::Rx::CommonType::EasyNew’s provided method fail:

      error => [ qw(type) ],
      message => "found value is not a w3 datetime",
      value => $value,

Now we can use this checker like so:

     ->assert_valid( 2003-02-15T13:50:05-05:00 );

    Enum - delegate to another schema

You’ll often want to create data-types that match a set of values like (open, closed) or (0, 15, 30, 40). Data::Rx doesn’t have an Enum type, but it does have //any:

    type => //any,
    of => [
      { type => //str, value => open },
      { type => //str, value => closed },

This is a bit clumsy though, with the repetition of the type //str. Instead we would like an Enum type which might be declared like:

    type => /example/enum,
    contents => {
      type    => //str,
      values  => [ qw/

Ignoring input checking (for this example), we can get this information from the $arg parameter:

  sub guts_from_arg {
    my ($class, $arg, $rx) = @_;

    my $type = $arg->{contents}{type};
    my @values = @{ $arg->{contents}{values} };

We already saw how we would write the enum as an //any schema. And in fact the easiest way to implement this type plugin is to do exactly that! Let’s create a schema which is equivalent, and return it, to be stashed in the object:

    my $schema = $rx->make_schema({
      type => //any,
      of   => [
        map {;
          { type => $type, value => $_ }
        } @values,

    return { schema => $schema };

Now, checking the enum is as simple as delegating to this schema:

  sub assert_valid {
    my ($self, $value) = @_;

    $self->{schema}->assert_valid( $value );

As we are delegating to another schema’s assert_valid we know that any exceptions will be in the correct format. However, the error will be the one that //any provides:

    Failed //any: matched none of the available alternatives

This is probably clear enough for an enum. But we could improve this message by calling check instead of assert_valid and raising our own, nicely formatted, exception using fail.

    CSV - delegation, checking input

Some APIs like to specify a list of IDs or statuses not as an array (which of course Rx handles with //arr but as a comma separated list. Curses!

We would like to write a type plugin that’s defined something like:

    type => /example/csv,
    contents => /example/status,

Of course now that we are getting data as strings, we also have to worry about spaces: e.g. in ’123, 456’, is the second ID ’ 456’ or just ’456’? So let’s also accept an optional 3rd parameter trim.

Now that we’re asking for a more complex input data structure, let’s validate it using Rx itself!

  sub guts_from_arg {
    my ($class, $arg, $rx) = @_;

    my $meta = $rx->make_schema({
      type => //rec,
      required => {
        # contents => /.meta/schema, # not yet implemented
        contents => //any,
      optional => {
        trim => {
          # we dont just accept //bool as this only includes boolean objects,
          # lets also allow undef/0/1, as this is more Perlish!
          type => //any,
          of => [ //nil, //bool, //int ]

    $meta->assert_valid( $arg );

The contents argument is required, and should be a valid schema. We’ve had to make a few trade-offs:
o There isn’t yet a convenient way to specify a schema, so we’ll just accept //any for now. As we will then pass this result to make_schema shortly, we will get a further validation of that in any case! (But see <> for the full definition of a schema, if you prefer!)
o Rx’s type //bool is deliberately targeted at JSON like boolean objects, so we’ll also accept undef and 1 as truthy values.
As we are expecting a comma separated string, the first check we’ll want to make is that the object we receive is in fact a string. So the guts we’ll return are:

    return {
        trim => $arg->{trim},
        str_schema => $rx->make_schema(//str),
        item_schema => $rx->make_schema( $arg->{contents} ),

Now our assert_valid routine will use all of these pieces:

  use String::Trim;

  sub assert_valid {
    my ($self, $value) = @_;

First we check that we got a string:

    $self->{str_schema}->assert_valid( $value );

This means we can safely split the result:

    my @values = split , => $value;

    my $item_schema = $self->{item_schema};
    my $trim = $self->{trim};

For each result we trim (if requested) and use the supplied checker on each element.

    for my $subvalue (@values) {
      trim($subvalue) if $trim;

      $item_schema->assert_valid( $subvalue );

    return 1;

Putting together all the pieces, we can call this like so:

  my $csv = $rx->make_schema({
    type => /example/csv,
    contents => {
      type     => /example/enum,
      contents => {
        type    => //str,
        values  => [qw/ open closed /],
    trim => 1,

  $csv->assert_valid( open, closed ); # OK!


Hakim Cassimally <>


Ricardo SIGNES <>


This software is copyright (c) 2015 by Ricardo SIGNES.

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

Search for    or go to Top of page |  Section 3 |  Main Index

perl v5.20.3 DATA::RX::MANUAL::CUSTOMTYPES (3) 2015-04-10

Powered by GSP Visit the GSP FreeBSD Man Page Interface.
Output converted with manServer 1.07.