Skip to content

Commit

Permalink
Feature: CONSTRAINT also allows Data::Validator, Poz and hashref
Browse files Browse the repository at this point in the history
  • Loading branch information
kfly8 committed Dec 15, 2024
1 parent e6f20c3 commit fb4d4f0
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 40 deletions.
98 changes: 86 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,57 @@ This module is useful for storing constraints in a package and exporting them to

- Simple Declaration
- Export Constraints
- Store Multiple Constraints
- Store Favorite Constraints

## FEATURES

### Simple Declaration

Kura makes it easy to store constraints in a package.

```perl
use kura NAME => CONSTRAINT;
```

`CONSTRAINT` must be a any object that has a `check` method or a code reference that returns true or false.
The following is an example of a constraint declaration:
Kura makes it easy to declare constraints. This usage is same as [constant](https://metacpan.org/pod/constant) pragma!
Default implementation of `CONSTRAINT` can accept following these types:

```perl
use kura Name => StrLength[1, 255];
```
- Object having a `check` method

Many constraint libraries has a `check` method, such as [Type::Tiny](https://metacpan.org/pod/Type%3A%3ATiny), [Moose::Meta::TypeConstraint](https://metacpan.org/pod/Moose%3A%3AMeta%3A%3ATypeConstraint), [Mouse::Meta::TypeConstraint](https://metacpan.org/pod/Mouse%3A%3AMeta%3A%3ATypeConstraint), [Specio](https://metacpan.org/pod/Specio) and more. Kura accepts these objects.

```perl
use Types::Common -types;
use kura Name => StrLength[1, 255];
```

- Allowed constraint classes

Kura allows these classes: [Data::Validator](https://metacpan.org/pod/Data%3A%3AValidator), [Poz::Types](https://metacpan.org/pod/Poz%3A%3ATypes). Here is an example of using [Poz](https://metacpan.org/pod/Poz):

```perl
use Poz qw(z);
use kura Name => z->string->min(1)->max(255);
```

- Code reference

Code reference makes Type::Tiny object internally.

```perl
use kura Name => sub { length($_[0]) > 0 };
# => Name isa Type::Tiny and check method equals to this coderef.
```

- Hash reference

Hash reference also makes Type::Tiny object internally.

```perl
use kura Name => {
constraint => sub { length($_[0]) > 0,
message => sub { 'Invalid name' },
};
# => Name isa Type::Tiny
```

### Export Constraints

Expand All @@ -58,9 +91,9 @@ Foo->check('foo'); # true
Foo->check('bar'); # false
```

### Store Multiple Constraints
### Store Favorite Constraints

Kura supports multiple constraints such as [Data::Checks](https://metacpan.org/pod/Data%3A%3AChecks), [Type::Tiny](https://metacpan.org/pod/Type%3A%3ATiny), [Moose::Meta::TypeConstraint](https://metacpan.org/pod/Moose%3A%3AMeta%3A%3ATypeConstraint), [Mouse::Meta::TypeConstraint](https://metacpan.org/pod/Mouse%3A%3AMeta%3A%3ATypeConstraint), [Specio](https://metacpan.org/pod/Specio), and more.
Kura stores your favorite constraints such as [Data::Checks](https://metacpan.org/pod/Data%3A%3AChecks), [Type::Tiny](https://metacpan.org/pod/Type%3A%3ATiny), [Moose::Meta::TypeConstraint](https://metacpan.org/pod/Moose%3A%3AMeta%3A%3ATypeConstraint), [Mouse::Meta::TypeConstraint](https://metacpan.org/pod/Mouse%3A%3AMeta%3A%3ATypeConstraint), [Specio](https://metacpan.org/pod/Specio), [Data::Validator](https://metacpan.org/pod/Data%3A%3AValidator), [Poz::Types](https://metacpan.org/pod/Poz%3A%3ATypes) and more.

```
Data::Checks -----------------> +--------+
Expand Down Expand Up @@ -164,8 +197,7 @@ Kura serves a similar purpose to [Type::Library](https://metacpan.org/pod/Type%3
- Multiple Constraints
Kura is not limited to Type::Tiny. It supports multiple constraint libraries such as Moose, Mouse, Specio, and Data::Checks.
This flexibility allows consistent management of type constraints in projects that mix different libraries.
Kura is not limited to Type::Tiny. It supports multiple constraint libraries such as Moose, Mouse, Specio, Data::Checks and more. This flexibility allows consistent management of type constraints in projects that mix different libraries.
While Type::Library is powerful and versatile, Kura stands out for its simplicity, flexibility, and ability to integrate with multiple constraint systems.
It’s particularly useful in projects where multiple type constraint libraries coexist or when leveraging built-in class syntax.
Expand Down Expand Up @@ -252,6 +284,40 @@ use kura _PrivateFoo => Str;
# => "_PrivateFoo" is not exported
```

## Customizing Constraints

If you want to customize constraints, `create_constraint` function is a hook point. You can override this function to customize constraints.
Following are examples of customizing constraints:

```perl
package mykura {
use kura ();
use MyConstraint;
sub import {
shift;
my ($name, $args) = @_;
my $caller = caller;
no strict 'refs';
local *{"kura::create_constraint"} = \&create_constraint;
kura->import_into($caller, $name, $args);
}
sub create_constraint {
my ($args, $opts) = @_;
return (undef, "Invalid mykura arguments") unless (ref $args||'') eq 'HASH';
return (MyConstraint->new(%$args), undef);
}
}
package main {
use mykura Name => { constraint => sub { length($_[0]) > 0 } };
}
```

# LICENSE

Copyright (C) kobaken.
Expand All @@ -262,3 +328,11 @@ it under the same terms as Perl itself.
# AUTHOR

kobaken <kentafly88@gmail.com>

# POD ERRORS

Hey! **The above document had some coding errors, which are explained below:**

- Around line 225:

You forgot a '=back' before '=head3'
90 changes: 76 additions & 14 deletions lib/kura.pm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ my %FORBIDDEN_NAME = map { $_ => 1 } qw{
AUTOLOAD STDIN STDOUT STDERR ARGV ARGVOUT ENV INC SIG
};

my @ALLOWED_CONSTRAINT_CLASSES = qw(
Data::Validator
Poz::Types
);

sub import {
my $pkg = shift;
my $caller = caller;
Expand All @@ -32,11 +37,6 @@ sub import_into {
_save_inc($caller);
}

our @ALLOWED_CONSTRAINT_CLASSES = qw(
Data::Validator
Poz::Types
);

# Create a constraint object.
#
# @param $constraint Defined. Following `create_constraint` function allows these types: Object, CodeRef, HashRef.
Expand Down Expand Up @@ -174,23 +174,54 @@ This module is useful for storing constraints in a package and exporting them to
=item * Export Constraints
=item * Store Multiple Constraints
=item * Store Favorite Constraints
=back
=head2 FEATURES
=head3 Simple Declaration
Kura makes it easy to store constraints in a package.
use kura NAME => CONSTRAINT;
C<CONSTRAINT> must be a any object that has a C<check> method or a code reference that returns true or false.
The following is an example of a constraint declaration:
Kura makes it easy to declare constraints. This usage is same as L<constant> pragma!
Default implementation of C<CONSTRAINT> can accept following these types:
=over 2
=item Object having a C<check> method
Many constraint libraries has a C<check> method, such as L<Type::Tiny>, L<Moose::Meta::TypeConstraint>, L<Mouse::Meta::TypeConstraint>, L<Specio> and more. Kura accepts these objects.
use Types::Common -types;
use kura Name => StrLength[1, 255];
=item Allowed constraint classes
Kura allows these classes: L<Data::Validator>, L<Poz::Types>. Here is an example of using L<Poz>:
use Poz qw(z);
use kura Name => z->string->min(1)->max(255);
=item Code reference
Code reference makes Type::Tiny object internally.
use kura Name => sub { length($_[0]) > 0 };
# => Name isa Type::Tiny and check method equals to this coderef.
=item Hash reference
Hash reference also makes Type::Tiny object internally.
use kura Name => {
constraint => sub { length($_[0]) > 0,
message => sub { 'Invalid name' },
};
# => Name isa Type::Tiny
=cut
=head3 Export Constraints
Kura allows you to export constraints to other packages using your favorite exporter such as L<Exporter>, L<Exporter::Tiny>, and more.
Expand All @@ -206,9 +237,9 @@ Kura allows you to export constraints to other packages using your favorite expo
Foo->check('foo'); # true
Foo->check('bar'); # false
=head3 Store Multiple Constraints
=head3 Store Favorite Constraints
Kura supports multiple constraints such as L<Data::Checks>, L<Type::Tiny>, L<Moose::Meta::TypeConstraint>, L<Mouse::Meta::TypeConstraint>, L<Specio>, and more.
Kura stores your favorite constraints such as L<Data::Checks>, L<Type::Tiny>, L<Moose::Meta::TypeConstraint>, L<Mouse::Meta::TypeConstraint>, L<Specio>, L<Data::Validator>, L<Poz::Types> and more.
Data::Checks -----------------> +--------+
| |
Expand Down Expand Up @@ -304,8 +335,7 @@ This keeps your namespace cleaner and focuses on the essential C<check> method.
=item * Multiple Constraints
Kura is not limited to Type::Tiny. It supports multiple constraint libraries such as Moose, Mouse, Specio, and Data::Checks.
This flexibility allows consistent management of type constraints in projects that mix different libraries.
Kura is not limited to Type::Tiny. It supports multiple constraint libraries such as Moose, Mouse, Specio, Data::Checks and more. This flexibility allows consistent management of type constraints in projects that mix different libraries.
=back
Expand Down Expand Up @@ -385,6 +415,38 @@ If you don't want to export constraints, put a prefix C<_> to the constraint nam
use kura _PrivateFoo => Str;
# => "_PrivateFoo" is not exported
=head2 Customizing Constraints
If you want to customize constraints, C<create_constraint> function is a hook point. You can override this function to customize constraints.
Following are examples of customizing constraints:
package mykura {
use kura ();
use MyConstraint;
sub import {
shift;
my ($name, $args) = @_;
my $caller = caller;
no strict 'refs';
local *{"kura::create_constraint"} = \&create_constraint;
kura->import_into($caller, $name, $args);
}
sub create_constraint {
my ($args, $opts) = @_;
return (undef, "Invalid mykura arguments") unless (ref $args||'') eq 'HASH';
return (MyConstraint->new(%$args), undef);
}
}
package main {
use mykura Name => { constraint => sub { length($_[0]) > 0 } };
}
=head1 LICENSE
Copyright (C) kobaken.
Expand Down
12 changes: 8 additions & 4 deletions t/02-import_into.t
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
use Test2::V0;

use lib './t/lib';
use MyConstraint;

subtest 'Test `import_into` method' => sub {
subtest 'Customize the import method to your taste' => sub {
use mykura Foo => MyConstraint->new;
use mykura Foo => { a => 1, b => 2 };

# MyKura customize the name of the constraint
isa_ok MyFoo, 'MyConstraint';
isa_ok Foo, 'MyConstraint';

is Foo->{a}, 1;
is Foo->{b}, 2;

eval 'use mykura Bar => 1';
like $@, qr/^Invalid mykura arguments/;
}
};

Expand Down
11 changes: 11 additions & 0 deletions t/10-integration/Data-Validator/TestDataValidator.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package TestDataValidator;

use Exporter 'import';
use Data::Validator;

use kura Book => Data::Validator->new(
title => 'Str',
author => 'Str',
);

1;
24 changes: 24 additions & 0 deletions t/10-integration/Data-Validator/basic.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use Test2::V0;
use Test2::Require::Module 'Poz', '0.02';

use FindBin qw($Bin);
use lib "$Bin";

use TestDataValidator qw(Book);

subtest 'Test `kura` with Data::Validator' => sub {
isa_ok Book, 'Data::Validator';

my $data = { title => "Spidering Hacks", author => "Kevin Hemenway" };

my $got = Book->validate($data);
is $got, $data;

ok dies {
Book->validate({
isbn => "978-0-596-00797-3",
});
};
};

done_testing;
12 changes: 7 additions & 5 deletions t/10-integration/Poz/TestPoz.pm
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package TestPoz;
use Exporter 'import';
use Poz qw(z);

use kura Title => z->string->min(1)->max(255);
use kura Author => z->string->default("Anonymous");
use kura Published => z->date;

use kura Book => z->object({
title => z->string,
author => z->string->default("Anonymous"),
published => z->date,
created_at => z->date->default(sub { Time::Piece::localtime()->strftime('%Y-%m-%d') }),
updated_at => z->date->default(sub { Time::Piece::localtime()->strftime('%Y-%m-%d') }),
title => Title,
author => Author,
published => Published,
})->as("My::Book");

1;
6 changes: 5 additions & 1 deletion t/lib/MyConstraint.pm
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package MyConstraint;

sub new { bless {}, shift }
sub new {
my ($class, %args) = @_;
bless \%args, $class;
}

sub check { 1 }

1;
Loading

0 comments on commit fb4d4f0

Please sign in to comment.