# ABSTRACT: Type Library for Perl 5
package Data::Object::Library;

use strict;
use warnings;

use 5.014;

use Data::Object;
use Scalar::Util;

use Type::Library -base;
use Type::Utils -all;

our $VERSION = '0.60'; # VERSION

extends 'Types::Standard';
extends 'Types::Common::Numeric';
extends 'Types::Common::String';

our @TYPES = qw(
  Any
  AnyObj
  AnyObject
  ArrayObj
  ArrayObject
  ArrayRef
  Bool
  ClassName
  CodeObj
  CodeObject
  CodeRef
  ConsumerOf
  Defined
  Dict
  Enum
  FileHandle
  FloatObj
  FloatObject
  GlobRef
  HasMethods
  HashObj
  HashObject
  HashRef
  InstanceOf
  Int
  IntObj
  IntObject
  IntegerObj
  IntegerObject
  Item
  LaxNum
  LowerCaseSimpleStr
  LowerCaseStr
  Map
  Maybe
  NegativeInt
  NegativeNum
  NegativeOrZeroInt
  NegativeOrZeroNum
  NonEmptySimpleStr
  NonEmptyStr
  Num
  NumObj
  NumObject
  NumberObj
  NumberObject
  NumericCode
  Object
  OptList
  Optional
  Overload
  Password
  PositiveInt
  PositiveNum
  PositiveOrZeroInt
  PositiveOrZeroNum
  Ref
  RegexpObj
  RegexpObject
  RegexpRef
  RoleName
  ScalarObj
  ScalarObject
  ScalarRef
  SimpleStr
  SingleDigit
  Str
  StrMatch
  StrObj
  StrObject
  StrictNum
  StringObj
  StringObject
  StrongPassword
  Tied
  Tuple
  Undef
  UndefObj
  UndefObject
  UniversalObj
  UniversalObject
  UpperCaseSimpleStr
  UpperCaseStr
  Value
);

my $registry = __PACKAGE__->meta;

sub DECLARE {

  my ($name, %opts) = @_;

  return map +(DECLARE($_, %opts)), @$name if ref $name;

  ($opts{name} = $name) =~ s/:://g;

  my @cans = ref($opts{can}) eq 'ARRAY'  ? @{$opts{can}}  : $opts{can}  // ();
  my @isas = ref($opts{isa}) eq 'ARRAY'  ? @{$opts{isa}}  : $opts{isa}  // ();
  my @does = ref($opts{does}) eq 'ARRAY' ? @{$opts{does}} : $opts{does} // ();

  my $code = $opts{constraint};
  my $text = $opts{inlined};

  $opts{constraint} = sub {
    my @args = @_;
    return if @isas and grep(not($args[0]->isa($_)),  @isas);
    return if @cans and grep(not($args[0]->can($_)),  @cans);
    return if @does and grep(not($args[0]->does($_)), @does);
    return if $code and not $code->(@args);
    return 1;
  };

  $opts{inlined} = sub {
    my $blessed = "Scalar::Util::blessed($_[1])";
    return join(' && ',
      map "($_)",
      join(' && ', map "($blessed and $_[1]->isa('$_'))",  @isas),
      join(' && ', map "($blessed and $_[1]->does('$_'))", @does),
      join(' && ', map "($blessed and $_[1]->can('$_'))",  @cans),
      $text ? $text : (),
    );
  };

  $opts{bless}   = "Type::Tiny";
  $opts{parent}  = "Object" unless $opts{parent};
  $opts{coerion} = 1;

  { no warnings "numeric"; $opts{_caller_level}++ }

  my $coerce = delete $opts{coerce};
  my $type   = declare(%opts);

  my $functions = {
    'Data::Object::Array'     => 'data_array',
    'Data::Object::Code'      => 'data_code',
    'Data::Object::Float'     => 'data_float',
    'Data::Object::Hash'      => 'data_hash',
    'Data::Object::Integer'   => 'data_integer',
    'Data::Object::Number'    => 'data_number',
    'Data::Object::Regexp'    => 'data_regexp',
    'Data::Object::Scalar'    => 'data_scalar',
    'Data::Object::String'    => 'data_string',
    'Data::Object::Undef'     => 'data_undef',
    'Data::Object::Universal' => 'data_universal',
  };

  my ($key) = grep { $functions->{$_} } @isas;

  for my $coercive ('ARRAY' eq ref $coerce ? @$coerce : $coerce) {
    my $object   = $registry->get_type($coercive);
    my $function = $$functions{$key};

    my $forward = Data::Object->can($function);
    coerce $opts{name}, from $coercive, via { $forward->($_) };

    $object->coercion->i_really_want_to_unfreeze;

    my $reverse = Data::Object->can('deduce_deep');
    coerce $coercive, from $opts{name}, via { $reverse->($_) };

    $object->coercion->freeze;
  }

  return $type;

}

my %array_constraint = (
  constraint_generator => sub {

    my $param
      = @_
      ? Types::TypeTiny::to_TypeTiny(shift)
      : return $registry->get_type('ArrayObject');

    Types::TypeTiny::TypeTiny->check($param)
      or Types::Standard::_croak("Parameter to ArrayObject[`a] expected "
        . "to be a type constraint; got $param");

    return sub {
      my $arrayobj = shift;
      $param->check($_) || return for @$arrayobj;
      return !!1;
    }

  }
);

my %array_coercion = (
  coercion_generator => sub {

    my ($parent, $child, $param) = @_;

    return $parent->coercion unless $param->has_coercion;

    my $coercable_item = $param->coercion->_source_type_union;
    my $c              = "Type::Coercion"->new(type_constraint => $child);

    $c->add_type_coercions(
      $registry->get_type('ArrayRef') => sub {
        my $value = @_ ? $_[0] : $_;
        my $new   = [];

        for (my $i = 0; $i < @$value; $i++) {
          my $item = $value->[$i];
          return $value unless $coercable_item->check($item);
          $new->[$i] = $param->coerce($item);
        }

        return $parent->coerce($new);
      },
    );

    return $c;

  }
);

my %array_explanation = (
  deep_explanation => sub {

    my ($type, $value, $varname) = @_;
    my $param = $type->parameters->[0];

    for my $i (0 .. $#$value) {
      my $item = $value->[$i];
      next if $param->check($item);
      my $message  = '"%s" constrains each value in the array object with "%s"';
      my $position = sprintf('%s->[%d]', $varname, $i);
      my $criteria = $param->validate_explain($item, $position);
      return [sprintf($message, $type, $param), @{$criteria}];
    }

    return;

  }
);

DECLARE ["ArrayObj", "ArrayObject"] => (
  %array_constraint, %array_coercion, %array_explanation,

  isa    => ["Data::Object::Array"],
  does   => ["Data::Object::Role::Array"],
  can    => ["data", "dump"],
  coerce => ["ArrayRef"],
);

DECLARE ["CodeObj", "CodeObject"] => (
  isa    => ["Data::Object::Code"],
  does   => ["Data::Object::Role::Code"],
  can    => ["data", "dump"],
  coerce => ["CodeRef"],
);

DECLARE ["FloatObj", "FloatObject"] => (
  isa    => ["Data::Object::Float"],
  does   => ["Data::Object::Role::Float"],
  can    => ["data", "dump"],
  coerce => ["Str", "Num", "LaxNum"],
);

my %hash_constraint = (
  constraint_generator => sub {

    my $param
      = @_
      ? Types::TypeTiny::to_TypeTiny(shift)
      : return $registry->get_type('HashObject');

    Types::TypeTiny::TypeTiny->check($param)
      or Types::Standard::_croak("Parameter to HashObject[`a] expected "
        . "to be a type constraint; got $param");

    return sub {
      my $hashobj = shift;
      $param->check($_) || return for values %$hashobj;
      return !!1;
    }

  }
);

my %hash_coercion = (
  coercion_generator => sub {

    my ($parent, $child, $param) = @_;

    return $parent->coercion unless $param->has_coercion;

    my $coercable_item = $param->coercion->_source_type_union;
    my $c              = "Type::Coercion"->new(type_constraint => $child);

    $c->add_type_coercions(
      $registry->get_type('HashRef') => sub {
        my $value = @_ ? $_[0] : $_;
        my $new   = {};

        for my $key (sort keys %$value) {
          my $item = $value->{$key};
          return $value unless $coercable_item->check($item);
          $new->{$key} = $param->coerce($item);
        }

        return $parent->coerce($new);
      },
    );

    return $c;

  }
);

my %hash_explanation = (
  deep_explanation => sub {

    my ($type, $value, $varname) = @_;
    my $param = $type->parameters->[0];

    for my $key (sort keys %$value) {
      my $item = $value->{$key};
      next if $param->check($item);
      my $message  = '"%s" constrains each value in the hash object with "%s"';
      my $position = sprintf('%s->{%s}', $varname, B::perlstring($key));
      my $criteria = $param->validate_explain($item, $position);
      return [sprintf($message, $type, $param), @{$criteria}];
    }

    return;

  }
);

my %hash_overrides = (
  my_methods => {

    hashref_allows_key => sub {

      my ($self, $key) = @_;

      $registry->get_type('Str')->check($key);

    },

    hashref_allows_value => sub {

      my ($self, $key, $value) = @_;

      return !!0 unless $self->my_hashref_allows_key($key);
      return !!1 if $self == $registry->get_type('HashRef');

      my $href = $self->find_parent(sub {
        $_->has_parent && $registry->get_type('HashRef') == $_->parent;
      });

      my $param = $href->type_parameter;

      $registry->get_type('Str')->check($key) and $param->check($value);

    },

  }
);

DECLARE ["HashObj", "HashObject"] => (
  %hash_constraint, %hash_coercion, %hash_explanation, %hash_overrides,

  isa    => ["Data::Object::Hash"],
  does   => ["Data::Object::Role::Hash"],
  can    => ["data", "dump"],
  coerce => ["HashRef"],
);

DECLARE ["IntObj", "IntObject", "IntegerObj", "IntegerObject"] => (
  isa    => ["Data::Object::Integer"],
  does   => ["Data::Object::Role::Integer"],
  can    => ["data", "dump"],
  coerce => ["Str", "Num", "LaxNum", "StrictNum", "Int"],
);

DECLARE ["NumObj", "NumObject", "NumberObj", "NumberObject"] => (
  isa    => ["Data::Object::Number"],
  does   => ["Data::Object::Role::Number"],
  can    => ["data", "dump"],
  coerce => ["Str", "Num", "LaxNum", "StrictNum"],
);

DECLARE ["RegexpObj", "RegexpObject"] => (
  isa    => ["Data::Object::Regexp"],
  does   => ["Data::Object::Role::Regexp"],
  can    => ["data", "dump"],
  coerce => ["RegexpRef"],
);

DECLARE ["ScalarObj", "ScalarObject"] => (
  isa    => ["Data::Object::Scalar"],
  does   => ["Data::Object::Role::Scalar"],
  can    => ["data", "dump"],
  coerce => ["ScalarRef"],
);

DECLARE ["StrObj", "StrObject", "StringObj", "StringObject"] => (
  isa    => ["Data::Object::String"],
  does   => ["Data::Object::Role::String"],
  can    => ["data", "dump"],
  coerce => ["Str"],
);

DECLARE ["UndefObj", "UndefObject"] => (
  isa    => ["Data::Object::Undef"],
  does   => ["Data::Object::Role::Undef"],
  can    => ["data", "dump"],
  coerce => ["Undef"],
);

DECLARE ["AnyObj", "AnyObject", "UniversalObj", "UniversalObject"] => (
  isa    => ["Data::Object::Universal"],
  does   => ["Data::Object::Role::Universal"],
  can    => ["data", "dump"],
  coerce => ["Any"],
);

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Data::Object::Library - Type Library for Perl 5

=head1 VERSION

version 0.60

=head1 SYNOPSIS

  use Data::Object::Library;

=head1 DESCRIPTION

Data::Object::Library is a L<Type::Tiny> type library that extends the
L<Types::Standard>, L<Types::Common::Numeric>, and L<Types::Common::String>
libraries and adds type constraints and coercions for L<Data::Object> objects.

=head1 TYPES

=head2 Any

  has data => (
    is  => 'rw',
    isa => Any,
  );

The Any type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Any> function can be
used to throw an exception is the argument can not be validated. The C<is_Any>
function can be used to return true or false if the argument can not be
validated.

=head2 AnyObj

  has data => (
    is  => 'rw',
    isa => AnyObj,
  );

The AnyObj type constraint is provided by this library and accepts any object
that is, or is derived from, a L<Data::Object::Universal> object. The
C<assert_AnyObj> function can be used to throw an exception if the argument can
not be validated. The C<is_AnyObj> function can be used to return true or false if
the argument can not be validated.

=head2 AnyObject

  has data => (
    is  => 'rw',
    isa => AnyObject,
  );

The AnyObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Universal> object. The
C<assert_AnyObject> function can be used to throw an exception if the argument can
not be validated. The C<is_AnyObject> function can be used to return true or false
if the argument can not be validated.

=head2 ArrayObj

  has data => (
    is  => 'rw',
    isa => ArrayObj,
  );

The ArrayObj type constraint is provided by this library and accepts any object
that is, or is derived from, a L<Data::Object::Array> object. The
C<assert_ArrayObj> function can be used to throw an exception if the argument can
not be validated. The C<is_ArrayObj> function can be used to return true or false
if the argument can not be validated.

=head2 ArrayObject

  has data => (
    is  => 'rw',
    isa => ArrayObject,
  );

The ArrayObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Array> object. The
C<assert_ArrayObject> function can be used to throw an exception if the argument
can not be validated. The C<is_ArrayObject> function can be used to return true or
false if the argument can not be validated.

=head2 ArrayRef

  has data => (
    is  => 'rw',
    isa => ArrayRef,
  );

The ArrayRef type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_ArrayRef
function> can be used to throw an exception if the argument can not be
validated. The C<is_ArrayRef> function can be used to return true or false if the
argument can not be validated.

=head2 Bool

  has data => (
    is  => 'rw',
    isa => Bool,
  );

The Bool type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Bool> function can be
used to throw an exception if the argument can not be validated. The C<is_Bool>
function can be used to return true or false if the argument can not be
validated.

=head2 ClassName

  has data => (
    is  => 'rw',
    isa => ClassName['MyClass'],
  );

The ClassName type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_ClassName
function> can be used to throw an exception if the argument can not be
validated. The C<is_ClassName> function can be used to return true or false if the
argument can not be validated.

=head2 CodeObj

  has data => (
    is  => 'rw',
    isa => CodeObj,
  );

The CodeObj type constraint is provided by this library and accepts any object
that is, or is derived from, a L<Data::Object::Code> object. The C<assert_CodeObj
function> can be used to throw an exception if the argument can not be
validated. The C<is_CodeObj> function can be used to return true or false if the
argument can not be validated.

=head2 CodeObject

  has data => (
    is  => 'rw',
    isa => CodeObject,
  );

The CodeObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Code> object. The
C<assert_CodeObject> function can be used to throw an exception if the argument
can not be validated. The C<is_CodeObject> function can be used to return true or
false if the argument can not be validated.

=head2 CodeRef

  has data => (
    is  => 'rw',
    isa => CodeRef,
  );

The CodeRef type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_CodeRef> function
can be used to throw an exception if the argument can not be validated. The
C<is_CodeRef> function can be used to return true or false if the argument can not
be validated.

=head2 ConsumerOf

  has data => (
    is  => 'rw',
    isa => ConsumerOf['MyRole'],
  );

The ConsumerOf type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_ConsumerOf
function> can be used to throw an exception if the argument can not be
validated. The C<is_ConsumerOf> function can be used to return true or false if
the argument can not be validated.

=head2 Defined

  has data => (
    is  => 'rw',
    isa => Defined,
  );

The Defined type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_Defined> function
can be used to throw an exception if the argument can not be validated. The
C<is_Defined> function can be used to return true or false if the argument can not
be validated.

=head2 Dict

  has data => (
    is  => 'rw',
    isa => Dict,
  );

The Dict type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Dict> function can be
used to throw an exception if the argument can not be validated. The C<is_Dict>
function can be used to return true or false if the argument can not be
validated.

=head2 Enum

  has data => (
    is  => 'rw',
    isa => Enum,
  );

The Enum type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Enum> function can be
used to throw an exception if the argument can not be validated. The C<is_Enum>
function can be used to return true or false if the argument can not be
validated.

=head2 FileHandle

  has data => (
    is  => 'rw',
    isa => FileHandle,
  );

The FileHandle type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_FileHandle
function> can be used to throw an exception if the argument can not be
validated. The C<is_FileHandle> function can be used to return true or false if
the argument can not be validated.

=head2 FloatObj

  has data => (
    is  => 'rw',
    isa => FloatObj,
  );

The FloatObj type constraint is provided by this library and accepts any object
that is, or is derived from, a L<Data::Object::Float> object. The
C<assert_FloatObj> function can be used to throw an exception if the argument can
not be validated. The C<is_FloatObj> function can be used to return true or false
if the argument can not be validated.

=head2 FloatObject

  has data => (
    is  => 'rw',
    isa => FloatObject,
  );

The FloatObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Float> object. The
C<assert_FloatObject> function can be used to throw an exception if the argument
can not be validated. The C<is_FloatObject> function can be used to return true or
false if the argument can not be validated.

=head2 GlobRef

  has data => (
    is  => 'rw',
    isa => GlobRef,
  );

The GlobRef type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_GlobRef> function
can be used to throw an exception if the argument can not be validated. The
C<is_GlobRef> function can be used to return true or false if the argument can not
be validated.

=head2 HasMethods

  has data => (
    is  => 'rw',
    isa => HasMethods[...],
  );

The HasMethods type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_HasMethods
function> can be used to throw an exception if the argument can not be
validated. The C<is_HasMethods> function can be used to return true or false if
the argument can not be validated.

=head2 HashObj

  has data => (
    is  => 'rw',
    isa => HashObj,
  );

The HashObj type constraint is provided by this library and accepts any object
that is, or is derived from, a L<Data::Object::Hash> object. The C<assert_HashObj
function> can be used to throw an exception if the argument can not be
validated. The C<is_HashObj> function can be used to return true or false if the
argument can not be validated.

=head2 HashObject

  has data => (
    is  => 'rw',
    isa => HashObject,
  );

The HashObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Hash> object. The
C<assert_HashObject> function can be used to throw an exception if the argument
can not be validated. The C<is_HashObject> function can be used to return true or
false if the argument can not be validated.

=head2 HashRef

  has data => (
    is  => 'rw',
    isa => HashRef,
  );

The HashRef type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_HashRef> function
can be used to throw an exception if the argument can not be validated. The
C<is_HashRef> function can be used to return true or false if the argument can not
be validated.

=head2 InstanceOf

  has data => (
    is  => 'rw',
    isa => InstanceOf['MyClass'],
  );

The InstanceOf type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_InstanceOf
function> can be used to throw an exception if the argument can not be
validated. The C<is_InstanceOf> function can be used to return true or false if
the argument can not be validated.

=head2 Int

  has data => (
    is  => 'rw',
    isa => Int,
  );

The Int type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Int> function can be
used to throw an exception if the argument can not be validated. The C<is_Int>
function can be used to return true or false if the argument can not be
validated.

=head2 IntObj

  has data => (
    is  => 'rw',
    isa => IntObj,
  );

The IntObj type constraint is provided by this library and accepts any object
that is, or is derived from, a L<Data::Object::Integer> object. The
C<assert_IntObj> function can be used to throw an exception if the argument can
not be validated. The C<is_IntObj> function can be used to return true or false if
the argument can not be validated.

=head2 IntObject

  has data => (
    is  => 'rw',
    isa => IntObject,
  );

The IntObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Integer> object. The
C<assert_IntObject> function can be used to throw an exception if the argument can
not be validated. The C<is_IntObject> function can be used to return true or false
if the argument can not be validated.

=head2 IntegerObj

  has data => (
    is  => 'rw',
    isa => IntegerObj,
  );

The IntegerObj type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Integer> object. The
C<assert_IntegerObj> function can be used to throw an exception if the argument
can not be validated. The C<is_IntegerObj> function can be used to return true or
false if the argument can not be validated.

=head2 IntegerObject

  has data => (
    is  => 'rw',
    isa => IntegerObject,
  );

The IntegerObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Integer> object. The
C<assert_IntegerObject> function can be used to throw an exception if the argument
can not be validated. The C<is_IntegerObject> function can be used to return true
or false if the argument can not be validated.

=head2 Item

  has data => (
    is  => 'rw',
    isa => Item,
  );

The Item type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Item> function can be
used to throw an exception if the argument can not be validated. The C<is_Item>
function can be used to return true or false if the argument can not be
validated.

=head2 LaxNum

  has data => (
    is  => 'rw',
    isa => LaxNum,
  );

The LaxNum type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_LaxNum> function
can be used to throw an exception if the argument can not be validated. The
C<is_LaxNum> function can be used to return true or false if the argument can not
be validated.

=head2 LowerCaseSimpleStr

  has data => (
    is  => 'rw',
    isa => LowerCaseSimpleStr,
  );

The LowerCaseSimpleStr type constraint is provided by the
L<Types::Common::String> library. Please see that documentation for more The
C<assert_LowerCaseSimpleStr> function can be used to throw an exception if the
argument can not be validated. The C<is_LowerCaseSimpleStr> function can be used
to return true or false if the argument can not be validated.
information.

=head2 LowerCaseStr

  has data => (
    is  => 'rw',
    isa => LowerCaseStr,
  );

The LowerCaseStr type constraint is provided by the L<Types::Common::String>
library. Please see that documentation for more information. The C<assert_type
function> can be used to throw an exception if the argument can not be
validated. The C<is_type> function can be used to return true or false if the
argument can not be validated.

=head2 Map

  has data => (
    is  => 'rw',
    isa => Map[Int, HashRef],
  );

The Map type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Map> function can be
used to throw an exception if the argument can not be validated. The C<is_Map>
function can be used to return true or false if the argument can not be
validated.

=head2 Maybe

  has data => (
    is  => 'rw',
    isa => Maybe,
  );

The Maybe type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Maybe> function can be
used to throw an exception if the argument can not be validated. The C<is_Maybe>
function can be used to return true or false if the argument can not be
validated.

=head2 NegativeInt

  has data => (
    is  => 'rw',
    isa => NegativeInt,
  );

The NegativeInt type constraint is provided by the L<Types::Common::Numeric>
library. Please see that documentation for more information. The
C<assert_NegativeInt> function can be used to throw an exception if the argument
can not be validated. The C<is_NegativeInt> function can be used to return true or
false if the argument can not be validated.

=head2 NegativeNum

  has data => (
    is  => 'rw',
    isa => NegativeNum,
  );

The NegativeNum type constraint is provided by the L<Types::Common::Numeric>
library. Please see that documentation for more information. The
C<assert_NegativeNum> function can be used to throw an exception if the argument
can not be validated. The C<is_NegativeNum> function can be used to return true or
false if the argument can not be validated.

=head2 NegativeOrZeroInt

  has data => (
    is  => 'rw',
    isa => NegativeOrZeroInt,
  );

The NegativeOrZeroInt type constraint is provided by the
L<Types::Common::Numeric> library. Please see that documentation for more The
C<assert_NegativeOrZeroInt> function can be used to throw an exception if the
argument can not be validated. The C<is_NegativeOrZeroInt> function can be used to
return true or false if the argument can not be validated.
information.

=head2 NegativeOrZeroNum

  has data => (
    is  => 'rw',
    isa => NegativeOrZeroNum,
  );

The NegativeOrZeroNum type constraint is provided by the
L<Types::Common::Numeric> library. Please see that documentation for more The
C<assert_type> function can be used to throw an exception if the argument can not
be validated. The C<is_type> function can be used to return true or false if the
argument can not be validated.
information.

=head2 NonEmptySimpleStr

  has data => (
    is  => 'rw',
    isa => NonEmptySimpleStr,
  );

The NonEmptySimpleStr type constraint is provided by the
L<Types::Common::String> library. Please see that documentation for more The
C<assert_type> function can be used to throw an exception if the argument can not
be validated. The C<is_type> function can be used to return true or false if the
argument can not be validated.
information.

=head2 NonEmptyStr

  has data => (
    is  => 'rw',
    isa => NonEmptyStr,
  );

The NonEmptyStr type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_type> function
can be used to throw an exception if the argument can not be validated. The
C<is_type> function can be used to return true or false if the argument can not be
validated.

=head2 Num

  has data => (
    is  => 'rw',
    isa => Num,
  );

The Num type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Num> function can be
used to throw an exception if the argument can not be validated. The C<is_Num>
function can be used to return true or false if the argument can not be
validated.

=head2 NumObj

  has data => (
    is  => 'rw',
    isa => NumObj,
  );

The NumObj type constraint is provided by this library and accepts any object
that is, or is derived from, a L<Data::Object::Number> object. The
C<assert_NumObj> function can be used to throw an exception if the argument can
not be validated. The C<is_NumObj> function can be used to return true or false if
the argument can not be validated.

=head2 NumObject

  has data => (
    is  => 'rw',
    isa => NumObject,
  );

The NumObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Number> object. The
C<assert_NumObject> function can be used to throw an exception if the argument can
not be validated. The C<is_NumObject> function can be used to return true or false
if the argument can not be validated.

=head2 NumberObj

  has data => (
    is  => 'rw',
    isa => NumberObj,
  );

The NumberObj type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Number> object. The
C<assert_NumberObj> function can be used to throw an exception if the argument can
not be validated. The C<is_NumberObj> function can be used to return true or false
if the argument can not be validated.

=head2 NumberObject

  has data => (
    is  => 'rw',
    isa => NumberObject,
  );

The NumberObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Number> object. The
C<assert_NumberObject> function can be used to throw an exception if the argument
can not be validated. The C<is_NumberObject> function can be used to return true
or false if the argument can not be validated.

=head2 NumericCode

  has data => (
    is  => 'rw',
    isa => NumericCode,
  );

The NumericCode type constraint is provided by the L<Types::Common::String>
library. Please see that documentation for more information. The
C<assert_NumericCode> function can be used to throw an exception if the argument
can not be validated. The C<is_NumericCode> function can be used to return true or
false if the argument can not be validated.

=head2 Object

  has data => (
    is  => 'rw',
    isa => Object,
  );

The Object type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_Object> function
can be used to throw an exception if the argument can not be validated. The
C<is_Object> function can be used to return true or false if the argument can not
be validated.

=head2 OptList

  has data => (
    is  => 'rw',
    isa => OptList,
  );

The OptList type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_OptList> function
can be used to throw an exception if the argument can not be validated. The
C<is_OptList> function can be used to return true or false if the argument can not
be validated.

=head2 Optional

  has data => (
    is  => 'rw',
    isa => Dict[id => Optional[Int]],
  );

The Optional type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_Optional
function> can be used to throw an exception if the argument can not be
validated. The C<is_Optional> function can be used to return true or false if the
argument can not be validated.

=head2 Overload

  has data => (
    is  => 'rw',
    isa => Overload,
  );

The Overload type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_Overload
function> can be used to throw an exception if the argument can not be
validated. The C<is_Overload> function can be used to return true or false if the
argument can not be validated.

=head2 Password

  has data => (
    is  => 'rw',
    isa => Password,
  );

The Password type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_Password
function> can be used to throw an exception if the argument can not be
validated. The C<is_Password> function can be used to return true or false if the
argument can not be validated.

=head2 PositiveInt

  has data => (
    is  => 'rw',
    isa => PositiveInt,
  );

The PositiveInt type constraint is provided by the L<Types::Common::Numeric>
library. Please see that documentation for more information. The
C<assert_PositiveInt> function can be used to throw an exception if the argument
can not be validated. The C<is_PositiveInt> function can be used to return true or
false if the argument can not be validated.

=head2 PositiveNum

  has data => (
    is  => 'rw',
    isa => PositiveNum,
  );

The PositiveNum type constraint is provided by the L<Types::Common::Numeric>
library. Please see that documentation for more information. The
C<assert_PositiveNum> function can be used to throw an exception if the argument
can not be validated. The C<is_PositiveNum> function can be used to return true or
false if the argument can not be validated.

=head2 PositiveOrZeroInt

  has data => (
    is  => 'rw',
    isa => PositiveOrZeroInt,
  );

The PositiveOrZeroInt type constraint is provided by the
L<Types::Common::Numeric> library. Please see that documentation for more The
C<assert_PositiveOrZeroInt> function can be used to throw an exception if the
argument can not be validated. The C<is_PositiveOrZeroInt> function can be used to
return true or false if the argument can not be validated.
information.

=head2 PositiveOrZeroNum

  has data => (
    is  => 'rw',
    isa => PositiveOrZeroNum,
  );

The PositiveOrZeroNum type constraint is provided by the
L<Types::Common::Numeric> library. Please see that documentation for more The
C<assert_type> function can be used to throw an exception if the argument can not
be validated. The C<is_type> function can be used to return true or false if the
argument can not be validated.
information.

=head2 Ref

  has data => (
    is  => 'rw',
    isa => Ref['SCALAR'],
  );

The Ref type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_type> function can be
used to throw an exception if the argument can not be validated. The C<is_type>
function can be used to return true or false if the argument can not be
validated.

=head2 RegexpObj

  has data => (
    is  => 'rw',
    isa => RegexpObj,
  );

The RegexpObj type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Regexp> object. The
C<assert_RegexpObj> function can be used to throw an exception if the argument can
not be validated. The C<is_RegexpObj> function can be used to return true or false
if the argument can not be validated.

=head2 RegexpObject

  has data => (
    is  => 'rw',
    isa => RegexpObject,
  );

The RegexpObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Regexp> object. The
C<assert_RegexpObject> function can be used to throw an exception if the argument
can not be validated. The C<is_RegexpObject> function can be used to return true
or false if the argument can not be validated.

=head2 RegexpRef

  has data => (
    is  => 'rw',
    isa => RegexpRef,
  );

The RegexpRef type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_RegexpRef
function> can be used to throw an exception if the argument can not be
validated. The C<is_RegexpRef> function can be used to return true or false if the
argument can not be validated.

=head2 RoleName

  has data => (
    is  => 'rw',
    isa => RoleName,
  );

The RoleName type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_RoleName
function> can be used to throw an exception if the argument can not be
validated. The C<is_RoleName> function can be used to return true or false if the
argument can not be validated.

=head2 ScalarObj

  has data => (
    is  => 'rw',
    isa => ScalarObj,
  );

The ScalarObj type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Scalar> object. The
C<assert_ScalarObj> function can be used to throw an exception if the argument can
not be validated. The C<is_ScalarObj> function can be used to return true or false
if the argument can not be validated.

=head2 ScalarObject

  has data => (
    is  => 'rw',
    isa => ScalarObject,
  );

The ScalarObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Scalar> object. The
C<assert_ScalarObject> function can be used to throw an exception if the argument
can not be validated. The C<is_ScalarObject> function can be used to return true
or false if the argument can not be validated.

=head2 ScalarRef

  has data => (
    is  => 'rw',
    isa => ScalarRef,
  );

The ScalarRef type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_ScalarRef
function> can be used to throw an exception if the argument can not be
validated. The C<is_ScalarRef> function can be used to return true or false if the
argument can not be validated.

=head2 SimpleStr

  has data => (
    is  => 'rw',
    isa => SimpleStr,
  );

The SimpleStr type constraint is provided by the L<Types::Common::String>
library. Please see that documentation for more information. The
C<assert_SimpleStr> function can be used to throw an exception if the argument can
not be validated. The C<is_SimpleStr> function can be used to return true or false
if the argument can not be validated.

=head2 SingleDigit

  has data => (
    is  => 'rw',
    isa => SingleDigit,
  );

The SingleDigit type constraint is provided by the L<Types::Common::Numeric>
library. Please see that documentation for more information. The
C<assert_SingleDigit> function can be used to throw an exception if the argument
can not be validated. The C<is_SingleDigit> function can be used to return true or
false if the argument can not be validated.

=head2 Str

  has data => (
    is  => 'rw',
    isa => Str,
  );

The Str type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Str> function can be
used to throw an exception if the argument can not be validated. The C<is_Str>
function can be used to return true or false if the argument can not be
validated.

=head2 StrMatch

  has data => (
    is  => 'rw',
    isa => StrMatch,
  );

The StrMatch type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_StrMatch
function> can be used to throw an exception if the argument can not be
validated. The C<is_StrMatch> function can be used to return true or false if the
argument can not be validated.

=head2 StrObj

  has data => (
    is  => 'rw',
    isa => StrObj,
  );

The StrObj type constraint is provided by this library and accepts any object
that is, or is derived from, a L<Data::Object::String> object. The
C<assert_StrObj> function can be used to throw an exception if the argument can
not be validated. The C<is_StrObj> function can be used to return true or false if
the argument can not be validated.

=head2 StrObject

  has data => (
    is  => 'rw',
    isa => StrObject,
  );

The StrObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::String> object. The
C<assert_StrObject> function can be used to throw an exception if the argument can
not be validated. The C<is_StrObject> function can be used to return true or false
if the argument can not be validated.

=head2 StrictNum

  has data => (
    is  => 'rw',
    isa => StrictNum,
  );

The StrictNum type constraint is provided by the L<Types::Standard> library.
Please see that documentation for more information. The C<assert_StrictNum
function> can be used to throw an exception if the argument can not be
validated. The C<is_StrictNum> function can be used to return true or false if the
argument can not be validated.

=head2 StringObj

  has data => (
    is  => 'rw',
    isa => StringObj,
  );

The StringObj type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::String> object. The
C<assert_StringObj> function can be used to throw an exception if the argument can
not be validated. The C<is_StringObj> function can be used to return true or false
if the argument can not be validated.

=head2 StringObject

  has data => (
    is  => 'rw',
    isa => StringObject,
  );

The StringObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::String> object. The
C<assert_StringObject> function can be used to throw an exception if the argument
can not be validated. The C<is_StringObject> function can be used to return true
or false if the argument can not be validated.

=head2 StrongPassword

  has data => (
    is  => 'rw',
    isa => StrongPassword,
  );

The StrongPassword type constraint is provided by the L<Types::Common::String>
library. Please see that documentation for more information. The
C<assert_StrongPassword> function can be used to throw an exception if the
argument can not be validated. The C<is_StrongPassword> function can be used to
return true or false if the argument can not be validated.

=head2 Tied

  has data => (
    is  => 'rw',
    isa => Tied['MyClass'],
  );

The Tied type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Tied> function can be
used to throw an exception if the argument can not be validated. The C<is_Tied>
function can be used to return true or false if the argument can not be
validated.

=head2 Tuple

  has data => (
    is  => 'rw',
    isa => Tuple[Int, Str, Str],
  );

The Tuple type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Tuple> function can be
used to throw an exception if the argument can not be validated. The C<is_Tuple>
function can be used to return true or false if the argument can not be
validated.

=head2 Undef

  has data => (
    is  => 'rw',
    isa => Undef,
  );

The Undef type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Undef> function can be
used to throw an exception if the argument can not be validated. The C<is_Undef>
function can be used to return true or false if the argument can not be
validated.

=head2 UndefObj

  has data => (
    is  => 'rw',
    isa => UndefObj,
  );

The UndefObj type constraint is provided by this library and accepts any object
that is, or is derived from, a L<Data::Object::Undef> object. The
C<assert_UndefObj> function can be used to throw an exception if the argument can
not be validated. The C<is_UndefObj> function can be used to return true or false
if the argument can not be validated.

=head2 UndefObject

  has data => (
    is  => 'rw',
    isa => UndefObject,
  );

The UndefObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Undef> object. The
C<assert_UndefObject> function can be used to throw an exception if the argument
can not be validated. The C<is_UndefObject> function can be used to return true or
false if the argument can not be validated.

=head2 UniversalObj

  has data => (
    is  => 'rw',
    isa => UniversalObj,
  );

The UniversalObj type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Universal> object. The
C<assert_UniversalObj> function can be used to throw an exception if the argument
can not be validated. The C<is_UniversalObj> function can be used to return true
or false if the argument can not be validated.

=head2 UniversalObject

  has data => (
    is  => 'rw',
    isa => UniversalObject,
  );

The UniversalObject type constraint is provided by this library and accepts any
object that is, or is derived from, a L<Data::Object::Universal> object. The
C<assert_UniversalObject> function can be used to throw an exception if the
argument can not be validated. The C<is_UniversalObject> function can be used to
return true or false if the argument can not be validated.

=head2 UpperCaseSimpleStr

  has data => (
    is  => 'rw',
    isa => UpperCaseSimpleStr,
  );

The UpperCaseSimpleStr type constraint is provided by the
L<Types::Common::String> library. Please see that documentation for more The
C<assert_UpperCaseSimpleStr> function can be used to throw an exception if the
argument can not be validated. The C<is_UpperCaseSimpleStr> function can be used
to return true or false if the argument can not be validated.
information.

=head2 UpperCaseStr

  has data => (
    is  => 'rw',
    isa => UpperCaseStr,
  );

The UpperCaseStr type constraint is provided by the L<Types::Common::String>
library. Please see that documentation for more information. The C<assert_type
function> can be used to throw an exception if the argument can not be
validated. The C<is_type> function can be used to return true or false if the
argument can not be validated.

=head2 Value

  has data => (
    is  => 'rw',
    isa => Value,
  );

The Value type constraint is provided by the L<Types::Standard> library. Please
see that documentation for more information. The C<assert_Value> function can be
used to throw an exception if the argument can not be validated. The C<is_Value>
function can be used to return true or false if the argument can not be
validated.

=head1 SEE ALSO

=over 4

=item *

L<Data::Object::Array>

=item *

L<Data::Object::Class>

=item *

L<Data::Object::Class::Syntax>

=item *

L<Data::Object::Code>

=item *

L<Data::Object::Float>

=item *

L<Data::Object::Hash>

=item *

L<Data::Object::Integer>

=item *

L<Data::Object::Number>

=item *

L<Data::Object::Role>

=item *

L<Data::Object::Role::Syntax>

=item *

L<Data::Object::Regexp>

=item *

L<Data::Object::Scalar>

=item *

L<Data::Object::String>

=item *

L<Data::Object::Undef>

=item *

L<Data::Object::Universal>

=item *

L<Data::Object::Autobox>

=item *

L<Data::Object::Immutable>

=item *

L<Data::Object::Library>

=item *

L<Data::Object::Prototype>

=item *

L<Data::Object::Signatures>

=back

=head1 AUTHOR

Al Newkirk <anewkirk@ana.io>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2018 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.

=cut
