File Coverage

blib/lib/Mic/Assembler.pm
Criterion Covered Total %
statement 337 355 94.9
branch 108 138 78.2
condition 38 57 66.6
subroutine 65 71 91.5
pod 0 5 0.0
total 548 626 87.5


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