From 981918e859dfff1df78824976f6164eaecbd8ae5 Mon Sep 17 00:00:00 2001 From: kobaken Date: Mon, 25 Nov 2024 06:50:02 +0900 Subject: [PATCH 1/3] Move tests --- .../Data-Checks/TestDataChecks.pm | 7 ++++ .../{Data-Checks.t => Data-Checks/basic.t} | 7 ++-- .../basic.t} | 2 +- t/10-integration/Moo/TestMoo.pm | 5 +++ t/10-integration/{Moo.t => Moo/basic.t} | 7 ++-- t/10-integration/Moose/TestMoose.pm | 7 ++++ t/10-integration/{Moose.t => Moose/basic.t} | 7 ++-- .../MooseX-Types/TestMooseXTypes.pm | 7 ++++ .../{MooseX-Types.t => MooseX-Types/basic.t} | 7 ++-- t/10-integration/Mouse/TestMouse.pm | 7 ++++ t/10-integration/{Mouse.t => Mouse/basic.t} | 7 ++-- t/10-integration/Specio/TestSpecio.pm | 7 ++++ t/10-integration/{Specio.t => Specio/basic.t} | 7 ++-- t/10-integration/Type-Tiny/TestTypeTiny.pm | 7 ++++ .../{Type-Tiny.t => Type-Tiny/basic.t} | 7 ++-- t/10-integration/Valiant.t | 34 ------------------- t/10-integration/Valiant/LocalPerson.pm | 15 ++++++++ t/10-integration/Valiant/TestValiant.pm | 6 ++++ t/10-integration/Valiant/basic.t | 21 ++++++++++++ 19 files changed, 119 insertions(+), 55 deletions(-) create mode 100644 t/10-integration/Data-Checks/TestDataChecks.pm rename t/10-integration/{Data-Checks.t => Data-Checks/basic.t} (78%) rename t/10-integration/{Exporter-Tiny.t => Exporter-Tiny/basic.t} (94%) create mode 100644 t/10-integration/Moo/TestMoo.pm rename t/10-integration/{Moo.t => Moo/basic.t} (82%) create mode 100644 t/10-integration/Moose/TestMoose.pm rename t/10-integration/{Moose.t => Moose/basic.t} (67%) create mode 100644 t/10-integration/MooseX-Types/TestMooseXTypes.pm rename t/10-integration/{MooseX-Types.t => MooseX-Types/basic.t} (66%) create mode 100644 t/10-integration/Mouse/TestMouse.pm rename t/10-integration/{Mouse.t => Mouse/basic.t} (67%) create mode 100644 t/10-integration/Specio/TestSpecio.pm rename t/10-integration/{Specio.t => Specio/basic.t} (70%) create mode 100644 t/10-integration/Type-Tiny/TestTypeTiny.pm rename t/10-integration/{Type-Tiny.t => Type-Tiny/basic.t} (73%) delete mode 100644 t/10-integration/Valiant.t create mode 100644 t/10-integration/Valiant/LocalPerson.pm create mode 100644 t/10-integration/Valiant/TestValiant.pm create mode 100644 t/10-integration/Valiant/basic.t diff --git a/t/10-integration/Data-Checks/TestDataChecks.pm b/t/10-integration/Data-Checks/TestDataChecks.pm new file mode 100644 index 0000000..fcd7477 --- /dev/null +++ b/t/10-integration/Data-Checks/TestDataChecks.pm @@ -0,0 +1,7 @@ +package TestDataChecks; + +use Data::Checks qw(StrEq); + +use kura Foo => StrEq('foo'); + +1; diff --git a/t/10-integration/Data-Checks.t b/t/10-integration/Data-Checks/basic.t similarity index 78% rename from t/10-integration/Data-Checks.t rename to t/10-integration/Data-Checks/basic.t index cc4b076..bbd1c38 100644 --- a/t/10-integration/Data-Checks.t +++ b/t/10-integration/Data-Checks/basic.t @@ -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'); diff --git a/t/10-integration/Exporter-Tiny.t b/t/10-integration/Exporter-Tiny/basic.t similarity index 94% rename from t/10-integration/Exporter-Tiny.t rename to t/10-integration/Exporter-Tiny/basic.t index e468f93..f6ba75b 100644 --- a/t/10-integration/Exporter-Tiny.t +++ b/t/10-integration/Exporter-Tiny/basic.t @@ -3,7 +3,7 @@ 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"; subtest 'Test `kura` with Exporter::Tiny' => sub { use mykura Foo => sub { $_ eq 'foo' }; diff --git a/t/10-integration/Moo/TestMoo.pm b/t/10-integration/Moo/TestMoo.pm new file mode 100644 index 0000000..3d05315 --- /dev/null +++ b/t/10-integration/Moo/TestMoo.pm @@ -0,0 +1,5 @@ +package TestMoo; + +use kura Foo => sub { ($_[0]||'') eq 'foo' }; + +1; diff --git a/t/10-integration/Moo.t b/t/10-integration/Moo/basic.t similarity index 82% rename from t/10-integration/Moo.t rename to t/10-integration/Moo/basic.t index 3b9edde..5d0512b 100644 --- a/t/10-integration/Moo.t +++ b/t/10-integration/Moo/basic.t @@ -2,9 +2,12 @@ use Test2::V0; use Test2::Require::Module 'Moo', '2.005005'; use Test2::Require::Module 'Type::Tiny', '2.000000'; -subtest 'Test `kura` with Moo' => sub { - use kura Foo => sub { $_[0] eq 'foo' }; +use FindBin qw($Bin); +use lib "$Bin"; + +use TestMoo qw(Foo); +subtest 'Test `kura` with Moo' => sub { # Moo accepts Type::Tiny isa_ok Foo, 'Type::Tiny'; diff --git a/t/10-integration/Moose/TestMoose.pm b/t/10-integration/Moose/TestMoose.pm new file mode 100644 index 0000000..2bd24b3 --- /dev/null +++ b/t/10-integration/Moose/TestMoose.pm @@ -0,0 +1,7 @@ +package TestMoose; + +use Moose::Util::TypeConstraints; + +use kura Foo => subtype 'Name', as 'Str', where { length $_ > 0 }; + +1; diff --git a/t/10-integration/Moose.t b/t/10-integration/Moose/basic.t similarity index 67% rename from t/10-integration/Moose.t rename to t/10-integration/Moose/basic.t index 04ffeb1..309b732 100644 --- a/t/10-integration/Moose.t +++ b/t/10-integration/Moose/basic.t @@ -1,11 +1,12 @@ use Test2::V0; use Test2::Require::Module 'Moose', '2.2207'; -use Moose::Util::TypeConstraints; +use FindBin qw($Bin); +use lib "$Bin"; -subtest 'Test `kura` with Moose' => sub { - use kura Foo => subtype 'Name', as 'Str', where { length $_ > 0 }; +use TestMoose qw(Foo); +subtest 'Test `kura` with Moose' => sub { isa_ok Foo, 'Moose::Meta::TypeConstraint'; ok !Foo->check(''); diff --git a/t/10-integration/MooseX-Types/TestMooseXTypes.pm b/t/10-integration/MooseX-Types/TestMooseXTypes.pm new file mode 100644 index 0000000..1de434b --- /dev/null +++ b/t/10-integration/MooseX-Types/TestMooseXTypes.pm @@ -0,0 +1,7 @@ +package TestMooseXTypes; + +use MooseX::Types::Moose qw( Str ); + +use kura Foo => Str->create_child_type(constraint => sub { length $_ > 0 }); + +1; diff --git a/t/10-integration/MooseX-Types.t b/t/10-integration/MooseX-Types/basic.t similarity index 66% rename from t/10-integration/MooseX-Types.t rename to t/10-integration/MooseX-Types/basic.t index c80c1a4..4e8c11d 100644 --- a/t/10-integration/MooseX-Types.t +++ b/t/10-integration/MooseX-Types/basic.t @@ -1,11 +1,12 @@ use Test2::V0; use Test2::Require::Module 'MooseX::Types', '0.50'; -use MooseX::Types::Moose qw( Str ); +use FindBin qw($Bin); +use lib "$Bin"; -subtest 'Test `kura` with MooseX::Types' => sub { - use kura Foo => Str->create_child_type(constraint => sub { length $_ > 0 }); +use TestMooseXTypes qw(Foo); +subtest 'Test `kura` with MooseX::Types' => sub { isa_ok Foo, 'Moose::Meta::TypeConstraint'; ok !Foo->check(''); diff --git a/t/10-integration/Mouse/TestMouse.pm b/t/10-integration/Mouse/TestMouse.pm new file mode 100644 index 0000000..8800fa2 --- /dev/null +++ b/t/10-integration/Mouse/TestMouse.pm @@ -0,0 +1,7 @@ +package TestMouse; + +use Mouse::Util::TypeConstraints; + +use kura Foo => subtype 'Name', as 'Str', where { length $_ > 0 }; + +1; diff --git a/t/10-integration/Mouse.t b/t/10-integration/Mouse/basic.t similarity index 67% rename from t/10-integration/Mouse.t rename to t/10-integration/Mouse/basic.t index 76fb952..e4d2b61 100644 --- a/t/10-integration/Mouse.t +++ b/t/10-integration/Mouse/basic.t @@ -1,11 +1,12 @@ use Test2::V0; use Test2::Require::Module 'Mouse', 'v2.5.11'; -use Mouse::Util::TypeConstraints; +use FindBin qw($Bin); +use lib "$Bin"; -subtest 'Test `kura` with Mouse' => sub { - use kura Foo => subtype 'Name', as 'Str', where { length $_ > 0 }; +use TestMouse qw(Foo); +subtest 'Test `kura` with Mouse' => sub { isa_ok Foo, 'Mouse::Meta::TypeConstraint'; ok !Foo->check(''); diff --git a/t/10-integration/Specio/TestSpecio.pm b/t/10-integration/Specio/TestSpecio.pm new file mode 100644 index 0000000..b094e98 --- /dev/null +++ b/t/10-integration/Specio/TestSpecio.pm @@ -0,0 +1,7 @@ +package TestSpecio; + +use Specio::Declare; + +use kura Foo => declare 'Name', where => sub { length $_[0] > 0 }; + +1; diff --git a/t/10-integration/Specio.t b/t/10-integration/Specio/basic.t similarity index 70% rename from t/10-integration/Specio.t rename to t/10-integration/Specio/basic.t index cccd699..01144df 100644 --- a/t/10-integration/Specio.t +++ b/t/10-integration/Specio/basic.t @@ -1,11 +1,12 @@ use Test2::V0; use Test2::Require::Module 'Specio', '0.48'; -use Specio::Declare; +use FindBin qw($Bin); +use lib "$Bin"; -subtest 'Test `kura` with Specio' => sub { - use kura Foo => declare 'Name', where => sub { length $_[0] > 0 }; +use TestSpecio qw(Foo); +subtest 'Test `kura` with Specio' => sub { isa_ok Foo, 'Specio::Constraint::Simple'; ok !Foo->check(''); diff --git a/t/10-integration/Type-Tiny/TestTypeTiny.pm b/t/10-integration/Type-Tiny/TestTypeTiny.pm new file mode 100644 index 0000000..843fa51 --- /dev/null +++ b/t/10-integration/Type-Tiny/TestTypeTiny.pm @@ -0,0 +1,7 @@ +package TestTypeTiny; + +use Types::Standard qw(Str); + +use kura Foo => Str & sub { length $_ > 0 }; + +1; diff --git a/t/10-integration/Type-Tiny.t b/t/10-integration/Type-Tiny/basic.t similarity index 73% rename from t/10-integration/Type-Tiny.t rename to t/10-integration/Type-Tiny/basic.t index a56a3dd..9806493 100644 --- a/t/10-integration/Type-Tiny.t +++ b/t/10-integration/Type-Tiny/basic.t @@ -1,11 +1,12 @@ use Test2::V0; use Test2::Require::Module 'Type::Tiny', '2.000000'; -use Types::Standard -types; +use FindBin qw($Bin); +use lib "$Bin"; -subtest 'Test `kura` with Type::Tiny' => sub { - use kura Foo => Str & sub { length $_ > 0 }; +use TestTypeTiny qw(Foo); +subtest 'Test `kura` with Type::Tiny' => sub { isa_ok Foo, 'Type::Tiny'; ok !Foo->check(''); diff --git a/t/10-integration/Valiant.t b/t/10-integration/Valiant.t deleted file mode 100644 index 0ebfdad..0000000 --- a/t/10-integration/Valiant.t +++ /dev/null @@ -1,34 +0,0 @@ -use Test2::V0; -use Test2::Require::Module 'Valiant', '0.002004'; -use Test2::Require::Module 'Type::Tiny', '2.000000'; - -package Local::Person { - use Moo; - use Valiant::Validations; - use Valiant::Filters; - - has name => (is=>'ro'); - - validates name => ( - length => { - maximum => 10, - minimum => 3, - } - ) -} - -use Types::Standard qw(InstanceOf); - -subtest 'Test `kura` with Valiant' => sub { - use kura ValidLocalPerson => InstanceOf['Local::Person'] & sub { $_->valid }; - - isa_ok ValidLocalPerson, 'Type::Tiny'; - - my $person1 = Local::Person->new(name=>'foo'); - my $person2 = Local::Person->new(name=>'too long naaaaaaame'); - - ok ValidLocalPerson->check($person1); - ok !ValidLocalPerson->check($person2); -}; - -done_testing; diff --git a/t/10-integration/Valiant/LocalPerson.pm b/t/10-integration/Valiant/LocalPerson.pm new file mode 100644 index 0000000..16c6fc5 --- /dev/null +++ b/t/10-integration/Valiant/LocalPerson.pm @@ -0,0 +1,15 @@ +package LocalPerson; +use Moo; +use Valiant::Validations; +use Valiant::Filters; + +has name => (is=>'ro'); + +validates name => ( + length => { + maximum => 10, + minimum => 3, + } +); + +1; diff --git a/t/10-integration/Valiant/TestValiant.pm b/t/10-integration/Valiant/TestValiant.pm new file mode 100644 index 0000000..0761faa --- /dev/null +++ b/t/10-integration/Valiant/TestValiant.pm @@ -0,0 +1,6 @@ +package TestValiant; + +use Types::Standard qw(InstanceOf); +use kura ValidLocalPerson => InstanceOf['LocalPerson'] & sub { $_->valid }; + +1; diff --git a/t/10-integration/Valiant/basic.t b/t/10-integration/Valiant/basic.t new file mode 100644 index 0000000..b3e0bf9 --- /dev/null +++ b/t/10-integration/Valiant/basic.t @@ -0,0 +1,21 @@ +use Test2::V0; +use Test2::Require::Module 'Valiant', '0.002004'; +use Test2::Require::Module 'Type::Tiny', '2.000000'; + +use FindBin qw($Bin); +use lib "$Bin"; + +use TestValiant qw(ValidLocalPerson); +use LocalPerson; + +subtest 'Test `kura` with Valiant' => sub { + isa_ok ValidLocalPerson, 'Type::Tiny'; + + my $person1 = LocalPerson->new(name=>'foo'); + my $person2 = LocalPerson->new(name=>'too long naaaaaaame'); + + ok ValidLocalPerson->check($person1); + ok !ValidLocalPerson->check($person2); +}; + +done_testing; From 1ffabc541ffab9c1b37c2728402325c14fe3d4ac Mon Sep 17 00:00:00 2001 From: kobaken Date: Mon, 25 Nov 2024 07:00:24 +0900 Subject: [PATCH 2/3] Add test: builtin-class with kura --- .../builtin-class/TestBuiltinClass.pm | 8 ++++++++ t/10-integration/builtin-class/basic.t | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 t/10-integration/builtin-class/TestBuiltinClass.pm create mode 100644 t/10-integration/builtin-class/basic.t diff --git a/t/10-integration/builtin-class/TestBuiltinClass.pm b/t/10-integration/builtin-class/TestBuiltinClass.pm new file mode 100644 index 0000000..06879c6 --- /dev/null +++ b/t/10-integration/builtin-class/TestBuiltinClass.pm @@ -0,0 +1,8 @@ +use experimental 'class'; +class TestBuiltinClass; + +#use Exporter 'import'; + +use kura Foo => sub { length $_ > 0 }; + +1; diff --git a/t/10-integration/builtin-class/basic.t b/t/10-integration/builtin-class/basic.t new file mode 100644 index 0000000..d65172d --- /dev/null +++ b/t/10-integration/builtin-class/basic.t @@ -0,0 +1,18 @@ +use Test2::V0; +use Test2::Require::Module 'Type::Tiny', '2.000000'; +use Test2::Require::Perl 'v5.38'; + +use FindBin qw($Bin); +use lib "$Bin"; + +# Error! builtin-class @ISA is a read-only, but attempt to modify it +use TestBuiltinClass qw(Foo); + +subtest 'Test `kura` with builtin class' => sub { + isa_ok Foo, 'Type::Tiny'; + + ok !Foo->check(''); + ok Foo->check('foo'); +}; + +done_testing; From 1ce7fec4ca9e773128a784be93676f6b8c6a713b Mon Sep 17 00:00:00 2001 From: kobaken Date: Mon, 25 Nov 2024 10:03:32 +0900 Subject: [PATCH 3/3] Support to builtin class with kura, but it has to break changes: BREAKING CHANGES: - Need to put Exporter class/ manually. - Remove $EXPORTER_CLASS `@ISA` of the builtin class is a read-only, so kura failed to modify it. However, this commit makes choosing your favorite Exporter class. --- META.json | 2 +- README.md | 74 +++++---------- lib/kura.pm | 89 ++++++------------- .../Data-Checks/TestDataChecks.pm | 1 + t/10-integration/Exporter-Tiny/MyFoo.pm | 5 -- .../Exporter-Tiny/TestExporterTiny.pm | 6 ++ t/10-integration/Exporter-Tiny/basic.t | 11 +-- t/10-integration/Exporter-Tiny/mykura.pm | 15 ---- t/10-integration/Moo/TestMoo.pm | 1 + t/10-integration/Moose/TestMoose.pm | 1 + .../MooseX-Types/TestMooseXTypes.pm | 1 + t/10-integration/Mouse/TestMouse.pm | 1 + t/10-integration/Specio/TestSpecio.pm | 1 + t/10-integration/Type-Tiny/TestTypeTiny.pm | 1 + t/10-integration/Valiant/TestValiant.pm | 1 + .../builtin-class/TestBuiltinClass.pm | 4 +- t/10-integration/builtin-class/basic.t | 1 - t/99-synopsis.t | 4 + t/lib/MyFoo.pm | 2 + 19 files changed, 78 insertions(+), 143 deletions(-) delete mode 100644 t/10-integration/Exporter-Tiny/MyFoo.pm create mode 100644 t/10-integration/Exporter-Tiny/TestExporterTiny.pm delete mode 100644 t/10-integration/Exporter-Tiny/mykura.pm diff --git a/META.json b/META.json index d8c60df..7ef33a5 100644 --- a/META.json +++ b/META.json @@ -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 " ], diff --git a/README.md b/README.md index 29573b9..79c16a9 100644 --- a/README.md +++ b/README.md @@ -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' }; } @@ -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 -----------------> +--------+ @@ -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, ]; @@ -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 diff --git a/lib/kura.pm b/lib/kura.pm index 9b03259..75ff4e6 100644 --- a/lib/kura.pm +++ b/lib/kura.pm @@ -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. # @@ -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; } @@ -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; } @@ -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' }; } @@ -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, L, L, L, L and more. It can even be used with L when combined with L constraints. +Kura - means "Traditional Japanese storehouse" - stores constraints, such as L, L, L, L, L, and more. It can even be used with L when combined with L constraints. Data::Checks -----------------> +--------+ | | @@ -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 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, ]; @@ -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, L, and more. +Internally, Kura automatically adds the declared constraint to C<@EXPORT_OK>, so you just put C 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 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, 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. -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 diff --git a/t/10-integration/Data-Checks/TestDataChecks.pm b/t/10-integration/Data-Checks/TestDataChecks.pm index fcd7477..abad5c8 100644 --- a/t/10-integration/Data-Checks/TestDataChecks.pm +++ b/t/10-integration/Data-Checks/TestDataChecks.pm @@ -1,5 +1,6 @@ package TestDataChecks; +use Exporter 'import'; use Data::Checks qw(StrEq); use kura Foo => StrEq('foo'); diff --git a/t/10-integration/Exporter-Tiny/MyFoo.pm b/t/10-integration/Exporter-Tiny/MyFoo.pm deleted file mode 100644 index 9e33af3..0000000 --- a/t/10-integration/Exporter-Tiny/MyFoo.pm +++ /dev/null @@ -1,5 +0,0 @@ -package MyFoo; - -use mykura Foo => sub { $_ eq 'foo' }; - -1; diff --git a/t/10-integration/Exporter-Tiny/TestExporterTiny.pm b/t/10-integration/Exporter-Tiny/TestExporterTiny.pm new file mode 100644 index 0000000..100c823 --- /dev/null +++ b/t/10-integration/Exporter-Tiny/TestExporterTiny.pm @@ -0,0 +1,6 @@ +package TestExporterTiny; + +use parent qw(Exporter::Tiny); +use kura Foo => sub { $_ eq 'foo' }; + +1; diff --git a/t/10-integration/Exporter-Tiny/basic.t b/t/10-integration/Exporter-Tiny/basic.t index f6ba75b..57c5004 100644 --- a/t/10-integration/Exporter-Tiny/basic.t +++ b/t/10-integration/Exporter-Tiny/basic.t @@ -5,17 +5,18 @@ use Test2::Require::Module 'Type::Tiny', '2.000000'; use FindBin qw($Bin);; 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'); }; diff --git a/t/10-integration/Exporter-Tiny/mykura.pm b/t/10-integration/Exporter-Tiny/mykura.pm deleted file mode 100644 index e251eed..0000000 --- a/t/10-integration/Exporter-Tiny/mykura.pm +++ /dev/null @@ -1,15 +0,0 @@ -package mykura; -use strict; -use warnings; - -use kura (); - -sub import { - my $pkg = shift; - my $caller = caller; - - local $kura::EXPORTER_CLASS = 'Exporter::Tiny'; - kura->import_into($caller, @_); -} - -1; diff --git a/t/10-integration/Moo/TestMoo.pm b/t/10-integration/Moo/TestMoo.pm index 3d05315..42caea7 100644 --- a/t/10-integration/Moo/TestMoo.pm +++ b/t/10-integration/Moo/TestMoo.pm @@ -1,5 +1,6 @@ package TestMoo; +use Exporter 'import'; use kura Foo => sub { ($_[0]||'') eq 'foo' }; 1; diff --git a/t/10-integration/Moose/TestMoose.pm b/t/10-integration/Moose/TestMoose.pm index 2bd24b3..276a0aa 100644 --- a/t/10-integration/Moose/TestMoose.pm +++ b/t/10-integration/Moose/TestMoose.pm @@ -1,5 +1,6 @@ package TestMoose; +use Exporter 'import'; use Moose::Util::TypeConstraints; use kura Foo => subtype 'Name', as 'Str', where { length $_ > 0 }; diff --git a/t/10-integration/MooseX-Types/TestMooseXTypes.pm b/t/10-integration/MooseX-Types/TestMooseXTypes.pm index 1de434b..26fe86e 100644 --- a/t/10-integration/MooseX-Types/TestMooseXTypes.pm +++ b/t/10-integration/MooseX-Types/TestMooseXTypes.pm @@ -1,5 +1,6 @@ package TestMooseXTypes; +use Exporter 'import'; use MooseX::Types::Moose qw( Str ); use kura Foo => Str->create_child_type(constraint => sub { length $_ > 0 }); diff --git a/t/10-integration/Mouse/TestMouse.pm b/t/10-integration/Mouse/TestMouse.pm index 8800fa2..6a3a738 100644 --- a/t/10-integration/Mouse/TestMouse.pm +++ b/t/10-integration/Mouse/TestMouse.pm @@ -1,5 +1,6 @@ package TestMouse; +use Exporter 'import'; use Mouse::Util::TypeConstraints; use kura Foo => subtype 'Name', as 'Str', where { length $_ > 0 }; diff --git a/t/10-integration/Specio/TestSpecio.pm b/t/10-integration/Specio/TestSpecio.pm index b094e98..2e43177 100644 --- a/t/10-integration/Specio/TestSpecio.pm +++ b/t/10-integration/Specio/TestSpecio.pm @@ -1,5 +1,6 @@ package TestSpecio; +use Exporter 'import'; use Specio::Declare; use kura Foo => declare 'Name', where => sub { length $_[0] > 0 }; diff --git a/t/10-integration/Type-Tiny/TestTypeTiny.pm b/t/10-integration/Type-Tiny/TestTypeTiny.pm index 843fa51..b64ad63 100644 --- a/t/10-integration/Type-Tiny/TestTypeTiny.pm +++ b/t/10-integration/Type-Tiny/TestTypeTiny.pm @@ -1,5 +1,6 @@ package TestTypeTiny; +use Exporter 'import'; use Types::Standard qw(Str); use kura Foo => Str & sub { length $_ > 0 }; diff --git a/t/10-integration/Valiant/TestValiant.pm b/t/10-integration/Valiant/TestValiant.pm index 0761faa..425bcfa 100644 --- a/t/10-integration/Valiant/TestValiant.pm +++ b/t/10-integration/Valiant/TestValiant.pm @@ -1,5 +1,6 @@ package TestValiant; +use Exporter 'import'; use Types::Standard qw(InstanceOf); use kura ValidLocalPerson => InstanceOf['LocalPerson'] & sub { $_->valid }; diff --git a/t/10-integration/builtin-class/TestBuiltinClass.pm b/t/10-integration/builtin-class/TestBuiltinClass.pm index 06879c6..e0f31df 100644 --- a/t/10-integration/builtin-class/TestBuiltinClass.pm +++ b/t/10-integration/builtin-class/TestBuiltinClass.pm @@ -1,8 +1,8 @@ use experimental 'class'; -class TestBuiltinClass; -#use Exporter 'import'; +class TestBuiltinClass; +use Exporter 'import'; use kura Foo => sub { length $_ > 0 }; 1; diff --git a/t/10-integration/builtin-class/basic.t b/t/10-integration/builtin-class/basic.t index d65172d..a095a09 100644 --- a/t/10-integration/builtin-class/basic.t +++ b/t/10-integration/builtin-class/basic.t @@ -5,7 +5,6 @@ use Test2::Require::Perl 'v5.38'; use FindBin qw($Bin); use lib "$Bin"; -# Error! builtin-class @ISA is a read-only, but attempt to modify it use TestBuiltinClass qw(Foo); subtest 'Test `kura` with builtin class' => sub { diff --git a/t/99-synopsis.t b/t/99-synopsis.t index 6a37453..f7f9a98 100644 --- a/t/99-synopsis.t +++ b/t/99-synopsis.t @@ -4,21 +4,25 @@ use Test2::Require::Module 'Data::Checks', '0.09'; use Test2::Require::Module 'Moose', '2.2207'; 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' }; } diff --git a/t/lib/MyFoo.pm b/t/lib/MyFoo.pm index f887dd9..17171b9 100644 --- a/t/lib/MyFoo.pm +++ b/t/lib/MyFoo.pm @@ -6,6 +6,8 @@ push @EXPORT_OK, qw(hello); use lib 't/lib'; use MyConstraint; +use Exporter 'import'; + use kura Foo => MyConstraint->new; sub hello { 'Hello, Foo!' }