File Coverage

blib/lib/HO/accessor.pm
Criterion Covered Total %
statement 133 139 95.6
branch 56 64 87.5
condition 11 17 64.7
subroutine 20 22 90.9
pod 1 1 100.0
total 221 243 90.9


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