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