File Coverage

blib/lib/HO/accessor.pm
Criterion Covered Total %
statement 130 136 95.5
branch 56 64 87.5
condition 11 17 64.7
subroutine 19 21 90.4
pod 1 1 100.0
total 217 239 90.7


line stmt bran cond sub pod time code
1             package HO::accessor;
2             # +++++++++++++++++++
3 13     13   128552 use strict; use warnings;
  13     13   38  
  13         326  
  13         57  
  13         19  
  13         457  
4             our $VERSION='0.053';
5             # +++++++++++++++++++
6              
7             ; use Class::ISA ()
8 13     13   5043 ; use Package::Subroutine ()
  13         24806  
  13         243  
9 13     13   5455 ; use Carp ()
  13         9685  
  13         238  
10              
11 13     13   81 ; our %classes
  13         21  
  13         18000  
12             ; my %accessors
13             ; my %methods
14              
15             ; our %type = ('@'=>sub () {[]}, '%'=>sub () {{}}, '$'=>sub () {undef})
16              
17             ; our %init =
18             ( 'hash' => sub
19             { my ($self,%args) = @_
20             ; while(my ($method,$value)=each(%args))
21             { my $access = "_$method"
22             ; $self->[$self->$access] = $value
23             }
24             ; return $self
25             },
26             'hashref' => sub
27             { my ($self,$args) = @_
28             ; while(my ($method,$value)=each(%$args))
29             { my $access = "_$method"
30             ; $self->[$self->$access] = $value
31             }
32             ; return $self
33             }
34             )
35              
36             ; our %ro_accessor =
37             ( '$' => sub { my ($n,$class) = @_
38             ; my $idx = HO::accessor::_value_of($class, "_$n")
39             ; return sub ()
40 14 100   14   1967 { Carp::confess("Not a class method '$n'.")
41             unless ref($_[0])
42 13         45 ; $_[0]->[$idx]
43             }
44             }
45             , '@' => sub { my ($n,$class) = @_
46             ; my $ai = HO::accessor::_value_of($class, "_$n")
47             ; return sub
48 7     5   28 { my ($obj,$idx) = @_
49 7 100       23 ; if(@_==1)
50 7         30 { return @{$obj->[$ai]}
  4         30  
51             }
52             else
53 1         4 { return $obj->[$ai]->[$idx]
54             }
55             }}
56             , '%' => sub { my ($n,$class) = @_
57             ; my $idx = HO::accessor::_value_of($class, "_$n")
58             ; return sub
59 4     4   17 { my ($obj,$key) = @_
60 4         42 ; (@_==1) ? {%{$obj->[$idx]}}
61 4 50       19 : $obj->[$idx]->{$key}
62             }
63             }
64             )
65              
66             ; our %rw_accessor =
67             ( '$' => sub { my ($n,$class) = @_
68             ; my $idx = HO::accessor::_value_of($class, "_$n")
69             ; return sub
70 10     10   1253 { my ($obj,$val) = @_
71 10 100       36 ; Carp::confess("Not a class method '$n'.")
72             unless ref($obj)
73 9 100       40 ; return $obj->[$idx] if @_==1
74 2         4 ; $obj->[$idx] = $val
75 2         4 ; return $obj
76             }
77             }
78             , '@' => sub { my ($n,$class) = @_
79             ; my $ai = HO::accessor::_value_of($class, "_$n")
80             ; return sub
81 22     22   51 { my ($obj,$idx,$val) = @_
82 22 50       41 ; Carp::confess("Not a class method '$n'.")
83             unless ref $obj
84 22 100       52 ; if(@_==1) # get values
    100          
    50          
85             { # etwas mehr Zugriffsschutz da keine Ref
86             # einfache Anwendung in bool Kontext
87 10         10 ; return @{$obj->[$ai]}
  10         58  
88             }
89             elsif(@_ == 2)
90 4 100       9 { unless(ref $idx eq 'ARRAY')
91 1         3 { return $obj->[$ai]->[$idx] # get one index
92             }
93             else
94 3         3 { $obj->[$ai] = $idx # set complete array
95 3         7 ; return $obj
96             }
97             }
98             elsif(@_==3)
99 8 100       17 { if(ref($idx))
    100          
    100          
100 5 100       14 { if($val eq '<')
    100          
101 1         1 { $$idx = shift @{$obj->[$ai]}
  1         3  
102             }
103             elsif($val eq '>')
104 1         1 { $$idx = pop @{$obj->[$ai]}
  1         3  
105             }
106             else
107 3 100       9 { if(@$val == 0)
    100          
    50          
108 1         2 { @$idx = splice(@{$obj->[$ai]})
  1         3  
109             }
110             elsif(@$val == 1)
111 1         2 { @$idx = splice(@{$obj->[$ai]},$val->[0]);
  1         3  
112             }
113             elsif(@$val == 2)
114 1         1 { @$idx = splice(@{$obj->[$ai]},$val->[0],$val->[1]);
  1         4  
115             }
116             }
117             }
118             elsif($idx eq '<')
119 1         2 { push @{$obj->[$ai]}, $val
  1         2  
120             }
121             elsif($idx eq '>')
122 1         2 { unshift @{$obj->[$ai]}, $val
  1         3  
123             }
124             else
125 1         2 { $obj->[$ai]->[$idx] = $val # set one index
126             }
127 8         17 ; return $obj
128             }
129             }
130             }
131             , '%' => sub { my ($n,$class) = @_
132             ; my $idx = HO::accessor::_value_of($class, "_$n")
133 11     11   35 ; return sub { my ($obj,$key) = @_
134 11 100       29 ; if(@_==1)
    100          
135 5         19 { return $obj->[$idx] # for a hash an reference is easier to handle
136             }
137             elsif(@_==2)
138 5 100       11 { if(ref($key) eq 'HASH')
139 1         2 { $obj->[$idx] = $key
140 1         4 ; return $obj
141             }
142             else
143 4         15 { return $obj->[$idx]->{$key}
144             }
145             }
146             else
147 1         3 { shift(@_)
148 1         2 ; my @kv = @_
149 1         4 ; while(@kv)
150 1         2 { my ($k,$v) = splice(@kv,0,2)
151 1         4 ; $obj->[$idx]->{$k} = $v
152             }
153 1         3 ; return $obj
154             }
155             }}
156             )
157              
158             ; our $class
159              
160             ; my $object_builder = sub
161             { my ($obj,$constructor,$args) = @_
162             ; foreach my $typedefault (@$constructor)
163             { push @{$obj}, ref($typedefault) ? $typedefault->($obj,$args)
164             : $typedefault
165             }
166             }
167              
168             ; sub import
169 31     31   85 { my ($package,$ac,$methods,$init,$new) = @_
170 31         38 ; our %classes
171 31   50     70 ; $ac ||= []
172              
173 31   66     80 ; my $caller = $HO::accessor::class || CORE::caller
174              
175 31 100 66     108 ; Carp::croak "HO::accessor::import already called for class $caller."
176             if Package::Subroutine->isdefined($caller,'new') && $new
177              
178 30 100       444 ; $classes{$caller} = [] unless defined $classes{$caller}
179 30         47 ; push @{$classes{$caller}}, @$ac
  30         110  
180              
181 30         89 ; my @build = reverse Class::ISA::self_and_super_path($caller)
182             ; my @constructor
183 30         716 ; my @class_accessors
184              
185 30         46 ; my $count=0
186 30         67 ; foreach my $class (@build)
187 34 50       69 { $classes{$class} or next
188 34 100       54 ; my @acc=@{$classes{$class}} or next
  34         111  
189 22         51 ; while (@acc)
190 51         111 { my ($accessor,$type)=splice(@acc,0,2)
191 51 100       130 ; my $proto = ref($type) eq 'CODE' ? $type : $type{$type}
192 51 50       106 ; unless(ref $proto eq 'CODE')
193 0         0 { Carp::carp("Unknown property type '$type', in setup for class $caller.")
194 0     0   0 ; $proto=sub{undef}
195 0         0 }
196 51         62 ; my $val=$count
197 100     100   2558 ; my $acc=sub {$val}
198 51         149 ; push @class_accessors, $accessor
  51         86  
199 51         157 ; $accessors{$caller}{$accessor}=$acc
200 51         81 ; $constructor[$acc->()] = $proto
201 51         116 ; $count++
202             }
203             }
204             # FIXME: Die init Methode sollte Zugriff auf $self haben können.
205 13         3284 ; { no strict 'refs'
  30         45  
206 13 100   13   96 ; if($new)
  13         36  
  30         55  
207 28         106 { *{"${caller}::new"}=
208             ($init || $caller->can('init')) ?
209             sub
210 10     10   2479 { my ($self,@args)=@_
211 10   33     111 ; my $obj = bless [], ref $self || $self
212 10         34 ; $object_builder->($obj,\@constructor,\@args)
213 10         30 ; return $obj->init(@args)
214             }
215             : sub
216 20     20   9153 { my ($self,@args)=@_
217 20   66     105 ; my $obj = bless [], ref $self || $self
218 20         75 ; $object_builder->($obj,\@constructor,\@args)
219 20         61 ; return $obj
220             }
221 28 100 100     509 }
222              
223 30         67 ; foreach my $acc (@class_accessors)
224 51         86 { *{"${caller}::${acc}"} = $accessors{$caller}{$acc}
  51         179  
225             }
226              
227 30         58 ; my %class_methods = @$methods
228 30         92 ; $methods{$caller} = \%class_methods
229             }
230              
231             # setup init method
232 30 100       572 ; if($init)
233 2 50       7 { unless(ref($init) eq 'CODE' )
234 2         4 { $init = $init{$init}
235 2 50       4 ; unless(defined $init)
236 0         0 { Carp::croak("There is no init defined for init argument $init.")
237             }
238             }
239 13         2624 ; no strict 'refs'
240 13     13   96 ; *{"${caller}::init"}= $init
  13         24  
  2         3  
  2         13  
241             }
242             }
243              
244             # Package Method
245             ; sub accessors_for_class
246 0     0 1 0 { my ($self,$class)=@_
247 0         0 ; return $classes{$class}
248             }
249              
250             # Package Function
251             ; sub _value_of
252 32     32   59 { my ($class,$accessorname) = @_
253 32         72 ; return $accessors{$class}{$accessorname}->()
254             }
255              
256             ; sub _methods_code
257 1     1   2 { my ($class,$methodname) = @_
258 1         2 ; return $methods{$class}{$methodname}
259             }
260              
261             ; 1
262              
263             __END__