diff --git a/cpanfile b/cpanfile index 01c7a13..758de09 100644 --- a/cpanfile +++ b/cpanfile @@ -1,12 +1,13 @@ requires 'perl', '5.014004'; requires 'Function::Parameters', '2.000003'; -requires 'Function::Return', '0.07'; +requires 'Function::Return', '0.09'; requires 'PPR'; requires 'Keyword::Simple', '0.04'; requires 'Carp'; requires 'Class::Load'; requires 'Type::Tiny', '1.000000'; requires 'Import::Into'; +requires 'Sub::Meta', '0.08'; on 'test' => sub { requires 'Test2::V0'; diff --git a/lib/Function/Interface.pm b/lib/Function/Interface.pm index d841b11..519277d 100644 --- a/lib/Function/Interface.pm +++ b/lib/Function/Interface.pm @@ -9,10 +9,7 @@ use Carp qw(croak); use Keyword::Simple; use PPR; -use Function::Interface::Info; -use Function::Interface::Info::Function; -use Function::Interface::Info::Function::Param; -use Function::Interface::Info::Function::ReturnParam; +use Sub::Meta; sub import { my $class = shift; @@ -77,36 +74,18 @@ sub _register_info { sub info { my ($interface_package) = @_; - my $info = $metadata{$interface_package} or return undef; - - Function::Interface::Info->new( - package => $interface_package, - functions => [ map { - Function::Interface::Info::Function->new( - subname => $_->{subname}, - keyword => $_->{keyword}, - params => [ map { _make_function_param($_) } @{$_->{params}} ], - return => [ map { _make_function_return_param($_) } @{$_->{return}} ], - ) - } @{$info}], - ); -} - -sub _make_function_param { - my $param = shift; - Function::Interface::Info::Function::Param->new( - type => $param->{type}, - name => $param->{name}, - named => $param->{named}, - optional => $param->{optional}, - ) -} - -sub _make_function_return_param { - my $type = shift; - Function::Interface::Info::Function::ReturnParam->new( - type => $type, - ) + my $data = $metadata{$interface_package} or return undef; + + my @info; + for (@$data) { + push @info => Sub::Meta->new( + subname => $_->{subname}, + is_method => $_->{keyword} eq 'method' ? !!1 : !!0, + args => [ @{$_->{params}} ], + returns => { list => [ @{$_->{return}} ] }, + ); + } + return \@info; } sub _assert_valid_interface { diff --git a/lib/Function/Interface/Impl.pm b/lib/Function/Interface/Impl.pm index fa0b5c3..e2b048a 100644 --- a/lib/Function/Interface/Impl.pm +++ b/lib/Function/Interface/Impl.pm @@ -7,148 +7,72 @@ our $VERSION = "0.06"; use Class::Load qw(try_load_class is_class_loaded); use Scalar::Util qw(blessed); -use Import::Into; use B::Hooks::EndOfScope; use Function::Interface; -use Function::Parameters; -use Function::Return; +use Sub::Meta::Library; +use Import::Into; + +my %IMPL_CHECKED; + +our $ERROR_FILENAME; +our$ERROR_LINE; +sub _croak { + my ($msg) = @_; + require Carp; + @_ = sprintf "implements error: %s at %s line %s\n\tdied", $msg, $ERROR_FILENAME, $ERROR_LINE; + goto \&Carp::croak; +} sub import { my $class = shift; my @interface_packages = @_; - my ($pkg, $filename, $line) = caller; - - for (@interface_packages) { - _register_check_list($pkg, $_, $filename, $line); - } + my ($impl_package, $filename, $line) = caller; - Function::Parameters->import::into($pkg); - Function::Return->import::into($pkg); + Function::Parameters->import::into($impl_package); + Function::Return->import::into($impl_package); on_scope_end { - _check_impl(); - } -} - -our @CHECK_LIST; -my %IMPL_CHECKED; -sub _check_impl { - while (my $data = shift @CHECK_LIST) { - my ($package, $interface_package, @fl) = @$data{qw/package interface_package filename line/}; - assert_valid($package, $interface_package, @fl); - - # for Function::Interface::Types#ImplOf - $IMPL_CHECKED{$package}{$interface_package} = !!1; - } -} + local $ERROR_FILENAME = $filename; + local $ERROR_LINE = $line; -sub _register_check_list { - my ($package, $interface_package, $filename, $line) = @_; + for my $interface_package (@interface_packages) { + $class->assert_valid($impl_package, $interface_package); - push @CHECK_LIST => +{ - package => $package, - interface_package => $interface_package, - filename => $filename, - line => $line, + # for Function::Interface::Types#ImplOf + $IMPL_CHECKED{$interface_package}{$interface_package} = !!1; + } } } sub assert_valid { - my ($package, $interface_package, $filename, $line) = @_; - my @fl = ($filename, $line); + my $class = shift; + my ($package, $interface_package) = @_; { my $ok = is_class_loaded($package); - return _error("implements package is not loaded yet. required to use $package", @fl) if !$ok; + _croak("implements package is not loaded yet. required to use $package") if !$ok; } { my ($ok, $e) = try_load_class($interface_package); - return _error("cannot load interface package: $e", @fl) if !$ok; - } - - my $iinfo = info_interface($interface_package) - or return _error("cannot get interface info", @fl); - - for my $ifunction_info (@{$iinfo->functions}) { - my $fname = $ifunction_info->subname; - my $def = $ifunction_info->definition; - - my $code = $package->can($fname) - or return _error("function `$fname` is required. Interface: $def", @fl); - - my $pinfo = info_params($code) - or return _error("cannot get function `$fname` parameters info. Interface: $def", @fl); - my $rinfo = info_return($code) - or return _error("cannot get function `$fname` return info. Interface: $def", @fl); - - check_params($pinfo, $ifunction_info) - or return _error("function `$fname` is invalid parameters. Interface: $def", @fl); - check_return($rinfo, $ifunction_info) - or return _error("function `$fname` is invalid return. Interface: $def", @fl); - } -} - -sub _error { - my ($msg, $filename, $line) = @_; - die sprintf "implements error: %s at %s line %s\n\tdied", $msg, $filename, $line; -} - -sub info_interface { - my $interface_package = shift; - Function::Interface::info($interface_package) -} - -sub info_params { - my $code = shift; - Function::Parameters::info($code) -} - -sub info_return { - my $code = shift; - Function::Return::info($code) -} - -sub check_params { - my ($pinfo, $ifunction_info) = @_; - - return unless $ifunction_info->keyword eq $pinfo->keyword; - - my $params_count = 0; - for my $key (qw/positional_required positional_optional named_required named_optional/) { - my @params = $pinfo->$key; - $params_count += @params; - - for my $i (0 .. $#{$ifunction_info->$key}) { - my $ifp = $ifunction_info->$key->[$i]; - my $p = $params[$i]; - return unless check_param($p, $ifp); - } + _croak("cannot load interface package: $e") if !$ok; } - return unless $params_count == @{$ifunction_info->params}; - return !!1 -} - -sub check_param { - my ($param, $iparam) = @_; - return unless $param; - return $iparam->type eq $param->type - && $iparam->name eq $param->name -} + my $interface_info = Function::Interface::info($interface_package) + or _croak("cannot get interface info"); -sub check_return { - my ($rinfo, $ifunction_info) = @_; + for my $interface_submeta (@{$interface_info}) { + my $subname = $interface_submeta->subname; + my $code = $package->can($subname) + or _croak("function `$subname` is required."); - return unless @{$rinfo->types} == @{$ifunction_info->return}; + my $impl_submeta = Sub::Meta::Library->get($code) + or _croak("cannot get function `$subname` info."); - for my $i (0 .. $#{$ifunction_info->return}) { - my $ifr = $ifunction_info->return->[$i]; - my $type = $rinfo->types->[$i]; - return unless $ifr->type eq $type; + $interface_submeta->is_same_interface($impl_submeta) + or _croak("function `$subname` is invalid interface."); } - return !!1; } sub impl_of { @@ -172,6 +96,8 @@ Implements the interface package C: package Foo { use Function::Interface::Impl qw(IFoo); + use Function::Parameters; + use Function::Return; use Types::Standard -types; fun hello(Str $msg) :Return(Str) { @@ -186,20 +112,7 @@ Implements the interface package C: =head1 DESCRIPTION Function::Interface::Impl is for implementing interface package. -This module checks if the abstract functions are implemented at B and imports Function::Parameters and Function::Return into the implementing package. - -=head1 NOTES - -Function::Interface must be loaded B Function::Return. - -You need to call C code blocks in the following order: -1. Function::Return#CHECK (to get return info) -2. Function::Interface::Impl#CHECK (to check implements) - -C code blocks are LIFO order. -So, it is necessary to load in the following order: -1. Function::Interface::Impl -2. Function::Return +This module checks if the abstract functions are implemented at B. =head1 METHODS @@ -207,38 +120,10 @@ So, it is necessary to load in the following order: check if the interface package is implemented, otherwise die. -=head2 info_interface($interface_package) - -get the object of Function::Interface::Info. - -=head2 info_params($code) - -get the object of Function::Parameters. - -=head2 info_return($code) - -get the object of Function::Return. - -=head2 check_params($params_info, $interface_function_info) - -check if the arguments are implemented according to the interface info. - -=head2 check_param($param, $interface_param) - -check if the argument are implemented according to the interface info. - -=head2 check_return($return_info, $interface_function_info) - -check if the return types are implemented according to the interface info. - =head2 impl_of($package, $interface_package) check if specified package is an implementation of specified interface package. -=head1 SEE ALSO - -L, L - =head1 LICENSE Copyright (C) kfly8. diff --git a/lib/Function/Interface/Info.pm b/lib/Function/Interface/Info.pm deleted file mode 100644 index 1694461..0000000 --- a/lib/Function/Interface/Info.pm +++ /dev/null @@ -1,79 +0,0 @@ -package Function::Interface::Info; - -use v5.14.0; -use warnings; - -our $VERSION = "0.06"; - -sub new { - my ($class, %args) = @_; - bless { - package => $args{package}, - functions => $args{functions}, - } => $class; -} - -sub package() { $_[0]->{package} } -sub functions() { $_[0]->{functions} } - -1; -__END__ - -=encoding utf-8 - -=head1 NAME - -Function::Interface::Info - information about interface package - -=head1 SYNOPSIS - - package IFoo { - use Function::Interface; - - fun hello(Str $msg) :Return(Str); - } - - my $info = Function::Interface::info 'IFoo'; - $info->package; # IFoo - $info->functions; # [ Function::Interface::Info::Function ] - - for my $finfo (@{$info->functions}) { - $finfo->subname; # hello - $finfo->keyword; # fun - $finfo->params; # [ Function::Interface::Info::Function::Param ] - $finfo->return; # [ Function::Interface::Info::Function::ReturnParam ] - - for my $pinfo (@{$finfo->params}) { - $pinfo->type; # Str - $pinfo->name; # $msg - $pinfo->named; # false - $pinfo->optional; # false - } - - for my $rinfo (@{$rinfo->return}) { - $rinfo->type; # Str - } - } - -=head1 DESCRIPTION - -Function::Interface::info returns objects of this class to describe interface package. - -=head1 METHODS - -=head2 new - -Constructor of Function::Interface::Info. This is usually called at Function::Interface::info. - -=head2 $info->package - -Returns interface package name - -=head2 $info->functions - -Returns a list of L - -=head1 SEE ALSO - -L - diff --git a/lib/Function/Interface/Info/Function.pm b/lib/Function/Interface/Info/Function.pm deleted file mode 100644 index 8e50730..0000000 --- a/lib/Function/Interface/Info/Function.pm +++ /dev/null @@ -1,112 +0,0 @@ -package Function::Interface::Info::Function; - -use v5.14.0; -use warnings; - -our $VERSION = "0.06"; - -sub new { - my ($class, %args) = @_; - bless \%args => $class; -} - -sub subname() { $_[0]->{subname} } -sub keyword() { $_[0]->{keyword} } -sub params() { $_[0]->{params} } -sub return() { $_[0]->{return} } - -sub definition() { - my $self = shift; - - sprintf('%s %s(%s) :Return(%s)', - $self->keyword, - $self->subname, - (join ', ', map { - sprintf('%s %s%s%s', - $_->type_display_name, - $_->named ? ':' : '', - $_->name, - $_->optional ? '=' : '' - ) - } @{$self->params}), - (join ', ', map { - $_->type_display_name, - } @{$self->return}), - ); -} - -sub positional_required() { - my $self = shift; - $self->{positional_required} //= [ grep { !$_->named && !$_->optional } @{$self->params} ] -} - -sub positional_optional() { - my $self = shift; - $self->{positional_optional} //= [ grep { !$_->named && $_->optional } @{$self->params} ] -} - -sub named_required() { - my $self = shift; - $self->{named_required} //= [ grep { $_->named && !$_->optional } @{$self->params} ] -} - -sub named_optional() { - my $self = shift; - $self->{named_optional} //= [ grep { $_->named && $_->optional } @{$self->params} ] -} - -1; -__END__ - -=encoding utf-8 - -=head1 NAME - -Function::Interface::Info::Function - information about abstract function of interface package - -=head1 METHODS - -=head2 new - -Constructor of Function::Interface::Info::Function. This is usually called at Function::Interface::info. - -=head2 subname - -Returns an abstract function name - -=head2 keyword - -Returns the keyword used to define the abstract function, i.e. C or C - -=head2 params - -Returns a list of L - -=head3 positional_required - -Returns positional required params - -=head3 positional_optional - -Returns positional optional params - -=head3 named_required - -Returns named required params - -=head3 named_optional - -Returns named optional params - -=head2 return - -Returns a list of L - -=head2 definition - -Returns the abstract function declaration string. For example, "Str $msg" - -=head1 SEE ALSO - -L - diff --git a/lib/Function/Interface/Info/Function/Param.pm b/lib/Function/Interface/Info/Function/Param.pm deleted file mode 100644 index f3ae463..0000000 --- a/lib/Function/Interface/Info/Function/Param.pm +++ /dev/null @@ -1,60 +0,0 @@ -package Function::Interface::Info::Function::Param; - -use v5.14.0; -use warnings; - -our $VERSION = "0.06"; - -sub new { - my ($class, %args) = @_; - bless \%args => $class; -} - -sub type() { $_[0]->{type} } -sub name() { $_[0]->{name} } -sub optional() { !!$_[0]->{optional} } -sub named() { !!$_[0]->{named} } - -sub type_display_name() { $_[0]->type->display_name } - -1; -__END__ - -=encoding utf-8 - -=head1 NAME - -Function::Interface::Info::Function::Param - information about parameters of abstract function - -=head1 METHODS - -=head2 new - -Constructor of Function::Interface::Info::Function::Param. This is usually called at Function::Interface::info. - -=head2 name -> Str - -Returns parameter name of the abstract function, e.g. C<$msg>. - -=head2 named -> Bool - -Returns whether it is a named parameter. -For example, C is false, C is true. - -=head2 optional -> Bool - -Returns whether it is a optional parameter. -For example, C is false, C is true. - -=head2 type -> Object - -Returns type object of the parameter, e.g. C. - -=head3 type_display_name -> Str - -Returns type display name of the parameter - -=head1 SEE ALSO - -L - diff --git a/lib/Function/Interface/Info/Function/ReturnParam.pm b/lib/Function/Interface/Info/Function/ReturnParam.pm deleted file mode 100644 index f1c0041..0000000 --- a/lib/Function/Interface/Info/Function/ReturnParam.pm +++ /dev/null @@ -1,42 +0,0 @@ -package Function::Interface::Info::Function::ReturnParam; - -use v5.14.0; -use warnings; - -our $VERSION = "0.06"; - -sub new { - my ($class, %args) = @_; - bless \%args => $class; -} - -sub type() { $_[0]->{type} } -sub type_display_name() { $_[0]->type->display_name } - -1; -__END__ - -=encoding utf-8 - -=head1 NAME - -Function::Interface::Info::Function::ReturnParam - information about return values of abstract function - -=head1 METHODS - -=head2 new - -Constructor of Function::Interface::Info::Function::ReturnParam. This is usually called at Function::Interface::info. - -=head2 type -> Object - -Returns type object of the return value, e.g. C. - -=head3 type_display_name -> Str - -Returns type display name of the return value - -=head1 SEE ALSO - -L - diff --git a/t/01_function_interface/import.t b/t/01_function_interface/import.t index 4b4f569..3c2a9e3 100644 --- a/t/01_function_interface/import.t +++ b/t/01_function_interface/import.t @@ -11,7 +11,7 @@ sub optional() { !!1 } sub function_info { my $name = shift; my $info = Function::Interface::info __PACKAGE__; - my @f = grep { $_->subname eq $name } @{$info->functions}; + my @f = grep { $_->subname eq $name } @{$info}; return $f[0] } @@ -23,24 +23,24 @@ sub test { note "TEST $keyword $subname"; - is $info->keyword, $keyword, 'keyword'; + is $info->is_method, $keyword eq 'method', 'keyword'; is $info->subname, $subname, 'subname'; - for (my $i = 0; $i < @{$info->params}; $i++) { - my $p = $info->params->[$i]; + for (my $i = 0; $i < @{$info->args}; $i++) { + my $p = $info->args->[$i]; my ($type, $name, $named, $optional) = @{$params->[$i]}; - is $p->type_display_name, $type, "param $i type"; + is $p->type, $type, "param $i type"; is $p->name, $name, "param $i name"; is $p->named, $named, "param $i named"; is $p->optional, $optional, "param $i optional"; } - for (my $i = 0; $i < @{$info->return}; $i++) { - my $r = $info->return->[$i]; + for (my $i = 0; $i < @{$info->returns->list}; $i++) { + my $r = $info->returns->list->[$i]; my $type = $return->[$i]; - is $r->type_display_name, $type, "return $i type"; + is $r, $type, "return $i type"; } } diff --git a/t/01_function_interface/import_options.t b/t/01_function_interface/import_options.t index 8855c67..b4dc2fc 100644 --- a/t/01_function_interface/import_options.t +++ b/t/01_function_interface/import_options.t @@ -4,6 +4,6 @@ use Function::Interface pkg => 'MyTest'; fun foo() :Return(); my $info = Function::Interface::info 'MyTest'; -is $info->package, 'MyTest'; +ok $info; done_testing; diff --git a/t/01_function_interface/info.t b/t/01_function_interface/info.t index bb9b87c..510b78e 100644 --- a/t/01_function_interface/info.t +++ b/t/01_function_interface/info.t @@ -10,38 +10,36 @@ method baz() :Return(); subtest 'basic' => sub { my $info = Function::Interface::info __PACKAGE__; - is $info->package, 'main'; - is @{$info->functions}, 3; + is @{$info}, 3; subtest 'foo' => sub { - my $i = $info->functions->[0]; + my $i = $info->[0]; is $i->subname, 'foo'; - is $i->keyword, 'fun'; - is $i->params, []; - is $i->return, []; + ok !$i->is_method, 'fun'; + is $i->args, []; + is $i->returns->list, []; }; subtest 'bar' => sub { - my $i = $info->functions->[1]; + my $i = $info->[1]; is $i->subname, 'bar'; - is $i->keyword, 'fun'; + ok !$i->is_method, 'fun'; - is @{$i->params}, 1; - isa_ok $i->params->[0], 'Function::Interface::Info::Function::Param'; - ok $i->params->[0]->type eq Str; - is $i->params->[0]->name, '$msg'; + is @{$i->args}, 1; + isa_ok $i->args->[0], 'Sub::Meta::Param'; + ok $i->args->[0]->type eq Str; + is $i->args->[0]->name, '$msg'; - is @{$i->return}, 1; - isa_ok $i->return->[0], 'Function::Interface::Info::Function::ReturnParam'; - ok $i->return->[0]->type eq Int; + isa_ok $i->returns, 'Sub::Meta::Returns'; + ok $i->returns->list->[0], Int; }; subtest 'baz' => sub { - my $i = $info->functions->[2]; + my $i = $info->[2]; is $i->subname, 'baz'; - is $i->keyword, 'method'; - is $i->params, []; - is $i->return, []; + ok $i->is_method, 'method'; + is $i->args, []; + is $i->returns->list, []; }; }; diff --git a/t/02_function_interface_info/function.t b/t/02_function_interface_info/function.t deleted file mode 100644 index 6a429e9..0000000 --- a/t/02_function_interface_info/function.t +++ /dev/null @@ -1,89 +0,0 @@ -use Test2::V0; - -use Function::Interface::Info::Function; - -subtest 'basic' => sub { - my $info = Function::Interface::Info::Function->new( - subname => 'hello', - keyword => 'fun', - params => [], - return => [], - ); - - isa_ok $info, 'Function::Interface::Info::Function'; - is $info->subname, 'hello'; - is $info->keyword, 'fun'; - is $info->params, []; - is $info->return, []; -}; - -subtest 'definition' => sub { - is d('fun','hello', [], []), 'fun hello() :Return()'; - is d('fun','hello2', [], []), 'fun hello2() :Return()'; - is d('method','hello', [], []), 'method hello() :Return()'; - - is d('fun','hello', [ ['Str', '$msg'] ], []), 'fun hello(Str $msg) :Return()'; - is d('fun','hello', [ ['Str', '$msg'], ['Int', '$i'] ], []), 'fun hello(Str $msg, Int $i) :Return()'; - is d('fun','hello', [ ['Str', '$msg', 1] ], []), 'fun hello(Str $msg=) :Return()'; - is d('fun','hello', [ ['Str', '$msg', 0,1] ], []), 'fun hello(Str :$msg) :Return()'; - is d('fun','hello', [ ['Str', '$msg', 1,1] ], []), 'fun hello(Str :$msg=) :Return()'; - - is d('method','hello', [], ['Str']), 'method hello() :Return(Str)'; - is d('method','hello', [], ['Str', 'Int']), 'method hello() :Return(Str, Int)'; -}; - -subtest 'params' => sub { - my @params = ( - # opt named - ['Str', '$a', 0, 0], - ['Str', '$e', 1, 0], - ['Str', '$h', 0, 1], - ['Str', '$j', 1, 1], - ['Str', '$b', 0, 0], - ['Str', '$f', 1, 0], - ['Str', '$i', 0, 1], - ['Str', '$c', 0, 0], - ['Str', '$g', 1, 0], - ['Str', '$d', 0, 0], - ); - - my $info = make_info_function('fun', 'foo', \@params, []); - - is [map { $_->name } @{$info->positional_required}], ['$a', '$b', '$c', '$d']; - is [map { $_->name } @{$info->positional_optional}], ['$e', '$f', '$g']; - is [map { $_->name } @{$info->named_required}], ['$h', '$i']; - is [map { $_->name } @{$info->named_optional}], ['$j']; -}; - -sub d { make_info_function(@_)->definition } - -sub make_info_function { - my ($keyword, $subname, $params, $return) = @_; - - return Function::Interface::Info::Function->new( - subname => $subname, - keyword => $keyword, - params => [ map { mock_param($_) } @{$params} ], - return => [ map { mock_return($_) } @{$return} ], - ); -} - -sub mock_param { - my ($type, $name, $optional, $named) = @{$_[0]}; - - mock { - type_display_name => $type, - name => $name, - optional => $optional, - named => $named, - }; -} - -sub mock_return { - my ($type) = @_; - mock { - type_display_name => $type, - }; -} - -done_testing; diff --git a/t/02_function_interface_info/function/param.t b/t/02_function_interface_info/function/param.t deleted file mode 100644 index d370554..0000000 --- a/t/02_function_interface_info/function/param.t +++ /dev/null @@ -1,20 +0,0 @@ -use Test2::V0; - -use Function::Interface::Info::Function::Param; -use Types::Standard qw(Str); - -my $param = Function::Interface::Info::Function::Param->new( - type => Str, - name => '$foo', - optional => 0, - named => 0, -); - -isa_ok $param, 'Function::Interface::Info::Function::Param'; -ok $param->type eq Str; -is $param->type_display_name, Str->display_name; -is $param->name, '$foo'; -ok !$param->optional; -ok !$param->named; - -done_testing; diff --git a/t/02_function_interface_info/function/return_param.t b/t/02_function_interface_info/function/return_param.t deleted file mode 100644 index 6dc61cb..0000000 --- a/t/02_function_interface_info/function/return_param.t +++ /dev/null @@ -1,14 +0,0 @@ -use Test2::V0; - -use Function::Interface::Info::Function::ReturnParam; -use Types::Standard qw(Str); - -my $rparam = Function::Interface::Info::Function::ReturnParam->new( - type => Str, -); - -isa_ok $rparam, 'Function::Interface::Info::Function::ReturnParam'; -ok $rparam->type eq Str; -is $rparam->type_display_name, Str->display_name; - -done_testing; diff --git a/t/02_function_interface_info/info.t b/t/02_function_interface_info/info.t deleted file mode 100644 index 8e2d590..0000000 --- a/t/02_function_interface_info/info.t +++ /dev/null @@ -1,14 +0,0 @@ -use Test2::V0; - -use Function::Interface::Info; - -my $info = Function::Interface::Info->new( - package => 'IFoo', - functions => [] -); - -isa_ok $info, 'Function::Interface::Info'; -is $info->package, 'IFoo'; -is $info->functions, []; - -done_testing; diff --git a/t/03_function_interface_impl/assert_valid.t b/t/03_function_interface_impl/assert_valid.t index 334989c..1018097 100644 --- a/t/03_function_interface_impl/assert_valid.t +++ b/t/03_function_interface_impl/assert_valid.t @@ -19,8 +19,8 @@ use FooInvalidReturn; sub assert_valid { my ($package, $interface_package) = @_; - Function::Interface::Impl::assert_valid( - $package, $interface_package, __FILE__, __LINE__ + Function::Interface::Impl->assert_valid( + $package, $interface_package ); } diff --git a/t/03_function_interface_impl/case_duplicate.t b/t/03_function_interface_impl/case_duplicate.t deleted file mode 100644 index b62475e..0000000 --- a/t/03_function_interface_impl/case_duplicate.t +++ /dev/null @@ -1,24 +0,0 @@ -use Test2::V0; -our $COUNT_ASSERT_VALID; - -BEGIN { - require Function::Interface::Impl; - - no strict qw(refs); - no warnings qw(redefine); - *{Function::Interface::Impl::assert_valid} = sub { - $COUNT_ASSERT_VALID++; - } -} - -BEGIN { - is @Function::Interface::Impl::CHECK_LIST, 0; - is $COUNT_ASSERT_VALID, undef; -} - -use Function::Interface::Impl qw(IFoo); - -is @Function::Interface::Impl::CHECK_LIST, 0; -is $COUNT_ASSERT_VALID, 1; - -done_testing; diff --git a/t/03_function_interface_impl/check_params.t b/t/03_function_interface_impl/check_params.t deleted file mode 100644 index 341af8e..0000000 --- a/t/03_function_interface_impl/check_params.t +++ /dev/null @@ -1,97 +0,0 @@ -use Test2::V0; - -use Function::Parameters; -use Types::Standard -types; - -use Function::Interface::Impl; -use Function::Interface::Info::Function; -use Function::Interface::Info::Function::Param; - -sub positional() { !!0 } -sub named() { !!1 } -sub required() { !!0 } -sub optional() { !!1 } - -subtest 'basic' => sub { - - fun foo(Str $msg) { } - test(foo => ['fun', 'foo', [ [Str, '$msg', positional, required] ] ]); - - fun foo2(Str :$msg) { } - test(foo2 => ['fun', 'foo2', [ [Str, '$msg', named, required] ] ]); - - fun foo3(Str $msg=) { } - test(foo3 => ['fun', 'foo3', [ [Str, '$msg', positional, optional] ] ]); - - fun foo4(Str :$msg=) { } - test(foo4 => ['fun', 'foo4', [ [Str, '$msg', named, optional] ] ]); - - fun foo5(Str $msg, Int $i) { } - test(foo5 => ['fun', 'foo5', [ [Str, '$msg', positional, required], [Int, '$i', positional, required] ] ]); - - fun foo6() { } - test(foo6 => ['fun', 'foo6', [ ] ]); - - method foo7() { } - test(foo7 => ['method', 'foo7', [ ] ]); -}; - -subtest 'ng' => sub { - - fun bar() {} - my $bar = info(\&bar); - ok Function::Interface::Impl::check_params($bar, iinfo('fun', 'bar', [])); - ok not Function::Interface::Impl::check_params($bar, iinfo('method', 'bar', [])); - ok not Function::Interface::Impl::check_params($bar, iinfo('fun', 'bar', [ [Int, '$a', positional, required] ])); - - fun bar2(Str $msg) {} - my $bar2 = info(\&bar2); - ok Function::Interface::Impl::check_params($bar2, iinfo('fun', 'bar2', [ [Str, '$msg', positional, required] ])); - ok not Function::Interface::Impl::check_params($bar2, iinfo('fun', 'bar2', [])); - ok not Function::Interface::Impl::check_params($bar2, iinfo('method', 'bar2', [])); - ok not Function::Interface::Impl::check_params($bar2, iinfo('fun', 'bar2', [ [Int, '$msg', positional, required] ])); - ok not Function::Interface::Impl::check_params($bar2, iinfo('fun', 'bar2', [ [Str, '$smg', positional, required] ])); - ok not Function::Interface::Impl::check_params($bar2, iinfo('fun', 'bar2', [ [Str, '$msg', named, required] ])); - ok not Function::Interface::Impl::check_params($bar2, iinfo('fun', 'bar2', [ [Str, '$msg', named, optional] ])); - ok not Function::Interface::Impl::check_params($bar2, iinfo('fun', 'bar2', [ [Str, '$msg', positional, optional] ])); - - # TODO: slurpy - # fun bar3(Str $key, @values) {} - # my $bar3 = info(\&bar3); - # ok Function::Interface::Impl::check_params($bar3, iinfo('fun', 'bar3', [ [Str, '$key', positional, required] ])); -}; - -sub test { - my ($name, $expected) = @_; - - my $info = info(\&$name); - my $iinfo = iinfo(@$expected); - - ok Function::Interface::Impl::check_params($info, $iinfo); -} - -sub info { - my $code = shift; - Function::Parameters::info $code; -} - -sub iinfo { - my ($keyword, $subname, $params) = @_; - Function::Interface::Info::Function->new( - subname => $subname, - keyword => $keyword, - params => [map { iparam(@$_) } @$params], - ); -} - -sub iparam { - my ($type, $name, $named, $optional) = @_; - Function::Interface::Info::Function::Param->new( - type => $type, - name => $name, - named => $named, - optional => $optional, - ); -} - -done_testing; diff --git a/t/03_function_interface_impl/check_return.t b/t/03_function_interface_impl/check_return.t deleted file mode 100644 index a0374c2..0000000 --- a/t/03_function_interface_impl/check_return.t +++ /dev/null @@ -1,52 +0,0 @@ -use Test2::V0; - -use Function::Return; -use Types::Standard -types; - -use Function::Interface::Impl; -use Function::Interface::Info::Function; -use Function::Interface::Info::Function::ReturnParam; - -subtest 'empty return' => sub { - sub foo :Return() { } - ok check_return(\&foo, []); - ok not check_return(\&foo, [Str]); -}; - -subtest 'single return' => sub { - sub foo2 :Return(Str) { } - ok check_return(\&foo2, [Str]); - ok not check_return(\&foo2, []); - ok not check_return(\&foo2, [Int]); -}; - -subtest 'two return' => sub { - sub foo3 :Return(Str, Int) { } - ok check_return(\&foo3, [Str, Int]); - ok not check_return(\&foo3, []); - ok not check_return(\&foo3, [Str]); - ok not check_return(\&foo3, [Str, Int, Num]); - ok not check_return(\&foo3, [Str, Str]); - ok not check_return(\&foo3, [Int, Int]); - ok not check_return(\&foo3, [Int, Str]); -}; - -sub check_return { - my ($code, $types) = @_; - - my $rinfo = Function::Return::info($code); - my $iinfo = iinfo($types); - - Function::Interface::Impl::check_return($rinfo, $iinfo); -} - -sub iinfo { - my ($types) = @_; - Function::Interface::Info::Function->new( - return => [ - map { Function::Interface::Info::Function::ReturnParam->new( type => $_ ) } @$types - ] - ); -} - -done_testing; diff --git a/t/03_function_interface_impl/error.t b/t/03_function_interface_impl/error.t deleted file mode 100644 index 24bf74a..0000000 --- a/t/03_function_interface_impl/error.t +++ /dev/null @@ -1,9 +0,0 @@ -use Test2::V0; - -use Function::Interface::Impl; - -like dies { - Function::Interface::Impl::_error('some message', 'Foo.pm', 3); -}, qr/implements error: some message at Foo.pm line 3\n/; - -done_testing; diff --git a/t/03_function_interface_impl/import.t b/t/03_function_interface_impl/import.t deleted file mode 100644 index e382c46..0000000 --- a/t/03_function_interface_impl/import.t +++ /dev/null @@ -1,8 +0,0 @@ -use Test2::V0; - -use Function::Interface::Impl; - -ok $INC{'Function/Parameters.pm'}, 'loaded Function::Parameters'; -ok $INC{'Function/Return.pm'}, 'loaded Function::Return'; - -done_testing; diff --git a/t/03_function_interface_impl/info_interface.t b/t/03_function_interface_impl/info_interface.t deleted file mode 100644 index ce408e0..0000000 --- a/t/03_function_interface_impl/info_interface.t +++ /dev/null @@ -1,25 +0,0 @@ -use Test2::V0; - -package ITest; - -use Function::Interface; -fun hello() :Return(); - - -package main; - -use Function::Interface::Impl; - -my $info = Function::Interface::Impl::info_interface 'ITest'; -isa_ok $info, 'Function::Interface::Info'; -is $info->package, 'ITest'; -is $info->functions, [ - Function::Interface::Info::Function->new( - subname => 'hello', - keyword => 'fun', - params => [], - return => [], - ) -]; - -done_testing; diff --git a/t/03_function_interface_impl/info_params.t b/t/03_function_interface_impl/info_params.t deleted file mode 100644 index 4b23d1f..0000000 --- a/t/03_function_interface_impl/info_params.t +++ /dev/null @@ -1,16 +0,0 @@ -use Test2::V0; - -use Function::Interface::Impl; -use Function::Parameters; -fun hello() {} - -my $info = Function::Interface::Impl::info_params \&hello; - -isa_ok $info, 'Function::Parameters::Info'; -is $info->keyword, 'fun'; -is [$info->positional_required], []; -is [$info->positional_optional], []; -is [$info->named_required], []; -is [$info->named_optional], []; - -done_testing; diff --git a/t/03_function_interface_impl/info_return.t b/t/03_function_interface_impl/info_return.t deleted file mode 100644 index 7fe6a87..0000000 --- a/t/03_function_interface_impl/info_return.t +++ /dev/null @@ -1,12 +0,0 @@ -use Test2::V0; - -use Function::Interface::Impl; -use Function::Return; -sub hello :Return() {} - -my $info = Function::Interface::Impl::info_return \&hello; - -isa_ok $info, 'Function::Return::Info'; -is $info->types, []; - -done_testing; diff --git a/t/03_function_interface_impl/register_check_list.t b/t/03_function_interface_impl/register_check_list.t deleted file mode 100644 index 288fd81..0000000 --- a/t/03_function_interface_impl/register_check_list.t +++ /dev/null @@ -1,15 +0,0 @@ -use Test2::V0; - -use Function::Interface::Impl; - -Function::Interface::Impl::_register_check_list('Foo', 'IFoo', 'Foo.pm', 3); - -is @Function::Interface::Impl::CHECK_LIST, 1; -is $Function::Interface::Impl::CHECK_LIST[0], { - package => 'Foo', - interface_package => 'IFoo', - filename => 'Foo.pm', - line => 3, -}; - -done_testing;