File Coverage

blib/lib/HO/class.pm
Criterion Covered Total %
statement 92 97 94.8
branch 13 14 92.8
condition 3 5 60.0
subroutine 15 17 88.2
pod n/a
total 123 133 92.4


line stmt bran cond sub pod time code
1             package HO::class;
2             # ****************
3 13     13   538122 use strict; use warnings;
  13     13   75  
  13         324  
  13         59  
  13         17  
  13         8927  
4             our $VERSION='0.079';
5             # *******************
6              
7             ; require HO::accessor
8             ; require Carp
9              
10             ; our (%mixin_classes,%class_args,%class_methods)
11              
12             ; sub import
13 31     31   3427 { my ($package,@args)=@_
14 31         47 ; our (%mixin_classes,%class_args,%class_methods)
15 31         54 ; my $makeconstr = 1
16             ; # uncoverable branch false
17             # uncoverable condition right
18             # uncoverable condition false
19 31   66     153 my $class = $HO::accessor::class ||
20             CORE::caller # uncoverable statement
21             ; my @acc # all internal accessors
22 31         137 ; my @methods # method changeable on a per object base
23             ; my @lvalue # lvalue accessor
24 31         0 ; my @r_ # common accessors
25 31         0 ; my $makeinit # key for init method or subref used as init
  31         0  
26             ; my @alias
27              
28 31         0 ; $class_methods{$class} = {}
  31         75  
29 31         84 ; $class_args{$class} = [ @args ]
30 31 100       95 ; if($mixin_classes{$class})
31 1         2 { push @args, @{$mixin_classes{$class}}
  1         4  
32             }
33              
34 31         72 ; while(@args)
35 43         111 { my $action = lc(shift @args)
36 43         67 ; my ($name,$type,$code)
37             ;({ '_method' => sub
38 4     4   11 { ($name,$code) = splice(@args,0,2)
39 4         23 ; push @acc, "__$name",sub { $code } if defined $code
  7         16  
40 4         10 ; push @acc, "_$name",'$'
41 4         39 ; push @methods, $name, $code
42             }
43             , '_index' => sub
44 3     3   11 { ($name,$type) = splice(@args,0,2)
45 3         41 ; push @acc, $name, $type
46             }
47             , '_lvalue' => sub
48 1     1   3 { ($name,$type) = splice(@args,0,2)
49 1         3 ; push @acc, "_$name", $type
50 1         10 ; push @lvalue, $name
51             }
52             , '_rw' => sub
53 12     12   36 { ($name,$type) = splice(@args,0,2)
54 12         36 ; push @acc, "_$name", $type
55 12 100       68 ; if(defined($args[0]) && lc($args[0]) eq 'abstract')
56             { shift @args
57 1         11 }
58             else
59 11         31 { $type = _type_of($type) if ref($type) eq 'CODE'
60 11         25 ; my $coderef = $HO::accessor::rw_accessor{$type}
61 11         33 ; Carp::croak("Unknown property type '$type', in setup for class $class.")
62             unless defined $coderef
63 11         161 ; push @r_, $name => [ $coderef, $name, $class ]
64             }
65             }
66             , '_ro' => sub
67 17     17   47 { ($name,$type) = splice(@args,0,2)
68 17         56 ; push @acc, "_$name", $type
69             # abstract is similar to _index, but there is TIMTOWTDI
70 17 100       87 ; if(defined($args[0]) && lc($args[0]) eq 'abstract')
71             { shift @args
72 1         14 }
73             else
74 16         47 { $type = _type_of($type) if ref($type) eq 'CODE'
75 16         29 ; my $coderef = $HO::accessor::ro_accessor{$type}
76 16         236 ; Carp::croak("Unknown property type '$type', in setup for class $class.")
77             unless defined $coderef
78 15         209 ; push @r_, $name => [ $coderef, $name, $class ]
79             }
80             }
81             , 'init' => sub
82 3     3   28 { $makeinit = shift @args
83             }
84             # no actions => options
85             , 'noconstructor' => sub
86 2     2   23 { $makeconstr = 0
87             }
88             , 'alias' => sub
89 1     1   16 { push @alias, splice(@args,0,2)
90             }
91 0     0   0 }->{$action}||sub { die "Unknown action '$action' for $package."
92 43   50     712 })->()
93             }
94 30         48 ; { local $HO::accessor::class = $class
  30         44  
95 30         130 ; import HO::accessor:: (\@acc,\@methods,$makeinit,$makeconstr)
96             }
97              
98 13         6285 ; { no strict 'refs'
  29         48  
99 13     13   108 ; while(@methods)
  13         44  
  29         76  
100 4         10 { my ($name,$code) = splice(@methods,0,2)
101              
102 4         10 ; my ($nidx,$ncdx) = ("_$name","__$name")
103 4         9 ; my $idx = HO::accessor::_value_of($class, $nidx)
104 4         8 ; my $cdx = HO::accessor::_value_of($class, $ncdx)
105              
106 4 50       10 ; if(defined $cdx)
107 4         16 { *{join('::',$class,$name)} = sub
108 6     6   510 { my $self = shift
109 6 100       20 ; return $self->[$idx]
110             ? $self->[$idx]->($self,@_)
111             : $self->[$cdx]->($self,@_)
112             }
113 4         11 }
114             else
115 0         0 { *{join('::',$class,$name)} = sub
116 0     0   0 { my $self = shift
117 0         0 ; return $self->[$idx]->($self,@_)
118             }
119 0         0 }
120 4         20 ; $class_methods{$class}{$name} = "_method"
121             }
122              
123 29         64 ; while(@lvalue)
124 1         1 { my $name = shift(@lvalue)
125 1         2 ; my $acc = "_$name"
126             # lvalue methods are inherited not copied, so they needs to have dynamic index
127 1         4 ; *{join('::',$class,$name)} = sub : lvalue
128 1     1   2 { my $self = shift();
129 1         5 ; $self->[$self->$acc]
130             }
131 1         2 ; $class_methods{$class}{$name} = "_lvalue"
  1         2  
132             }
133 29         121 ; while(my ($name,$subdata) = splice(@r_,0,2))
134 25         53 { my ($coderef,$name,$class) = @$subdata
135 25         64 ; *{join('::',$class,$name)} = $coderef->($name,$class)
  24         120  
136 24         142 ; $class_methods{$class}{$name} = "_data"
137             }
138 28         10707 ; while(my ($new,$subname) = splice(@alias,0,2))
139 1         2 { my $code = HO::accessor::_methods_code($class, $subname)
140 1         1 ; *{join('::',$class,$new)} = $code
  1         9  
141 1         121 ; $class_methods{$class}{$new} = "_alias"
142             }
143             }
144             }
145              
146             ; sub _type_of ($)
147 8     8   38 { my $coderef = shift
148 8         19 ; my $val = $coderef->()
149 8 100       56 ; return ref($val) eq 'HASH' ? '%' :
    100          
150             ref($val) eq 'ARRAY' ? '@' : '$'
151             }
152              
153             ; 1
154              
155             __END__