File Coverage

blib/lib/HO/class.pm
Criterion Covered Total %
statement 93 99 93.9
branch 14 16 87.5
condition 3 5 60.0
subroutine 15 17 88.2
pod n/a
total 125 137 91.2


line stmt bran cond sub pod time code
1             package HO::class;
2             # ****************
3 13     13   535845 use strict; use warnings;
  13     13   84  
  13         393  
  13         63  
  13         21  
  13         8808  
4             our $VERSION='0.080';
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   3575 { my ($package,@args)=@_
14 31         50 ; 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     150 my $class = $HO::accessor::class ||
20             CORE::caller # uncoverable statement
21             ; my @acc # all internal accessors
22 31         147 ; 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         74  
29 31         90 ; $class_args{$class} = [ @args ]
30 31 100       100 ; if($mixin_classes{$class})
31 1         2 { push @args, @{$mixin_classes{$class}}
  1         3  
32             }
33              
34 31         81 ; while(@args)
35 43         97 { my $action = lc(shift @args)
36 43         71 ; my ($name,$type,$code)
37             ;({ '_method' => sub
38 4     4   12 { ($name,$code) = splice(@args,0,2)
39 4         29 ; push @acc, "__$name",sub { $code } if defined $code
  7         20  
40 4         11 ; push @acc, "_$name",'$'
41 4         52 ; push @methods, $name, $code
42             }
43             , '_index' => sub
44 3     3   8 { ($name,$type) = splice(@args,0,2)
45 3         37 ; push @acc, $name, $type
46             }
47             , '_lvalue' => sub
48 1     1   3 { ($name,$type) = splice(@args,0,2)
49 1         2 ; push @acc, "_$name", $type
50 1         13 ; push @lvalue, $name
51             }
52             , '_rw' => sub
53 12     12   36 { ($name,$type) = splice(@args,0,2)
54 12         34 ; push @acc, "_$name", $type
55 12 100       67 ; if(defined($args[0]) && lc($args[0]) eq 'abstract')
56             { shift @args
57 1         10 }
58             else
59 11         31 { $type = _type_of($type) if ref($type) eq 'CODE'
60 11         28 ; my $coderef = $HO::accessor::rw_accessor{$type}
61 11         36 ; Carp::croak("Unknown property type '$type', in setup for class $class.")
62             unless defined $coderef
63 11         281 ; push @r_, $name => [ $coderef, $name, $class ]
64             }
65             }
66             , '_ro' => sub
67 17     17   47 { ($name,$type) = splice(@args,0,2)
68 17         76 ; push @acc, "_$name", $type
69             # abstract is similar to _index, but there is TIMTOWTDI
70 17 100       98 ; if(defined($args[0]) && lc($args[0]) eq 'abstract')
71             { shift @args
72 1         13 }
73             else
74 16         52 { $type = _type_of($type) if ref($type) eq 'CODE'
75 16         37 ; my $coderef = $HO::accessor::ro_accessor{$type}
76 16         237 ; Carp::croak("Unknown property type '$type', in setup for class $class.")
77             unless defined $coderef
78 15         273 ; push @r_, $name => [ $coderef, $name, $class ]
79             }
80             }
81             , 'init' => sub
82 3     3   30 { $makeinit = shift @args
83             }
84             # no actions => options
85             , 'noconstructor' => sub
86 2     2   22 { $makeconstr = 0
87             }
88             , 'alias' => sub
89 1     1   21 { push @alias, splice(@args,0,2)
90             }
91 0     0   0 }->{$action}||sub { die "Unknown action '$action' for $package."
92 43   50     742 })->()
93             }
94 30         51 ; { local $HO::accessor::class = $class
  30         48  
95 30         140 ; import HO::accessor:: (\@acc,\@methods,$makeinit,$makeconstr)
96             }
97              
98 13         6767 ; { no strict 'refs'
  29         46  
99 13     13   211 ; while(@methods)
  13         42  
  29         78  
100 4         11 { my ($name,$code) = splice(@methods,0,2)
101              
102 4         13 ; my ($nidx,$ncdx) = ("_$name","__$name")
103 4         12 ; 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         20 { *{join('::',$class,$name)} = sub
108 6     6   515 { my $self = shift
109 6 100       28 ; return $self->[$idx]
110             ? $self->[$idx]->($self,@_)
111             : $self->[$cdx]->($self,@_)
112             }
113 4         14 }
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         22 ; $class_methods{$class}{$name} = "_method"
121             }
122              
123 29         72 ; 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         10 ; *{join('::',$class,$name)} = sub : lvalue
128 1     1   2 { my $self = shift();
129 1         4 ; $self->[$self->$acc]
130             }
131 1         3 ; $class_methods{$class}{$name} = "_lvalue"
  1         4  
132             }
133 29         104 ; while(my ($name,$subdata) = splice(@r_,0,2))
134 25         51 { my ($coderef,$name,$class) = @$subdata
135 25         80 ; *{join('::',$class,$name)} = $coderef->($name,$class)
  24         133  
136 24         114 ; $class_methods{$class}{$name} = "_data"
137             }
138 28         11333 ; while(my ($new,$subname) = splice(@alias,0,2))
139 1         5 { my $code = HO::accessor::_methods_code($class, $subname)
140 1 50       10 ; unless($code)
141 0         0 { Carp::croak("Alias method ${class}::${subname} is undefined.")
142             }
143 1         3 ; *{join('::',$class,$new)} = $code
  1         6  
144 1         127 ; $class_methods{$class}{$new} = "_alias"
145             }
146             }
147             }
148              
149             ; sub _type_of ($)
150 8     8   36 { my $coderef = shift
151 8         22 ; my $val = $coderef->()
152 8 100       57 ; return ref($val) eq 'HASH' ? '%' :
    100          
153             ref($val) eq 'ARRAY' ? '@' : '$'
154             }
155              
156             ; 1
157              
158             __END__