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   495 use common::sense;
  5         9  
  5         26  
5              
6 5     5   359 use Aion::Meta::Util qw//;
  5         5  
  5         78  
7 5     5   13 use Aion::Types qw/Tuple/;
  5         7  
  5         675  
8 5     5   123 use Scalar::Util qw//;
  5         8  
  5         81  
9 5     5   139 use Sub::Util qw//;
  5         114  
  5         4020  
10              
11             Aion::Meta::Util::create_getters(qw/pkg subname signature referent wrapsub/);
12              
13             sub new {
14 12     12 1 14 my $cls = shift;
15 12   33     89 bless {@_}, ref $cls || $cls;
16             }
17              
18             sub wrap_sub {
19 9     9 1 10 my ($self) = @_;
20              
21 9         32 my ($pkg, $subname, $signature, $referent) = @$self{qw/pkg subname signature referent/};
22              
23 9         15 my $args_of_meth = "Arguments of method `$subname`";
24 9         12 my $returns_of_meth = "Returns of method `$subname`";
25 9         13 my $return_of_meth = "Return of method `$subname`";
26              
27 9         29 my @signature = @$signature;
28 9         13 my $ret = pop @signature;
29              
30 9 100       131 my ($ret_array, $ret_scalar) = exists $ret->{is_wantarray}? @{$ret->{args}}: (Tuple([$ret]), $ret);
  1         2  
31              
32 9         125 my $args = Tuple(\@signature);
33              
34             my $sub = sub {
35 13     13   9711 $args->validate(\@_, $args_of_meth);
        7      
        7      
        7      
        7      
        7      
        6      
        6      
        6      
        6      
36             wantarray? do {
37 2         8 my @returns = $referent->(@_);
38 2         18 $ret_array->validate(\@returns, $returns_of_meth);
39             @returns
40 11 100       18 }: do {
  1         4  
41 9         29 my $return = $referent->(@_);
42 9         61 $ret_scalar->validate($return, $return_of_meth);
43 8         23 $return
44             }
45 9         35 };
46              
47 9         26 Sub::Util::set_prototype Sub::Util::prototype($referent), $sub;
48 9         99 Sub::Util::set_subname Sub::Util::subname($referent), $sub;
49            
50 9 50       20 *{"$pkg\::$subname"} = $sub if $subname ne '__ANON__';
  9         37  
51            
52 9         16 $self->{wrapsub} = $sub;
53 9         15 $Aion::META{$pkg}{subroutine}{$subname} = $self;
54              
55 9         35 my $key = pack "J", Scalar::Util::refaddr $sub;
56 9         16 $Aion::Isa{$key} = $self;
57 9         13 Scalar::Util::weaken $Aion::Isa{$key};
58            
59 9         25 $self
60             }
61              
62             sub compare {
63 3     3 1 5 my ($self, $subroutine) = @_;
64              
65 3 50       8 die "Requires subroutine ${\$self->name}" unless $subroutine->isa('Aion::Meta::Subroutine');
  0         0  
66              
67 3         4 my $i = 0;
68 3         41 my $signature = $subroutine->signature;
69 3         5 my $fail = 0;
70              
71 3 50       8 if(@$signature == @{$self->signature}) {
  3         34  
72 3         3 for my $type (@{$self->{signature}}) {
  3         7  
73 6         7 my $other_type = $signature->[$i++];
74 6 100       15 $fail = 1, last unless $type <= $other_type;
75             }
76             } else {
77 0         0 $fail = 1;
78             }
79              
80 3 100       18 die "Signature mismatch: ${\$self->stringify} <=> ${\$subroutine->stringify}" if $fail;
  1         3  
  1         2  
81             }
82              
83             sub stringify {
84 3     3 1 12 my ($self) = @_;
85              
86 3         11 my ($pkg, $subname) = @$self{qw/pkg subname/};
87 3         7 my $signature = join " => ", @{$self->signature};
  3         66  
88 3         18 return "$subname($signature) of $pkg";
89             }
90              
91             1;
92              
93             __END__