Skip to content

Commit

Permalink
Merge pull request #2 from kfly8/builtin-class-with-kura
Browse files Browse the repository at this point in the history
Support builtin class with kura
  • Loading branch information
kfly8 authored Nov 25, 2024
2 parents fa46ad7 + 1ce7fec commit 924ec61
Show file tree
Hide file tree
Showing 29 changed files with 220 additions and 195 deletions.
2 changes: 1 addition & 1 deletion META.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"abstract" : "Store constraints for Data::Checks, Type::Tiny, Moose and more.",
"abstract" : "Store constraints for Data::Checks, Type::Tiny, Moose, and more.",
"author" : [
"kobaken <[email protected]>"
],
Expand Down
74 changes: 22 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
[![Actions Status](https://github.com/kfly8/kura/actions/workflows/test.yml/badge.svg)](https://github.com/kfly8/kura/actions) [![Coverage Status](https://img.shields.io/coveralls/kfly8/kura/main.svg?style=flat)](https://coveralls.io/r/kfly8/kura?branch=main) [![MetaCPAN Release](https://badge.fury.io/pl/kura.svg)](https://metacpan.org/release/kura)
# NAME

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

# SYNOPSIS

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

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

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

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

Expand All @@ -38,7 +42,7 @@ ok !Qux->check('foo') && !Qux->check('bar') && !Qux->check('baz') && Qux->check

# DESCRIPTION

Kura - means "Traditional Japanese storehouse" - stores 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. It can even be used with [Moo](https://metacpan.org/pod/Moo) when combined with [Type::Tiny](https://metacpan.org/pod/Type%3A%3ATiny) constraints.
Kura - means "Traditional Japanese storehouse" - stores 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. It can even be used with [Moo](https://metacpan.org/pod/Moo) when combined with [Type::Tiny](https://metacpan.org/pod/Type%3A%3ATiny) constraints.

```
Data::Checks -----------------> +--------+
Expand Down Expand Up @@ -66,13 +70,13 @@ This constraint must be a any object that has a `check` method or a code referen
The following is an example of a constraint declaration:

```perl
# use Type::Tiny
use Exporter 'import';
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[
use kura Character => Dict[
name => Name,
level => Level,
];
Expand All @@ -92,71 +96,37 @@ use kura Parent => Dict[ name => Child ];

If constraints are declared in the wrong order, you might encounter errors like “Bareword not allowed.” Ensure that all dependencies are declared beforehand to prevent such issues.

## Using a constraint
## Export a constraint

You can use the declared constraint as follows:
You can export the declared constraints by your favorite Exporter package such as [Exporter](https://metacpan.org/pod/Exporter), [Exporter::Tiny](https://metacpan.org/pod/Exporter%3A%3ATiny), and more.
Internally, Kura automatically adds the declared constraint to `@EXPORT_OK`, so you just put `use Exporter 'import';` in your package:

```perl
package MyFoo {
use Exporter 'import';

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

use MyFoo qw(Foo);
Foo->check('foo'); # true
Foo->check('bar'); # false
```

Internally, Kura inherits [Exporter](https://metacpan.org/pod/Exporter) and automatically adds the declared constraint to `@EXPORT_OK`:

```
MyFoo->isa('Exporter'); # true
@MyFoo::EXPORT_OK; # ('Foo')
```

So, you can add other functions to `@EXPORT_OK`:
If you forget to put `use Exporter 'import';`, you get an error like this:

```perl
package MyFoo {
our @EXPORT_OK;
push @EXPORT_OK => qw(hello);

use kura Foo => sub { $_[0] eq 'foo' };

sub hello { 'Hello, World!' }
}

use MyFoo qw(Foo hello);
hello(); # 'Hello, World!'
```

# Customizing

## `$EXPORTER_CLASS`

`$EXPORTER_CLASS` is a package name of the Exporter class, default is [Exporter](https://metacpan.org/pod/Exporter).
You can change this class by setting `$kura::EXPORTER_CLASS`.

```perl
package mykura {
use kura ();

sub import {
my $pkg = shift;
my $caller = caller;

local $kura::EXPORTER_CLASS = 'Exporter::Tiny';
kura->import_into($caller, @_);
}
}

package MyFoo {
use mykura Foo => sub { $_[0] eq 'foo' };
# use Exporter 'import'; # Forgot to load Exporter!!
use Data::Checks qw(StrEq);
use kura Foo => StrEq('foo');
}

# Exporter::Tiny accepts the `-as` option
use MyFoo Foo => { -as => 'CheckerFoo' };

CheckerFoo->check('foo'); # true
use MyFoo qw(Foo);
# => ERROR!
Attempt to call undefined import method with arguments ("Foo" ...) via package "MyFoo"
(Perhaps you forgot to load the package?)
```

# LICENSE
Expand Down
89 changes: 27 additions & 62 deletions lib/kura.pm
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ my %FORBIDDEN_NAME = map { $_ => 1 } qw{
AUTOLOAD STDIN STDOUT STDERR ARGV ARGVOUT ENV INC SIG
};

# This is a default Exporter class.
# You can change this class by setting $kura::EXPORTER_CLASS.
our $EXPORTER_CLASS = 'Exporter';

# This is a default constraint code to object.
# You can change this code by setting $kura::CALLABLE_TO_OBJECT.
#
Expand Down Expand Up @@ -52,7 +48,7 @@ sub import_into {
$err = _install_constraint($name, $constraint, $caller);
Carp::croak $err if $err;

$err = _setup_exporter($caller);
$err = _setup_inc($caller);
Carp::croak $err if $err;
}

Expand Down Expand Up @@ -112,17 +108,12 @@ sub _install_constraint {
return;
}

sub _setup_exporter {
sub _setup_inc {
my ($caller) = @_;

my $exporter_class = $EXPORTER_CLASS;

unless ($caller->isa($exporter_class)) {
no strict "refs";
push @{ "$caller\::ISA" }, $exporter_class;
( my $file = $caller ) =~ s{::}{/}g;
$INC{"$file.pm"} ||= __FILE__;
}
# Hack to make the caller package already loaded. Useful for multi-packages in a single file.
( my $file = $caller ) =~ s{::}{/}g;
$INC{"$file.pm"} ||= __FILE__;

return;
}
Expand All @@ -134,26 +125,30 @@ __END__
=head1 NAME
kura - Store constraints for Data::Checks, Type::Tiny, Moose and more.
kura - Store constraints for Data::Checks, Type::Tiny, Moose, and more.
=head1 SYNOPSIS
package MyFoo {
use Exporter 'import';
use Data::Checks qw(StrEq);
use kura Foo => StrEq('foo');
}
package MyBar {
use Exporter 'import';
use Types::Standard -types;
use kura Bar => Str & sub { $_[0] eq 'bar' };
}
package MyBaz {
use Exporter 'import';
use Moose::Util::TypeConstraints;
use kura Baz => subtype as 'Str' => where { $_[0] eq 'baz' };
}
package MyQux {
use Exporter 'import';
use kura Qux => sub { $_[0] eq 'qux' };
}
Expand All @@ -169,7 +164,7 @@ kura - Store constraints for Data::Checks, Type::Tiny, Moose and more.
=head1 DESCRIPTION
Kura - means "Traditional Japanese storehouse" - stores constraints, such as L<Data::Checks>, L<Type::Tiny>, L<Moose::Meta::TypeConstraint>, L<Mouse::Meta::TypeConstraint>, L<Specio> and more. It can even be used with L<Moo> when combined with L<Type::Tiny> constraints.
Kura - means "Traditional Japanese storehouse" - stores constraints, such as L<Data::Checks>, L<Type::Tiny>, L<Moose::Meta::TypeConstraint>, L<Mouse::Meta::TypeConstraint>, L<Specio>, and more. It can even be used with L<Moo> when combined with L<Type::Tiny> constraints.
Data::Checks -----------------> +--------+
| |
Expand All @@ -192,13 +187,13 @@ It's easy to use to store constraints in a package:
This 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:
# use Type::Tiny
use Exporter 'import';
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[
use kura Character => Dict[
name => Name,
level => Level,
];
Expand All @@ -215,64 +210,34 @@ When declaring constraints, it is important to define child constraints before t
If constraints are declared in the wrong order, you might encounter errors like “Bareword not allowed.” Ensure that all dependencies are declared beforehand to prevent such issues.
=head2 Using a constraint
=head2 Export a constraint
You can use the declared constraint as follows:
You can export the declared constraints by your favorite Exporter package such as L<Exporter>, L<Exporter::Tiny>, and more.
Internally, Kura automatically adds the declared constraint to C<@EXPORT_OK>, so you just put C<use Exporter 'import';> in your package:
package MyFoo {
use Exporter 'import';
use Data::Checks qw(StrEq);
use kura Foo => StrEq('foo');
}
use MyFoo qw(Foo);
Foo->check('foo'); # true
Foo->check('bar'); # false
Internally, Kura inherits L<Exporter> and automatically adds the declared constraint to C<@EXPORT_OK>:
MyFoo->isa('Exporter'); # true
@MyFoo::EXPORT_OK; # ('Foo')
So, you can add other functions to C<@EXPORT_OK>:
If you forget to put C<use Exporter 'import';>, you get an error like this:
package MyFoo {
our @EXPORT_OK;
push @EXPORT_OK => qw(hello);
use kura Foo => sub { $_[0] eq 'foo' };
sub hello { 'Hello, World!' }
}
use MyFoo qw(Foo hello);
hello(); # 'Hello, World!'
=head1 Customizing
=head2 C<$EXPORTER_CLASS>
C<$EXPORTER_CLASS> is a package name of the Exporter class, default is L<Exporter>.
You can change this class by setting C<$kura::EXPORTER_CLASS>.
package mykura {
use kura ();
sub import {
my $pkg = shift;
my $caller = caller;
local $kura::EXPORTER_CLASS = 'Exporter::Tiny';
kura->import_into($caller, @_);
}
}
package MyFoo {
use mykura Foo => sub { $_[0] eq 'foo' };
# use Exporter 'import'; # Forgot to load Exporter!!
use Data::Checks qw(StrEq);
use kura Foo => StrEq('foo');
}
# Exporter::Tiny accepts the `-as` option
use MyFoo Foo => { -as => 'CheckerFoo' };
CheckerFoo->check('foo'); # true
use MyFoo qw(Foo);
# => ERROR!
Attempt to call undefined import method with arguments ("Foo" ...) via package "MyFoo"
(Perhaps you forgot to load the package?)
=head1 LICENSE
Expand Down
8 changes: 8 additions & 0 deletions t/10-integration/Data-Checks/TestDataChecks.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package TestDataChecks;

use Exporter 'import';
use Data::Checks qw(StrEq);

use kura Foo => StrEq('foo');

1;
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use Test2::V0;
use Test2::Require::Module 'Data::Checks', '0.09';

use Data::Checks qw(StrEq);
use FindBin qw($Bin);
use lib "$Bin";

subtest 'Test `kura` with Data::Checks' => sub {
use kura Foo => StrEq('foo');
use TestDataChecks qw(Foo);

subtest 'Test `kura` with Data::Checks' => sub {
isa_ok Foo, 'Data::Checks::Constraint';

ok Foo->check('foo');
Expand Down
5 changes: 0 additions & 5 deletions t/10-integration/Exporter-Tiny/MyFoo.pm

This file was deleted.

6 changes: 6 additions & 0 deletions t/10-integration/Exporter-Tiny/TestExporterTiny.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package TestExporterTiny;

use parent qw(Exporter::Tiny);
use kura Foo => sub { $_ eq 'foo' };

1;
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ use Test2::Require::Module 'Exporter::Tiny', '1.006002';
use Test2::Require::Module 'Type::Tiny', '2.000000';

use FindBin qw($Bin);;
use lib "$Bin/Exporter-Tiny";
use lib "$Bin";

use TestExporterTiny qw(Foo);

# Exporter::Tiny accepts the `-as` option
use TestExporterTiny Foo => { -as => "Foo2" };

subtest 'Test `kura` with Exporter::Tiny' => sub {
use mykura Foo => sub { $_ eq 'foo' };

isa_ok __PACKAGE__, 'Exporter::Tiny';
ok +TestExporterTiny->isa('Exporter::Tiny');

ok !Foo->check('');
ok Foo->check('foo');

# Exporter::Tiny accepts the `-as` option
use MyFoo Foo => { -as => "Foo2" };

ok !Foo2->check('');
ok Foo2->check('foo');
};
Expand Down
Loading

0 comments on commit 924ec61

Please sign in to comment.