The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Data::Type::Docs::Howto - Point to point recipes how to get things done

TYPICAL SCENARIOS

Here some words on major fields where perl and Data::Type may be used. Generally you may use Data::Type::Guard (drawback: currently inferior problem reports) for a group of types, or use valid() one by one. Prompting the user when he made mistakes is best done with the summary() function (supports localized texts) or by simply translating the thrown exceptions to non-programmer-style instructions.

CGI

Web formfields ares definitivly the painmaker number one. Testing whether the user entered what you want is no more a difficult task. Data::Type also helps you to provide this nice red marks near incorrect input fields, to point the user what was wrong. A fictive form

  <form method="POST" enctype="application/x-www-form-urlencoded" action="/cgi-bin/applyform.cgi"> 
    <input type="text" name="firstname"/>
    <input type="text" name="email"/>
    <input type="text" name="social_id"/>
    <input type="text" name="contacts"/>
    <input type="submit" value="OK"> 
  </form> 

The corresponding /cgi-bin/applyform.cgi would look like

  use Data::Type qw(:all);

  use Data::Type::Guard;

    my $dtg = Data::Type::Guard->new
    (
      tests =>
      {
        email =>       STD::EMAIL( 1 ),
        firstname =>   STD::WORD,
        social_id =>   [ STD::NUM, STD::VARCHAR( 10 ) ],
        contacts =>    sub { my %args = @_; exists $args{lucy} },
      }
    );

    cgi_error( "You made a mistake in one of the form fields. Please review your input." ) unless $dtg->inspect( $cgi->Params );

and alternativ for /cgi-bin/applyform.cgi:

    my %problems;

    use Data::Iter 'iter'; # exports 'iter'

    foreach my $i ( iter { email => STD::EMAIL( 1 ), firstname => STD::WORD  } )
    {
      try
      {
          valid $cgi->param( $i->KEY ), $i->VALUE;
      }
      catch Error with
      { 
          my $dte = shift;

          $problems{ $i->KEY } = sprintf "%s is not %s", $i->KEY, $dte->info;
      };
    }

    generate_cgi__form( annotate => \%problems );

[Note] iter() is a function from the Data::Iter (CPAN).

[Info] Visit the contrib/cgi_application_datatype_verifier.pl under the distributions root directory. It provides a machine-independant approach to type verification. Via this cgi-script you install Data::Type on one machine and all others with network access can harness it (even from another language then perl).

DBI

Imagine you want to test whether all email addresses in an existing database are active/valid. Since no known database vendor has a custom "email" datatype included AFAIK, Data::Type shines here:

  use Data::Type qw(:all);

    my $dbh = DBI->new( ... );

    my $sth = $dbh->do( 'SELECT userid, lastname, email FROM customers' ) or die $DBI::err;

    while( my $href = $sth->fetchrow_hashref )
    {
      try
      {
          valid $href->{social_id}, STD::NUM, STD::VARCHAR( 10 );

          valid $href->{email}, STD::EMAIL;
      }
      catch Error with
      { 
          $dbh->do( sprintf "DELETE FROM customers WHERE userid = %s", $href->{userid} );
      };
    }

[Note] This would have been easier to use an Data::Type::Guard object, but its verbose.

Class properties

  my $g = Data::Type::Guard->new( 

    tests =>
    {
      email => STD::EMAIL, 
      firstname => STD::WORD,
      lastname  => STD::WORD,
      sex => STD::GENDER,
      countrycode => STD::NUM,
      age => STD::NUM,
      contacts => sub { my %args = @_; exists $args{lucy} },                            
    }
  );

  my $h = Human->new( email => 'j@d.de', firstname => 'john', lastname => 'doe', sex => 'male', countrycode => '123123', age => 12 );

  $h->contacts( { lucy => '110', john => '123' } );

  printf "%s is ok", $h->firstname if $g->inspect( $h );

If one is really adventerous enough to use Class::Maker (i use it!) one could use following extension to its 'class' function:

 class 'Human',
 {
   public =>
   {
      string => [qw(email firstname lastname sex)],

      num => [qw(age countrycode)],

      hash => [qw(contacts)],
   },
   types =>
   {
      email => STD::EMAIL, 

      firstname => STD::WORD,

      lastname  => STD::WORD,

      sex => STD::GENDER,

      countrycode => STD::NUM,

      age => STD::NUM,

      contacts => sub { my %args = @_; exists $args{lucy} },            
   }
 };

 ... create $g and $h as above ...

 $g->inspect( $h );

[Note] Class::Maker has soon more documentation on it.

Getopt

  use Getopt::Long;

    my %options = ();

    my @config = qw/help|? man recipient=s firstname=s count=s/;

    my $ctypes = { recipient => STD::EMAIL, firstname => STD::WORD, count => STD::NUM };

       GetOptions( \%options, @config ) or pod2usage(2);

       my $g = Data::Type::Guard->new( tests => $ctypes );

       die "invalid parameter type found\n" unless $g->inspect( \%options );

[NOTE] recipient=s is already some loose valuetype definition. So a more integrated Getopt::Long could someday use Data::Type types like recipient=STD::EMAIL. Anybody interested, hands up?

Perl data

  sub my_function
  {
    my %params = @_;

    try
    {
      valid $params{one}, STD::NUM, STD::VARCHAR( 10 );

      valid $params{three}, STD::VARCHAR( 2 );
    }
    catch Error with
    { 
      my $e = shift;

      print "Expected '%s' %s at %s line %s\n", $e->value, $e->type->info, $e->file, $e->line;

      Carp::croak "invalid parameters";
    };
  }

  my_function( one => 123, two => 3247, three => 'xxxx' );

LOCALIZATION

The default initialized locale handle resides in $Data::Type-lh> (read only). Visit Locale::Maketext manual for more material. So a simple warning would look like:

  warn $Data::Type->lh->maketext( "Can't open file [_1]: [_2]\n", $f, $! );

while the lexicon in Data::Type::L18N::de would look like

  our %Lexicon =
  (
     "Can't open file [_1]: [_2]\n" => "Problem beim öffnen der Datei [_1]. Grund: [_2]\n",
  );

Here a complete template for your own locale:

  package Data::Type::L18N::de;

    our @ISA = qw(Data::Type::L18N);

    use strict;

    our %Lexicon =
    (
      __current_locale__ => 'deutsch',

      "Can't open file [_1]: [_2]\n" => "Problem beim öffnen der datei [_1]. Grund: [_2]\n",

      "error occured" => "Ein Fehler ist aufgetreten",
    );

CONTACT

Sourceforge http://sf.net/projects/datatype is hosting a project dedicated to this module. And I enjoy receiving your comments/suggestion/reports also via http://rt.cpan.org or http://testers.cpan.org.

AUTHOR

Murat Uenalan, <muenalan@cpan.org>

1 POD Error

The following errors were encountered while parsing the POD:

Around line 203:

Non-ASCII character seen before =encoding in 'öffnen'. Assuming CP1252