File Coverage

blib/lib/Mic/Assembler.pm
Criterion Covered Total %
statement 346 361 95.8
branch 118 146 80.8
condition 35 54 64.8
subroutine 64 70 91.4
pod 0 5 0.0
total 563 636 88.5


line stmt bran cond sub pod time code
1             package Mic::Assembler;
2              
3 33     33   216 use strict;
  33         71  
  33         1060  
4 33     33   9265 use Class::Method::Modifiers qw(install_modifier);
  33         47185  
  33         1889  
5 33     33   243 use Carp;
  33         74  
  33         1636  
6 33     33   11403 use Hash::Util qw( lock_keys );
  33         76182  
  33         234  
7 33     33   15475 use List::MoreUtils qw( any uniq );
  33         337190  
  33         228  
8 33     33   32625 use Module::Runtime qw( require_module );
  33         85  
  33         303  
9 33     33   1931 use Params::Validate qw(:all);
  33         75  
  33         6505  
10 33     33   11096 use Package::Stash;
  33         44534  
  33         1157  
11 33     33   235 use Scalar::Util qw( reftype );
  33         69  
  33         1700  
12 33     33   13569 use Storable qw( dclone );
  33         84374  
  33         2139  
13 33     33   9603 use Sub::Name;
  33         13383  
  33         1623  
14              
15 33     33   10236 use Mic::_Guts;
  33         120  
  33         118433  
16              
17             sub new {
18 49     49 0 194 my ($class, %arg) = @_;
19              
20             my $obj = {
21             spec => $arg{-spec} || {},
22 49   50     284 };
23 49         202 bless $obj;
24             }
25              
26             sub load_spec_from {
27 47     47 0 157 my ($self, $package) = @_;
28              
29 47         193 my $spec = $self->{spec};
30 47         933 my $cls_stash = Package::Stash->new($package);
31              
32 47 50       188 $spec = { %$spec, %{ $cls_stash->get_symbol('%__meta__') || {} } };
  47         1092  
33 47         173 $spec->{name} = $package;
34 47         115 $self->{cls_stash} = $cls_stash;
35 47         103 $self->{spec} = $spec;
36 47         143 return $spec;
37             }
38              
39             sub assemble {
40 49     49 0 122 my ($self) = @_;
41              
42 49         110 my $spec = $self->{spec};
43 49   66     270 $self->{cls_stash} ||= Package::Stash->new($spec->{name});
44              
45 49         91 my $obj_stash;
46              
47 49   66     258 my $pkg = $Mic::Bound_implementation_of{ $spec->{name} } || $spec->{implementation};
48             $pkg ne $spec->{name}
49 49 50       159 or confess "$spec->{name} cannot be its own implementation.";
50 49         162 my $stash = _get_stash($pkg);
51              
52 49         277 my $meta = $stash->get_symbol('%__meta__');
53              
54             $spec->{implementation} = {
55             package => $pkg,
56             methods => $stash->get_all_symbols('CODE'),
57             has => {
58 49 50       438 %{ $meta->{has} || { } },
59             },
60             arrayimp => $meta->{arrayimp},
61             slot_offset => $meta->{slot_offset},
62 49         519 };
63 49         227 _collect_non_instance_methods($spec, $meta);
64 49         488 $obj_stash = Package::Stash->new("$spec->{implementation}{package}::__Assembled");
65              
66 49         213 _prep_interface($spec);
67 49         165 _merge_interfaces($spec);
68              
69 49         115 my $cls_stash = $self->{cls_stash};
70 49         575 $cls_stash->add_symbol('$__Obj_pkg', $obj_stash->name);
71 49 50       412 $cls_stash->add_symbol('%__meta__', $spec) if @_ > 0;
72              
73 49         193 _add_methods($spec, $obj_stash);
74 49         1307 _make_builder_class($spec);
75 49         196 _add_class_methods($spec, $cls_stash);
76 49         1623 _check_interface($spec);
77 48         1600 return $spec->{name};
78             }
79              
80             sub _collect_non_instance_methods {
81 49     49   155 my ($spec, $meta) = @_;
82              
83 49         148 my $is_classmethod = _interface($meta, 'classmethod');
84              
85 49         100 foreach my $sub ( keys %{ $spec->{implementation}{methods} } ) {
  49         243  
86 152         215 my $type;
87 152 100       438 if ( $is_classmethod->{$sub} ) {
88 1         3 $type = 'classmethod';
89             }
90 152 100       544 if ($type) {
91 1         6 $spec->{implementation}{$type}{$sub} = delete $spec->{implementation}{methods}{$sub};
92             }
93             }
94             }
95              
96             sub _get_stash {
97 49     49   121 my $pkg = shift;
98              
99 49         372 my $stash = Package::Stash->new($pkg); # allow for inlined pkg
100              
101 49 100       683 if ( ! $stash->has_symbol('%__meta__') ) {
102 44         289 require_module($pkg);
103 44         884 $stash = Package::Stash->new($pkg);
104             }
105 49 50       593 if ( ! $stash->has_symbol('%__meta__') ) {
106 0         0 confess "Package $pkg has no %__meta__";
107             }
108 49         170 return $stash;
109             }
110              
111             sub _interface {
112 98     98   242 my ($spec, $type) = @_;
113              
114 98   100     359 $type ||= 'interface';
115 98         608 my %must_allow = (
116             interface => [qw( AUTOLOAD can DOES DESTROY )],
117             classmethod => [ ],
118             );
119 98 100 66     503 if ( $type eq 'interface' && ref $spec->{$type} eq 'HASH') {
120 49         98 $spec->{interface_meta} = do {
121 49         85 my @args = %{ $spec->{$type} };
  49         218  
122 49         1222 validate(@args, {
123             object => { type => HASHREF },
124             class => { type => HASHREF },
125             extends => { type => SCALAR | ARRAYREF, optional => 1 },
126             invariant => { type => HASHREF, optional => 1 },
127             });
128 49         330 $spec->{$type};
129             };
130 49         105 $spec->{$type} = [ keys %{ $spec->{$type}{object} } ];
  49         272  
131 49         182 $Mic::Spec_for{ $spec->{name} }{interface} = $spec->{interface_meta};
132             }
133 98         200 return { map { $_ => 1 } @{ $spec->{$type} }, @{ $must_allow{$type} } };
  391         910  
  98         216  
  98         338  
134             }
135              
136             sub _prep_interface {
137 49     49   112 my ($spec) = @_;
138              
139 49 100       214 return if ref $spec->{interface};
140 3         5 my $count = 0;
141             {
142              
143 3 100       6 if (my $methods = $Mic::Spec_for{ $spec->{interface} }{interface}) {
  4         20  
144 3         7 $spec->{interface_name} = $spec->{interface};
145 3         8 $spec->{interface} = $methods;
146             }
147             else {
148 1 50       6 $count > 0
149             and confess "Invalid interface: $spec->{interface}";
150 1         7 require_module($spec->{interface});
151 1         11 $count++;
152 1         3 redo;
153             }
154             }
155             }
156              
157             sub _merge_interfaces {
158 51     51   133 my ($spec, $interfaces, $from_interface) = @_;
159              
160 51 100       157 if ( ! $interfaces ) {
161 49         340 $interfaces = to_aref($spec->{interface}{extends});
162             }
163              
164 51   100     328 $from_interface ||= {};
165              
166 51         85 foreach my $super (@{ $interfaces }) {
  51         154  
167             $super eq $spec->{name}
168 2 50       7 and confess "$spec->{name} cannot extend itself";
169 2         7 require_module($super);
170             my $declared_interface = $Mic::Spec_for{ $super }{interface}
171 2 50       39 or confess "Could not find interface '$super'";
172 2         8 merge($spec->{interface}, $declared_interface, $from_interface);
173 2         4 $spec->{does}{$super} = 1;
174 2         6 _merge_interfaces($spec, to_aref($declared_interface->{extends}), $from_interface);
175             }
176             }
177              
178             sub to_aref {
179 51     51 0 158 my ($x) = @_;
180              
181 51 100       191 return [] unless defined $x;
182 2 100       8 return ref $x eq 'ARRAY' ? $x : [$x];
183             }
184              
185             sub merge {
186 4     4 0 8 my ($h1, $h2, $from) = @_;
187              
188 4         4 foreach my $k (keys %{ $h2 }) {
  4         11  
189 14 100       22 if (exists $h1->{$k}) {
190 2 50 33     16 if ( ref $h1->{$k} eq 'HASH'
191             && ref $h2->{$k} eq 'HASH'
192             ) {
193 2         8 merge($h1->{$k}, $h2->{$k}, $from);
194             }
195             }
196             else {
197 12         18 $h1->{$k} = $h2->{$k};
198             }
199             }
200             }
201              
202             sub _check_interface {
203 49     49   112 my ($spec) = @_;
204 49         102 my $count = 0;
205 49         90 foreach my $method ( @{ $spec->{interface} } ) {
  49         137  
206 194 100       430 defined $spec->{implementation}{methods}{$method}
207             or confess "Interface method '$method' is not implemented.";
208 193         283 ++$count;
209             }
210 48 50       159 $count > 0 or confess "Cannot have an empty interface.";
211             }
212              
213             sub _add_methods {
214 49     49   167 my ($spec, $stash) = @_;
215              
216 49         126 my $in_interface = _interface($spec);
217              
218             $spec->{implementation}{methods}{DOES} = sub {
219 8     8   3422 my ($self, $r) = @_;
        6      
        8      
220              
221 8 100       27 if ( ! $r ) {
222             my @items = (( $spec->{interface_name} ? $spec->{interface_name} : () ),
223 2 50       17 $spec->{name}, sort keys %{ $spec->{does} });
  2         14  
224 2 50       16 return unless defined wantarray;
225 2 50       23 return wantarray ? @items : \@items;
226             }
227              
228             return $r eq $spec->{interface_name}
229             || $spec->{name} eq $r
230 6   33     70 || $spec->{does}{$r}
231             || $self->isa($r);
232 49         329 };
233             $spec->{implementation}{methods}{can} = sub {
234 75     75   9836 my ($self, $f) = @_;
        75      
        75      
235              
236 75 50       177 if ( ! $f ) {
237 0         0 my @items = sort @{ $spec->{interface} };
  0         0  
238 0 0       0 return unless defined wantarray;
239 0 0       0 return wantarray ? @items : \@items;
240             }
241 75         395 return UNIVERSAL::can($self, $f);
242 49         217 };
243              
244 49         127 while ( my ($name, $meta) = each %{ $spec->{implementation}{has} } ) {
  113         566  
245              
246 64         237 _validate_slot_def($meta);
247 64 100 66     807 if ( ! $spec->{implementation}{methods}{ $meta->{reader} }
      100        
248             && $meta->{reader}
249             && $in_interface->{ $meta->{reader} } ) {
250              
251 14         58 my $obfu_name = Mic::_Guts::obfu_name($name, $spec);
252             $spec->{implementation}{methods}{ $meta->{reader} } = sub {
253 143     143   2544 my ($self) = @_;
        26      
254              
255 143 100       380 if ( reftype $self eq 'HASH' ) {
256 142         2116 return $self->{$obfu_name};
257             }
258 1         10 return $self->[ $spec->{implementation}{slot_offset}{$name} ];
259 14         83 };
260             }
261              
262 64 100 66     412 if ( ! $spec->{implementation}{methods}{ $meta->{property} }
      66        
263             && $meta->{property}
264             && $in_interface->{ $meta->{property} } ) {
265              
266 1 50       6 confess "'property' can only be used from Perl 5.16 onwards"
267             if $] lt '5.016';
268 1         5 my $obfu_name = Mic::_Guts::obfu_name($name, $spec);
269             $spec->{implementation}{methods}{ $meta->{property} } = sub : lvalue {
270 2     2   11 my ($self) = @_;
271              
272 2 50       5 if ( reftype $self eq 'HASH' ) {
273 0         0 return $self->{$obfu_name};
274             }
275 2         15 return $self->[ $spec->{implementation}{slot_offset}{$name} ];
276 1         5 };
277             }
278              
279 64 100 66     360 if ( ! $spec->{implementation}{methods}{ $meta->{writer} }
      66        
280             && $meta->{writer}
281             && $in_interface->{ $meta->{writer} } ) {
282              
283             $spec->{implementation}{methods}{ $meta->{writer} } = sub {
284 1     1   9 my ($self, $new_val) = @_;
        12      
285              
286 1 50       7 if ( reftype $self eq 'HASH' ) {
287 0         0 $self->{ Mic::_Guts::obfu_name($name, $spec) } = $new_val;
288             }
289             else {
290 1         8 $self->[ $spec->{implementation}{slot_offset}{$name} ] = $new_val;
291             }
292 1         4 return $self;
293 1         8 };
294             }
295 64         207 _add_delegates($spec, $meta, $name);
296             }
297              
298 49         126 while ( my ($name, $sub) = each %{ $spec->{implementation}{methods} } ) {
  365         1267  
299 316 100       678 next unless $in_interface->{$name};
300 292         3593 $stash->add_symbol("&$name", subname $stash->name."::$name" => $sub);
301             }
302              
303 49         100 foreach my $name ( @{ $spec->{interface} } ) {
  49         132  
304 194         3539 _add_pre_conditions($spec, $stash, $name, 'object');
305 194         902 _add_post_conditions($spec, $stash, $name, 'object');
306             }
307 49         168 _add_invariants($spec, $stash);
308             }
309              
310             sub _validate_slot_def {
311 64     65   1626 validate(@_, {
312             default => { type => SCALAR | CODEREF, optional => 1 },
313             handles => { type => ARRAYREF | HASHREF, optional => 1 },
314             init_arg => { type => SCALAR, optional => 1 },
315             property => { type => SCALAR, optional => 1 },
316             reader => { type => SCALAR, optional => 1 },
317             writer => { type => SCALAR, optional => 1 },
318             });
319             }
320              
321             sub _add_invariants {
322 49     49   117 my ($spec, $stash) = @_;
323              
324 49 100       248 return unless $Mic::Contracts_for{ $spec->{name} }{invariant};
325             my $inv_hash =
326             (! ref $spec->{interface}
327             && $Mic::Spec_for{ $spec->{interface} }{interface_meta}{invariant})
328              
329             || $spec->{interface_meta}{invariant}
330 5 50 33     100 or return;
331              
332             $spec->{invariant_guard} ||= sub {
333             # skip methods called by the invariant
334 687 100   687   25002 return if (caller 1)[0] eq $spec->{name};
335              
336 125         1020 foreach my $desc (keys %{ $inv_hash }) {
  125         265  
337 125         169 my $sub = $inv_hash->{$desc};
338 125 100       247 $sub->(@_)
339             or confess "Invariant '$desc' violated";
340             }
341 5   50     47 };
342 5         14 foreach my $type ( qw[before after] ) {
343 10         735 install_modifier($stash->name, $type, @{ $spec->{interface} }, $spec->{invariant_guard});
  10         49  
344             }
345             }
346              
347              
348             sub _add_pre_conditions {
349 243     243   469 my ($spec, $stash, $name, $type) = @_;
350              
351 243 100       664 return unless $Mic::Contracts_for{ $spec->{name} }{pre};
352              
353 21         46 _validate_contract_def($spec->{interface_meta}{$type}{$name});
354             my $pre_cond_hash = $spec->{interface_meta}{$type}{$name}{require}
355 21 100       85 or return;
356              
357             my $guard = sub {
358 13     13   2566 foreach my $desc (keys %{ $pre_cond_hash }) {
  13         40  
359 13         26 my $sub = $pre_cond_hash->{$desc};
360 13 100       39 $sub->(@_)
361             or confess "Method '$name' failed precondition '$desc'";
362             }
363 6         28 };
364 6         28 install_modifier($stash->name, 'before', $name, $guard);
365             }
366              
367             sub _add_post_conditions {
368 243     243   444 my ($spec, $stash, $name, $type) = @_;
369              
370 243 100       691 return unless $Mic::Contracts_for{ $spec->{name} }{post};
371              
372 42         96 _validate_contract_def($spec->{interface_meta}{$type}{$name});
373             my $post_cond_hash = $spec->{interface_meta}{$type}{$name}{ensure}
374 42 100       183 or return;
375              
376 18         40 my $constructor_spec = _constructor_spec($spec);
377              
378             my $guard = sub {
379 30     30   5147 my $orig = shift;
380 30         58 my $self = shift;
381              
382 30         52 my @old;
383 30         73 my @invocant = ($self);
384 30 100       100 if ($type eq 'object') {
385 24         1516 @old = ( dclone($self) );
386             }
387 30         128 my $results = [$orig->($self, @_)];
388 30         574 my $results_to_check = $results;
389              
390 30 100 66     130 if ($type eq 'class' && $name eq $constructor_spec->{name}) {
391 6         20 $results_to_check = $results->[0];
392 6         18 @invocant = ();
393             }
394              
395 30         57 foreach my $desc (keys %{ $post_cond_hash }) {
  30         103  
396 44         190 my $sub = $post_cond_hash->{$desc};
397 44 100       153 $sub->(@invocant, @old, $results_to_check, @_)
398             or confess "Method '$name' failed postcondition '$desc'";
399             }
400 26 100       589 return unless defined wantarray;
401 7 100       61 return wantarray ? @$results : $results->[0];
402 18         74 };
403 18         91 install_modifier($stash->name, 'around', $name, $guard);
404             }
405              
406             sub _validate_contract_def {
407 63     63   667 validate(@_, {
408             ensure => { type => HASHREF, optional => 1 },
409             require => { type => HASHREF, optional => 1 },
410             });
411             }
412              
413             sub _make_builder_class {
414 49     49   113 my ($spec) = @_;
415              
416 49         612 my $stash = Package::Stash->new("$spec->{name}::__Util");
417 49         256 $Mic::Util_class{ $spec->{name} } = $stash->name;
418              
419 49         166 my $constructor_spec = _constructor_spec($spec);
420              
421 49         180 my %method = (
422             new_object => \&_object_maker,
423             );
424              
425 49     52   223 $method{main_class} = sub { $spec->{name} };
  52     52   166  
        32      
426              
427             $method{build} = sub {
428 51     51   135 my (undef, $obj, $arg) = @_;
        51      
        32      
429              
430 51         138 my $impl_pkg = $spec->{implementation}{package};
431 51 100       727 if ( my $builder = $impl_pkg->can('BUILD') ) {
432 6         23 $builder->($obj, $arg);
433             }
434 49         252 };
435              
436             $method{check_invariants} = sub {
437 51     51   84 shift;
        51      
        32      
438 51         122 my ($obj) = @_;
439              
440 51 100       190 return unless exists $spec->{invariant_guard};
441 5         24 $spec->{invariant_guard}->($obj);
442 49         207 };
443              
444 49         415 my $class_var_stash = Package::Stash->new("$spec->{name}::__ClassVar");
445              
446             $method{get_var} = sub {
447 0     0   0 my ($class, $name) = @_;
        0      
        0      
448 0         0 $class_var_stash->get_symbol($name);
449 49         256 };
450              
451             $method{set_var} = sub {
452 0     0   0 my ($class, $name, $val) = @_;
        0      
        0      
453 0         0 $class_var_stash->add_symbol($name, $val);
454 49         210 };
455              
456 49         197 foreach my $sub ( keys %method ) {
457 294         2051 $stash->add_symbol("&$sub", $method{$sub});
458 294         1764 subname $stash->name."::$sub", $method{$sub};
459             }
460             }
461              
462             sub _add_class_methods {
463 49     49   129 my ($spec, $stash) = @_;
464              
465 49         129 $spec->{class_methods} = $spec->{implementation}{classmethod};
466 49         178 _add_default_constructor($spec);
467              
468 49         98 foreach my $sub ( keys %{ $spec->{class_methods} } ) {
  49         186  
469 49         395 $stash->add_symbol("&$sub", $spec->{class_methods}{$sub});
470 49         385 subname "$spec->{name}::$sub", $spec->{class_methods}{$sub};
471 49         183 _add_pre_conditions($spec, $stash, $sub, 'class');
472 49         607 _add_post_conditions($spec, $stash, $sub, 'class');
473             }
474             }
475              
476             sub _add_delegates {
477 64     64   191 my ($spec, $meta, $name) = @_;
478              
479 64 100       251 if ( $meta->{handles} ) {
480 15         30 my $method;
481 15         33 my $target_method = {};
482 15 100       67 if ( ref $meta->{handles} eq 'ARRAY' ) {
    50          
483 14         27 $method = { map { $_ => 1 } @{ $meta->{handles} } };
  49         104  
  14         45  
484             }
485             elsif( ref $meta->{handles} eq 'HASH' ) {
486 1         2 $method = $meta->{handles};
487 1         2 $target_method = $method;
488             }
489              
490 15         34 foreach my $meth ( keys %{ $method } ) {
  15         57  
491 51 50       127 if ( defined $spec->{implementation}{methods}{$meth} ) {
492 0         0 confess "Cannot override implemented method '$meth' with a delegated method";
493             }
494             else {
495 51         122 my $obfu_name = Mic::_Guts::obfu_name($name, $spec);
496 51   66     185 my $target = $target_method->{$meth} || $meth;
497             $spec->{implementation}{methods}{$meth} = sub {
498 285     285   8131 my $obj = shift;
        87      
        86      
499              
500             my $delegate = reftype $obj eq 'HASH'
501             ? $obj->{$obfu_name}
502 285 100       855 : $obj->[ $spec->{implementation}{slot_offset}{ $name } ];
503 285 100       537 if (wantarray) {
    100          
504 187         491 my @results = $delegate->$target(@_);
505 187         4708 return @results;
506             }
507             elsif( defined wantarray ) {
508 83         289 return $delegate->$target(@_);
509             }
510             else {
511 15         48 $delegate->$target(@_);
512 15         185 return;
513             }
514             }
515 51         354 }
516             }
517             }
518             }
519              
520             sub _constructor_spec {
521 116     177   247 my ($spec) = @_;
522              
523 116 50       378 if(! ref $spec->{interface}) {
524 0         0 my $s;
525             $s = $Mic::Spec_for{ $spec->{interface} }{constructor}
526 0 0       0 and return $s;
527             }
528 116   100     421 $spec->{constructor} ||= {};
529 116         273 return $spec->{constructor};
530             }
531              
532             sub _add_default_constructor {
533 49     49   104 my ($spec) = @_;
534              
535 49         118 my $constructor_spec = _constructor_spec($spec);
536              
537 49   50     324 $constructor_spec->{name} ||= 'new';
538 49         90 my $sub_name = $constructor_spec->{name};
539 49 100       189 if ( ! exists $spec->{class_methods}{$sub_name} ) {
540             $spec->{class_methods}{$sub_name} = sub {
541 51     51   8122 my $class = shift;
        51      
        16      
542 51         96 my ($arg);
543              
544 51 100       262 if ( scalar @_ == 1 ) {
    100          
545 18         43 $arg = shift;
546             }
547             elsif ( scalar @_ > 1 ) {
548 2         7 $arg = [@_];
549             }
550              
551 51         237 my $builder = Mic::builder_for($class);
552 51         339 my $obj = $builder->new_object;
553 51 100       207 my $kv_args = ref $arg eq 'HASH' ? $arg : {};
554 51         97 for my $name ( keys %{ $kv_args } ) {
  51         181  
555              
556             # handle init_args
557 33         135 my ($attr, $dup) = grep { $spec->{implementation}{has}{$_}{init_arg} eq $name }
558 18         45 keys %{ $spec->{implementation}{has} };
  18         72  
559 18 50       75 if ( $dup ) {
560 0         0 confess "Cannot have same init_arg '$name' for attributes '$attr' and '$dup'";
561             }
562 18 100       72 if ( $attr ) {
563 17         46 my $attr_val = $arg->{$name};
564 17 100       92 if ( reftype $obj eq 'HASH' ) {
565 13         43 my $obfu_name = Mic::_Guts::obfu_name($attr, $spec);
566 13         49 $obj->{$obfu_name} = $attr_val;
567             }
568             else {
569 4         28 $obj->[ $spec->{implementation}{slot_offset}{$attr} ] = $attr_val;
570             }
571             }
572             }
573              
574 51         230 $builder->build($obj, $arg);
575 51         348 $builder->check_invariants($obj);
576 51         291 return $obj;
577 48         399 };
578             }
579             }
580              
581             sub _object_maker {
582 52     52   151 my ($builder, $init) = @_;
583              
584 52         241 my $class = $builder->main_class;
585              
586 52         627 my $stash = Package::Stash->new($class);
587              
588 52         531 my $spec = $stash->get_symbol('%__meta__');
589 52         253 my $pkg_key = Mic::_Guts::obfu_name('', $spec);
590             my $obj = $spec->{implementation}{arrayimp}
591 52 100       250 ? [ ]
592             : { };
593              
594 52         114 while ( my ($attr, $meta) = each %{ $spec->{implementation}{has} } ) {
  119         528  
595             my $init_val = $init->{$attr}
596             ? $init->{$attr}
597             : (ref $meta->{default} eq 'CODE'
598             ? $meta->{default}->()
599 67 100       443 : $meta->{default});
    100          
600 67 100       262 if ( $spec->{implementation}{arrayimp} ) {
601 19         57 my $offset = $spec->{implementation}{slot_offset}{$attr};
602 19         69 $obj->[$offset] = $init_val;
603             }
604             else {
605 48         132 my $obfu_name = Mic::_Guts::obfu_name($attr, $spec);
606 48         151 $obj->{$obfu_name} = $init_val;
607             }
608             }
609              
610 52         107 bless $obj => ${ $stash->get_symbol('$__Obj_pkg') };
  52         484  
611 52         181 $Mic::_Guts::Implementation_meta{ref $obj} = $spec->{implementation};
612              
613 52 100       298 if ( reftype $obj eq 'HASH' ) {
614 35         261 lock_keys(%$obj);
615             }
616 52         747 return $obj;
617             }
618              
619             1;
620              
621             __END__