DEV Community

Cover image for Released 'kura' - Store constraints for Data::Checks, Type::Tiny, Moose and more.
kobaken
kobaken

Posted on

Released 'kura' - Store constraints for Data::Checks, Type::Tiny, Moose and more.

Perl offers several libraries for managing type constraints, such as Data::Checks, Type::Tiny, and Moose. In large projects, you might encounter a mix of different type constraints, reflecting the codebase’s evolution over time. Furthermore, recent Perl versions have introduced projects like Corinna, which focuses on class features, and Oshun, which deals with value checking (with Data::Checks being a prototype from this project). Given these developments, I believed it would be useful to manage multiple type constraints through a unified interface, simplifying the process of staying up-to-date with Perl’s advancements.

To address this, I have released Kura, a tool designed to store and retrieve various type constraints from libraries like Data::Checks, Type::Tiny, and Moose in one central location. “Kura” is the Japanese word for a traditional storehouse.

Data::Checks -----------------> +--------+
                                |        |
Type::Tiny -------------------> |        |
                                |  Kura  | ---> Named Value Constraints!
Moose::Meta::TypeConstraint --> |        |
                                |        |
YourFavoriteConstraint -------> +--------+
Enter fullscreen mode Exit fullscreen mode

The following code is synopsis:

package MyFoo {
    use Data::Checks qw(StrEq);
    use kura Foo => StrEq('foo');
}

package MyBar {
    use Types::Standard -types;
    use kura Bar => Str & sub { $_[0] eq 'bar' };
}

package MyBaz {
    use Moose::Util::TypeConstraints;
    use kura Baz => subtype as 'Str' => where { $_[0] eq 'baz' };
}

package MyQux {
    use kura Qux => sub { $_[0] eq 'qux' };
}

use MyFoo qw(Foo);
use MyBar qw(Bar);
use MyBaz qw(Baz);
use MyQux qw(Qux); # CodeRef converted to Type::Tiny

ok  Foo->check('foo') && !Foo->check('bar') && !Foo->check('baz') && !Foo->check('qux');
ok !Bar->check('foo') &&  Bar->check('bar') && !Bar->check('baz') && !Bar->check('qux');
ok !Baz->check('foo') && !Baz->check('bar') &&  Baz->check('baz') && !Baz->check('qux');
ok !Qux->check('foo') && !Qux->check('bar') && !Qux->check('baz') &&  Qux->check('qux');
Enter fullscreen mode Exit fullscreen mode

And the next code show how to use it. If you mentally replace use kura with type, it should read similarly to type declarations in statically typed languages😁

package MyFoo {
   use Types::Standard -types;

   use kura Name  => Str & sub { qr/^[A-Z][a-z]+$/ };
   use kura Level => Int & sub { $_[0] >= 1 && $_[0] <= 100 };

   use kura Charactor => Dict[
      name  => Name,
      level => Level,
   ];
}

package main;
use MyFoo qw(Charactor);

Charactor->check({ name => 'Alice', level => 50 });
Enter fullscreen mode Exit fullscreen mode

Happy Hacking!

https://metacpan.org/release/KFLY/kura-0.01/view/lib/kura.pm

Top comments (3)

Collapse
 
thibaultduponchelle profile image
Tib

👍
How you managed to do that?
In particular I don’t see definition of a check sub in the Kura module?

Collapse
 
kfly8 profile image
kobaken

Constraints code is stored in the caller's @EXPORT_OK.
Below is the relevant code. Does this answer your question?

metacpan.org/release/KFLY/kura-0.0...

    my $code = _constraint_to_code(@_);

    {
        no strict "refs";
        *{"$caller\::$name"} = Sub::Util::set_subname( "$caller\::$name", $code);
        push @{"$caller\::EXPORT_OK"}, $name;
    }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
thibaultduponchelle profile image
Tib

Yes, totally. Thank you