File Coverage

blib/lib/Aion/Meta/Subroutine.pm
Criterion Covered Total %
statement 65 67 97.0
branch 11 14 78.5
condition 1 3 33.3
subroutine 19 19 100.0
pod 4 4 100.0
total 100 107 93.4


line stmt bran cond sub pod time code
1             package Aion::Meta::Subroutine;
2             # Описывает функцию с сигнатурой
3              
4 5     5   554 use common::sense;
  5         10  
  5         40  
5              
6 5     5   358 use Aion::Meta::Util qw//;
  5         24  
  5         115  
7 5     5   21 use Aion::Types qw/Tuple/;
  5         9  
  5         987  
8 5     5   33 use Scalar::Util qw//;
  5         9  
  5         103  
9 5     5   24 use Sub::Util qw//;
  5         294  
  5         5194  
10              
11             Aion::Meta::Util::create_getters(qw/pkg subname signature referent wrapsub/);
12              
13             sub new {
14 12     12 1 23 my $cls = shift;
15 12   33     127 bless {@_}, ref $cls || $cls;
16             }
17              
18             sub wrap_sub {
19 9     9 1 20 my ($self) = @_;
20              
21 9         81 my ($pkg, $subname, $signature, $referent) = @$self{qw/pkg subname signature referent/};
22              
23 9         25 my $args_of_meth = "Arguments of method `$subname`";
24 9         17 my $returns_of_meth = "Returns of method `$subname`";
25 9         16 my $return_of_meth = "Return of method `$subname`";
26              
27 9         30 my @signature = @$signature;
28 9         17 my $ret = pop @signature;
29              
30 9 100       248 my ($ret_array, $ret_scalar) = exists $ret->{is_wantarray}? @{$ret->{args}}: (Tuple([$ret]), $ret);
  1         2  
31              
32 9         264 my $args = Tuple(\@signature);
33              
34             my $sub = sub {
35 13     13   14058 $args->validate(\@_, $args_of_meth);
        7      
        7      
        7      
        7      
        7      
        6      
        6      
        6      
        6      
36             wantarray? do {
37 2         11 my @returns = $referent->(@_);
38 2         26 $ret_array->validate(\@returns, $returns_of_meth);
39             @returns
40 11 100       31 }: do {
  1         5  
41 9         36 my $return = $referent->(@_);
42 9         76 $ret_scalar->validate($return, $return_of_meth);
43 8         31 $return
44             }
45 9         61 };
46              
47 9         37 Sub::Util::set_prototype Sub::Util::prototype($referent), $sub;
48 9         161 Sub::Util::set_subname Sub::Util::subname($referent), $sub;
49            
50 9 50       33 *{"$pkg\::$subname"} = $sub if $subname ne '__ANON__';
  9         52  
51            
52 9         25 $self->{wrapsub} = $sub;
53 9         25 $Aion::META{$pkg}{subroutine}{$subname} = $self;
54              
55 9         47 my $key = pack "J", Scalar::Util::refaddr $sub;
56 9         27 $Aion::Isa{$key} = $self;
57 9         18 Scalar::Util::weaken $Aion::Isa{$key};
58            
59 9         38 $self
60             }
61              
62             sub compare {
63 3     3 1 9 my ($self, $subroutine) = @_;
64              
65 3 50       15 die "Requires subroutine ${\$self->name}" unless $subroutine->isa('Aion::Meta::Subroutine');
  0         0  
66              
67 3         7 my $i = 0;
68 3         79 my $signature = $subroutine->signature;
69 3         7 my $fail = 0;
70              
71 3 50       6 if(@$signature == @{$self->signature}) {
  3         61  
72 3         4 for my $type (@{$self->{signature}}) {
  3         29  
73 6         17 my $other_type = $signature->[$i++];
74 6 100       66 $fail = 1, last unless $type <= $other_type;
75             }
76             } else {
77 0         0 $fail = 1;
78             }
79              
80 3 100       28 die "Signature mismatch: ${\$self->stringify} <=> ${\$subroutine->stringify}" if $fail;
  1         7  
  1         3  
81             }
82              
83             sub stringify {
84 3     3 1 11 my ($self) = @_;
85              
86 3         12 my ($pkg, $subname) = @$self{qw/pkg subname/};
87 3         5 my $signature = join " => ", @{$self->signature};
  3         46  
88 3         19 return "$subname($signature) of $pkg";
89             }
90              
91             1;
92              
93             __END__