File Coverage

blib/lib/Rope.pm
Criterion Covered Total %
statement 405 431 93.9
branch 145 192 75.5
condition 51 81 62.9
subroutine 40 42 95.2
pod 9 11 81.8
total 650 757 85.8


line stmt bran cond sub pod time code
1             package Rope;
2              
3 64     64   4622841 use 5.006; use strict; use warnings;
  64     64   166  
  64     56   284  
  64         3021  
  64         1495  
  64         230  
  56         124  
  56         3357  
4             our $VERSION = '0.45';
5 56     55   19573 use Rope::Object;
  55         119  
  55         1698  
6 55     55   17985 use Rope::Pro;
  55         138  
  55         181023  
7             my (%META, %PRO);
8             our @ISA;
9              
10             BEGIN {
11             %PRO = Rope::Pro->new(
12             scope => sub {
13 6385         20180 my ($caller, $self, %props) = @_;
14 6385         6727 for my $prop (keys %{$props{properties}}) {
  6385         10685  
15 24342 100 100     55020 if ($props{properties}{$prop}{value} && ref $props{properties}{$prop}{value} eq 'CODE') {
16 6475         8340 my $cb = $props{properties}{$prop}{value};
17 6475         26474 $props{properties}{$prop}{value} = sub { $cb->($META{initialised}{$caller}{${$self}->{identifier}}, @_) };
  445         961  
  445         1577  
18             }
19              
20 24342         25146 for (qw/predicate clearer/) {
21 48684 100       68904 if ($props{properties}->{$prop}->{$_}) {
22 2288 100       3096 my $prep = $_ eq 'predicate' ? 'has_' : 'clear_';
23 2288         2987 my $pred = $props{properties}->{$prop}->{$_};
24 2288         2072 my $ref = ref($pred);
25 2288 100       2767 if ( !$ref ) {
    100          
    50          
26             $props{properties}->{$pred =~ m/^\d+$/ ? "$prep$prop" : $pred} = {
27             value => $_ eq 'predicate'
28 64 100       147 ? sub { return defined $META{initialised}{$caller}{${$self}->{identifier}}->{$prop} ? 1 : '' }
  64         156  
29 29         71 : sub { $META{initialised}{$caller}{${$self}->{identifier}}->{$prop} = undef; 1; }
  29         80  
  29         91  
30 2280 100       20502 };
    100          
31             } elsif ($ref eq 'CODE') {
32             $props{properties}->{"$prep$prop"} = {
33 4         9 value => sub { $pred->($META{initialised}{$caller}{${$self}->{identifier}}, $prop) }
  4         14  
34 4         24 };
35             } elsif ($ref eq 'HASH') {
36 4         6 my $cb = $pred->{value};
37 4         10 $pred->{value} = sub { $cb->($META{initialised}{$caller}{${$self}->{identifier}}, $prop) };
  4         9  
  4         12  
38 4   33     17 $props{properties}->{$pred->{name} || "$prep$prop"} = $pred;
39             }
40             }
41             }
42 24342         22786 for (qw/trigger delete_trigger/) {
43 48684         50206 my $trigger = $props{properties}{$prop}{$_};
44 48684 100       57547 if (defined $trigger) {
45             $props{properties}{$prop}{$_} = sub {
46 4187         5727 $trigger->($META{initialised}{$caller}{${$self}->{identifier}}, @_)
  4187         10805  
47 2122         8352 };
48             }
49             }
50 24342         22179 for (qw/before after/) {
51 48684         47712 my $mod = $props{properties}{$prop}{$_};
52 48684 50 100     56767 if (defined $mod && scalar @{$mod}) {
  65         133  
53             my $cb = sub {
54 140         161 my $cb = shift;
55 140         184 $cb->($META{initialised}{$caller}{${$self}->{identifier}}, @_);
  140         406  
56 65         209 };
57             $props{properties}{$prop}{$_} = sub {
58 101         205 my (@params) = @_;
59 101         145 for (my $i = 0; $i < scalar @{$mod} - 1; $i++) {
  140         336  
60 41         108 my @new_params = ($cb->($mod->[$i], @params));
61 39 100       243 @params = @new_params if @new_params;
62             }
63 99         193 return $cb->($mod->[-1], @params);
64 65         332 };
65             }
66             }
67 24342         23858 my $mod = $props{properties}{$prop}{around};
68 24342 50 100     27670 if (defined $mod && scalar @{$mod}) {
  32         72  
69             my $cb = sub {
70 45         55 my $cb = shift;
71 45         89 $cb->($META{initialised}{$caller}{${$self}->{identifier}}, @_);
  45         171  
72 32         121 };
73             $props{properties}{$prop}{around} = sub {
74 44         88 my ($orig, @params) = @_;
75 44   100     130 my $code = (ref($orig) || "") eq 'CODE';
76 44 100       115 @params = ($orig) if (!$code);
77 44         62 my @stack;
78 44         83 for (my $i = 0; $i < scalar @{$mod}; $i++) {
  89         196  
79 45         83 my $current = $mod->[$i];
80 45 100       117 my $next = $stack[-1] ? $stack[-1] : $code ? $orig : sub { $_[0] };
  3 100       24  
81             my $calling = sub {
82 45         110 return $cb->($current, $next, @_);
83 45         172 };
84 45         107 push @stack, $calling;
85             }
86 44         71 return $stack[-1]->(@params);
87 32         184 };
88             }
89 24342         22702 my $handles = $props{properties}{$prop}{handles};
90 24342 100       31330 if ($handles) {
91 4 100       25 $props{handles} = {%{ $props{handles} || {} }, map { $_ => $prop } keys %{$handles}};
  4         13  
  16         31  
  4         7  
92             }
93             }
94 6385         21012 return \%props;
95             },
96             clone => sub {
97 205092         167024 my $obj = shift;
98 205092         171610 my $ref = ref $obj;
99 205092 100       375209 return $obj if !$ref;
100 53644 100       60208 return [ map { $PRO{clone}->($_) } @{$obj} ] if $ref eq 'ARRAY';
  689         961  
  394         676  
101 53250 100       63724 return { map { $_ => $PRO{clone}->($obj->{$_}) } keys %{$obj} } if $ref eq 'HASH';
  197901         209718  
  44151         84148  
102 9099         12832 return $obj;
103             },
104             set_prop => sub {
105 357         954 my ($caller, $prop, %options) = @_;
106 357 100       777 if (exists $META{$caller}{properties}{$prop}) {
107 26   33     111 defined $options{$_} && do { $META{$caller}{properties}{$prop}{$_} = $options{$_} } for qw/builder trigger delete_trigger handles handles_via/;
  0         0  
108 26 50       37 if ($META{$caller}{properties}{$prop}{writeable}) {
    0          
109 26 50       42 $META{$caller}{properties}{$prop}{value} = $options{value} if exists $options{value};
110 26         72 $META{$caller}{properties}{$prop}{class} = $caller;
111             } elsif ($META{$caller}{properties}{$prop}{configurable}) {
112 0 0 0     0 if ((ref($META{$caller}{properties}{$prop}{value}) || "") eq (ref($options{value}) || "")) {
      0        
113 0 0       0 $META{$caller}{properties}{$prop}{value} = $options{value} if exists $options{value};
114 0         0 $META{$caller}{properties}{$prop}{class} = $caller;
115             } else {
116 0         0 die "Cannot inherit $META{$caller}{properties}{$prop}{class} and change property $prop type";
117             }
118             } else {
119 0         0 die "Cannot inherit $META{$caller}{properties}{$prop}{class} and change property $prop type";
120             }
121             } else {
122             $META{$caller}{properties}{$prop} = {
123             class => $options{class} || $caller,
124             index => ++$META{$caller}{keys},
125 331   66     2444 %options
126             };
127             }
128             },
129             requires => sub {
130 152         200 my ($caller) = shift;
131             return sub {
132 4 50 66 4   625 shift @_ if $_[0] && $_[0] eq $caller;
133 4         13 my (@requires) = @_;
134 4         21 $META{$caller}{requires}{$_}++ for (@requires);
135 152         611 };
136             },
137             readonly => sub {
138 142         175 my ($caller) = shift;
139             return sub {
140 3 50   3   136616 shift @_ if $_[0] eq $caller;
141 3         7 my ($prop, @options) = @_;
142 3 50       5 $prop = shift @options if ( @options > 1 );
143             $PRO{set_prop}(
144 3         8 $caller,
145             $prop,
146             value => $options[0],
147             enumerable => 0,
148             writeable => 0,
149             initable => 1,
150             readonly => 1,
151             );
152 142         429 };
153             },
154             private => sub {
155 142         181 my ($caller) = shift;
156             return sub {
157 1 50   1   123283 shift @_ if $_[0] eq $caller;
158 1         3 my ($prop, @options) = @_;
159 1 50       4 $prop = shift @options if ( @options > 1 );
160             $PRO{set_prop}(
161 1         6 $caller,
162             $prop,
163             value => $options[0],
164             enumerable => 0,
165             writeable => 0,
166             initable => 0,
167             private => 1,
168             );
169 142         380 };
170             },
171             function => sub {
172 150         221 my ($caller) = shift;
173             return sub {
174 36 100   36   275 shift @_ if $_[0] eq $caller;
175 36         78 my ($prop, @options) = @_;
176 36 50       80 $prop = shift @options if ( @options > 1 );
177             $PRO{set_prop}(
178 36         149 $caller,
179             $prop,
180             value => $options[0],
181             enumerable => 0,
182             writeable => 0,
183             initable => 0,
184             configurable => 0
185             );
186 150         694 };
187             },
188             properties => sub {
189 191         270 my ($caller) = shift;
190             return sub {
191 44 100   44   106 shift @_ if $_[0] eq $caller;
192 44         103 my (@properties) = @_;
193 44         82 while (@properties) {
194 151         213 my ($prop, $options) = (shift @properties, shift @properties);
195 151         189 my $ref = ref $options;
196 151 100 100     452 if (!$ref || $ref ne 'HASH' || ! grep { defined $options->{$_} }
  1716   66     2014  
197             qw/initable writeable builder enumerable configurable trigger clearer predicate delete_trigger value handles_via handles/
198             ) {
199 8         37 $options = {
200             initable => 1,
201             enumerable => 1,
202             writeable => 1,
203             configurable => 1,
204             value => $options
205             };
206             }
207              
208 151 100       237 for (ref $prop ? @{$prop} : ($prop)) {
  1         3  
209             $PRO{set_prop}(
210             $caller,
211             $_,
212 152         142 %{$options}
  152         280  
213             )
214             };
215             }
216 191         710 };
217             },
218             property => sub {
219 150         199 my ($caller) = shift;
220             return sub {
221 126 100   126   2766645 shift @_ if $_[0] eq $caller;
222 126         368 my ($prop, @options) = @_;
223 126 50       312 if (scalar @options % 2) {
224 0         0 $prop = shift @options;
225             }
226 126 100       292 for (ref $prop ? @{$prop} : ($prop)) {
  1         4  
227             $PRO{set_prop}(
228 127         310 $caller,
229             $_,
230             @options
231             );
232             }
233 150         492 };
234             },
235             prototyped => sub {
236 150         186 my ($caller) = shift;
237             return sub {
238 28 100   28   2038932 shift @_ if $_[0] eq $caller;
239 28         84 my (@proto) = @_;
240 28         76 while (@proto) {
241 36         81 my ($prop, $value) = (shift @proto, shift @proto);
242 36 100       124 for (ref $prop ? @{$prop} : ($prop)) {
  1         2  
243             $PRO{set_prop}(
244 38         144 $caller,
245             $_,
246             enumerable => 1,
247             writeable => 1,
248             configurable => 1,
249             initable => 1,
250             value => $value
251             );
252             }
253             }
254             }
255 150         466 },
256             with => sub {
257 143         205 my ($caller) = shift;
258             return sub {
259 9 50   9   45 shift @_ if $_[0] eq $caller;
260 9         17 my (@withs) = @_;
261 9         16 for my $with (@withs) {
262 9 100       25 if (!$META{$with}) {
263 1         3 (my $name = $with) =~ s!::!/!g;
264 1         2 $name .= ".pm";
265 1         333 CORE::require($name);
266             }
267 9         25 my $initial = $META{$caller};
268 9         28 my $merge = $PRO{clone}($META{$with});
269 9         15 push @{$merge->{with}}, $merge->{name};
  9         23  
270 9         18 $merge->{name} = $initial->{name};
271 9         12 $merge->{locked} = $initial->{locked};
272 9         13 for my $prop (keys %{$initial->{properties}}) {
  9         18  
273 2         5 $merge->{properties}->{$prop}->{index} = ++$merge->{keys};
274 2         4 my $modifier;
275 2         5 for (qw/before around after/) {
276 6 50       12 if ($initial->{properties}->{$prop}->{$_}) {
277 0         0 $modifier = 1;
278 0         0 unshift @{$merge->{properties}->{$prop}->{$_}}, @{$initial->{properties}->{$prop}->{$_}}
  0         0  
  0         0  
279             }
280             }
281 2 50       4 next if $modifier;
282 2 50       3 next if grep { $META{$with}->{properties}->{$prop}->{$_} } qw/before around after/;
  6         24  
283 2 50       32 if (scalar keys %{$merge->{properties}->{$prop}} > 1) {
  2         8  
284 0 0       0 if ($merge->{properties}->{writeable}) {
    0          
285 0         0 $merge->{properties}->{$prop} = $initial->{properties}->{$prop};
286             } elsif ($merge->{properties}->{configurable}) {
287 0 0 0     0 if ((ref($merge->{properties}->{$prop}->{value}) || "") eq (ref($initial->{properties}->{$prop}->{value} || ""))) {
      0        
288 0         0 $merge->{properties}->{$prop} = $initial->{properties}->{$prop};
289             } else {
290 0         0 die "Cannot include $with and change property $prop type";
291             }
292             } else {
293 0         0 die "Cannot include $with and override property $prop";
294             }
295             } else {
296 2         6 $merge->{properties}->{$prop} = $initial->{properties}->{$prop};
297             }
298             }
299 9         10 $merge->{requires} = {%{$merge->{requires}}, %{$initial->{requires}}};
  9         39  
  9         31  
300 9         37 $META{$caller} = $merge;
301             }
302             }
303 143         1044 },
304             extends => sub {
305 143         238 my ($caller) = shift;
306             return sub {
307 25 50   25   199 shift @_ if $_[0] eq $caller;
308 25         65 my (@extends) = @_;
309 25         81 for my $extend (@extends) {
310 25 100       84 if (!$META{$extend}) {
311 2         8 (my $name = $extend) =~ s!::!/!g;
312 2         3 $name .= ".pm";
313 2         598 CORE::require($name);
314             }
315 25         62 my $initial = $META{$caller};
316 25         76 my $merge = $PRO{clone}($META{$extend});
317 25         57 push @{$merge->{extends}}, $merge->{name};
  25         81  
318 25         82 $merge->{name} = $initial->{name};
319 25         45 $merge->{locked} = $initial->{locked};
320 25         34 for my $prop (keys %{$initial->{properties}}) {
  25         67  
321 2         4 $initial->{properties}->{$prop}->{index} = ++$merge->{keys};
322 2         2 for (qw/before around after/) {
323 6 50       11 unshift @{$merge->{properties}->{$prop}->{$_}}, @{$initial->{properties}->{$prop}->{$_}} if $initial->{properties}->{$prop}->{$_};
  0         0  
  0         0  
324             }
325 2 50       3 if ($merge->{properties}->{$prop}) {
326 0 0       0 if ($merge->{properties}->{writeable}) {
    0          
327 0         0 $merge->{properties}->{$prop} = $initial->{properties}->{$prop};
328             } elsif ($merge->{properties}->{configurable}) {
329 0 0 0     0 if ((ref($merge->{properties}->{$prop}->{value}) || "") eq (ref($initial->{properties}->{$prop}->{value} || ""))) {
      0        
330 0         0 $merge->{properties}->{$prop} = $initial->{properties}->{$prop};
331             } else {
332 0         0 die "Cannot inherit $extend and change property $prop type";
333             }
334             } else {
335 0         0 die "Cannot inherit $extend and override property $prop";
336             }
337             } else {
338 2         3 $merge->{properties}->{$prop} = $initial->{properties}->{$prop};
339             }
340             }
341 25         47 $merge->{requires} = {%{$merge->{requires}}, %{$initial->{requires}}};
  25         45  
  25         72  
342 25         60 my $isa = '@' . $caller . '::ISA';
343 25         1958 eval "push $isa, '$extend'";
344 25         161 $META{$caller} = $merge;
345             }
346             }
347 143         1037 },
348             before => sub {
349 150         198 my ($caller) = shift;
350             return sub {
351 8 50   8   58 shift @_ if $_[0] eq $caller;
352 8         15 my ($prop, $cb) = @_;
353 8         6 push @{$META{$caller}{properties}{$prop}{before}}, $cb;
  8         27  
354 150         619 };
355             },
356             around => sub {
357 150         203 my ($caller) = shift;
358             return sub {
359 5 50   5   43 shift @_ if $_[0] eq $caller;
360 5         10 my ($prop, $cb) = @_;
361 5         6 push @{$META{$caller}{properties}{$prop}{around}}, $cb;
  5         16  
362 150         628 };
363             },
364             after => sub {
365 150         188 my ($caller) = shift;
366             return sub {
367 17 100   17   66 shift @_ if $_[0] eq $caller;
368 17         36 my ($prop, $cb) = @_;
369 17         28 push @{$META{$caller}{properties}{$prop}{after}}, $cb;
  17         86  
370 150         499 };
371             },
372             locked => sub {
373 142         384 my ($caller) = shift;
374             return sub {
375 5     5   931 my ($self, $locked) = @_;
376 5 100       9 if (ref $self) {
377 4         10 $self->{locked} = $locked;
378 4         7 return;
379             } else {
380 1         2 $META{$caller}{locked} = 1;
381             }
382 142         668 };
383             },
384             destroy => sub {
385 142         258 my ($caller) = shift;
386             return sub {
387 6214     6214   12783 my ($self, $locked) = @_;
388 6214 50       8386 if (ref $self) {
389 6214         7430 return $self->DESTROY;
390             }
391 142         440 };
392             },
393             DESTROY => sub {
394 142         217 my ($caller) = shift;
395             return sub {
396 6216     6216   6118 my ($self, $locked) = @_;
397 6216 50       7419 if (ref $self) {
398 6216         6730 delete $META{initialised}{$caller}{${$self}->{identifier}};
  6216         9746  
399 6216         7909 return;
400             }
401 142         498 };
402             },
403             new => sub {
404 184         250 my ($caller) = shift;
405             return sub {
406 6387 100   6387   468108 my ($class, %params) = (shift, scalar @_ == 1 ? %{$_[0]} : @_);
  1         3  
407             my $self = \{
408             prototype => {},
409 6387         17666 identifier => $META{initialised}{$caller}{identifier}++
410             };
411 6387         10437 $self = bless $self, $caller;
412 6387         12440 my $build = $PRO{clone}($META{$caller});
413 6387         12535 for (keys %params) {
414 15170 50       22178 next if $_ =~ m/^_/;
415 15170 100       18641 if ($build->{properties}->{$_}) {
416 15167 100       17920 if ($build->{properties}->{$_}->{initable}) {
417 15165         25214 $build->{properties}->{$_}->{value} = $params{$_};
418             } else {
419 2         24 die "Cannot initalise Object ($caller) property ($_) as initable is not set to true.";
420             }
421             } else {
422             $build->{properties}->{$_} = {
423             value => $params{$_},
424             initable => 1,
425             writeable => 1,
426             enumerable => 1,
427             configurable => 1,
428             index => ++$META{$caller}{keys}
429 3         15 };
430             }
431             }
432 6385   100     6757 for ( sort { ($build->{properties}->{$a}->{index} || 0) <=> ($build->{properties}->{$b}->{index} || 0) } keys %{ $build->{properties} } ) {
  28675   50     56308  
  6385         18961  
433 24333 100 100     37021 if ( !defined $build->{properties}->{$_}->{value} && defined $build->{properties}->{$_}->{builder}) {
434 43         54 my $builder = $build->{properties}->{$_}->{builder};
435 43 50       107 $build->{properties}->{$_}->{value} = ref $builder ? $builder->($build) : $caller->$builder($build);
436             }
437             }
438             exists $build->{properties}->{INITIALISE}
439 6385 100 66     16202 ? $build->{properties}->{INITIALISE}->{value}->($self, $build, \%params)
440             : $self->can('INITIALISE') && $self->INITIALISE($build, \%params);
441 6385         6453 tie %{${$self}->{prototype}}, 'Rope::Object', $PRO{scope}($caller, $self, %{$build});
  6385         5286  
  6385         9351  
  6385         13127  
442 6385         11889 $META{initialised}{$caller}->{${$self}->{identifier}} = $self;
  6385         16006  
443 6385         8103 $self->{ROPE_init}->();
444              
445             exists $build->{properties}->{INITIALISED}
446 6382 50 66     24217 ? $build->{properties}->{INITIALISED}->{value}->(\%params)
447             : $self->can('INITIALISED') && $self->INITIALISED(\%params);
448 6382         22617 return $self;
449 184         1389 };
450             }
451 55     55   2023 );
452             }
453              
454             sub import {
455 160     160   11119 my ($pkg, $options, $caller) = (shift, {@_}, caller());
456 160 100       3755 return if $options->{no_import};
457 150 100       315 $caller = $options->{caller} if $options->{caller};
458 150 100       321 if (!$META{$caller}) {
459 113         565 $META{$caller} = {
460             name => $caller,
461             locked => 0,
462             properties => {},
463             requires => {},
464             keys => 0
465             };
466             }
467 150 100 66 12780   849 $PRO{keyword}($caller, 'can', sub { ref $_[0] and ($_[0]->{$_[1]} || $META{$caller}->{properties}->{$_[1]}) || $_[0]->CORE::can($_[1]) });
  12780   100     29417  
468 150     22097   511 $PRO{keyword}($caller, '(bool', sub { 1; });
  22097         49517  
469 150     0   490 $PRO{keyword}($caller, '(eq', sub { $_[1]; });
  0         0  
470 150     0   490 $PRO{keyword}($caller, '((', sub { });
471             $PRO{keyword}($caller, '(%{}', sub {
472 39942     39942   721162 ${$_[0]}->{prototype};
  39942         152082  
473 150         375 });
474             $PRO{keyword}($caller, $_, $PRO{$_}($caller))
475 150 100       662 for $options->{import}
476 8         35 ? @{$options->{import}}
477             : qw/function property properties prototyped private readonly extends with requires before around after locked destroy DESTROY new/;
478             }
479              
480             sub new {
481 42     42 1 231005 my ($pkg, $meta, %params) = @_;
482              
483 42   66     130 my $name = $meta->{name} || 'Rope::Anonymous' . $META{ANONYMOUS}++;
484              
485 42 100       81 if (!$META{$name}) {
486 34         205 $META{$name} = {
487             name => $name,
488             locked => 0,
489             properties => {},
490             requires => {},
491             keys => 0
492             };
493            
494 34         44 my $use = 'use Rope;';
495 34         38 $use .= "use ${_};" for (@{$meta->{use}});
  34         80  
496              
497 34         69 my $c = sprintf(q|
498             package %s;
499             %s
500             1;
501             |, $name, $use);
502 34     11   2868 eval $c;
  11     7   74  
  11     6   13  
  11         44  
  7         58  
  7         9  
  7         53  
  6         1686  
  6         12  
  6         20  
503             }
504              
505 42         160 $pkg->set_meta($meta, $name);
506              
507 42 100       43 if (grep { $_ eq 'Rope::Monkey' } @{$meta->{use}}) {
  17         37  
  42         126  
508 8         29 $meta->{name}->monkey();
509             }
510              
511 42         130 return $PRO{new}($name)($name, %params);
512             }
513              
514             sub from_array {
515 16     16 1 150305 my ($pkg, $data, $meta) = @_;
516              
517 16   100     46 $meta ||= {};
518 16   66     84 $meta->{name} ||= 'Rope::Anonymous' . $META{ANONYMOUS}++;
519 16         13 my $len = scalar @{$data};
  16         27  
520 16         30 for (my $i = 0; $i < $len; $i++) {
521 60         77 my ($key, $value) = ($data->[$i++], $data->[$i]);
522 60         169 $meta->{properties}->{$key} = {
523             value => $value,
524             writeable => 1,
525             enumerable => 1
526             };
527             }
528              
529 16         34 return $pkg->new($meta)->new();
530             }
531              
532              
533             sub from_data {
534 18     18 1 141727 my ($pkg, $data, $meta) = @_;
535              
536 18   100     53 $meta ||= {};
537 18   66     96 $meta->{name} ||= 'Rope::Anonymous' . $META{ANONYMOUS}++;
538              
539 18         14 for (keys %{$data}) {
  18         36  
540             $meta->{properties}->{$_} = {
541 59         131 value => $data->{$_},
542             writeable => 1,
543             enumerable => 1
544             };
545             }
546              
547 18         42 return $pkg->new($meta)->new();
548             }
549              
550             sub from_nested_array {
551 12     12 1 131566 my ($pkg, $data, $meta) = @_;
552              
553 12         25 $data = $PRO{clone}($data);
554 12         19 for (my $i = 0; $i < scalar @{$data}; $i++) {
  54         75  
555 42         73 my ($key, $value) = ($data->[$i++], $data->[$i]);
556 42         37 my $ref = ref $value;
557 42 100       60 if ($ref eq 'ARRAY') {
558 11 100 100     60 if ((ref($value->[-1]) || "") eq 'HASH' && $value->[-1]->{ROPE_scope} eq 'ARRAY') {
    100 66        
559 4         5 pop @{$value};
  4         5  
560 4         11 next;
561             }
562             elsif (ref $value->[0]) {
563 3         5 for (my $x = 0; $x < scalar @{$value}; $x++) {
  6         13  
564 3         4 my ($val) = ($value->[$x]);
565 3         4 my $rref = ref($val); # || "";
566 3 50       5 if ($rref eq 'ARRAY') {
567 3         6 $val = $pkg->from_nested_array(
568             $val,
569             $meta
570             );
571 3         9 $value->[$x] = $val;
572             }
573             }
574             } else {
575 4         12 $data->[$i] = $pkg->from_nested_array($value, $meta);
576             }
577             }
578             }
579              
580 12         26 return $pkg->from_array($data, $meta);
581             }
582              
583             sub from_nested_data {
584 14     14 1 250447 my ($pkg, $data, $meta) = @_;
585              
586 14         29 $data = $PRO{clone}($data);
587              
588 14         16 for my $d (keys %{$data}) {
  14         21  
589 42         53 my $ref = ref $data->{$d};
590 42 100       88 if ($ref eq 'HASH') {
    100          
591 5         14 $data->{$d} = $pkg->from_nested_data($data->{$d}, $meta);
592             } elsif ($ref eq 'ARRAY') {
593 4         7 for (my $i = 0; $i < scalar @{$data->{$d}}; $i++) {
  9         22  
594 5         7 my $val = $data->{$d}->[$i];
595 5   50     12 my $rref = ref $val || "";
596 5 50       8 if ($rref eq 'HASH') {
597 5         17 $val = $pkg->from_nested_data(
598             $val,
599             $meta
600             );
601 5         15 $data->{$d}->[$i] = $val;
602             }
603             }
604             }
605             }
606              
607 14         29 return $pkg->from_data($data, $meta);
608             }
609              
610             sub get_initialised {
611 2     2 1 13 my ($self, $caller, $init) = @_;
612 2         6 return $META{initialised}{$caller}{$init};
613             }
614              
615             sub get_meta {
616 55     55 1 116 my ($self, $caller) = @_;
617 55   33     214 return $PRO{clone}($META{$caller || ref $self});
618             }
619              
620             sub set_meta {
621 43     43 1 1030 my ($self, $meta, $name) = @_;
622 43 100       96 $name = $meta->{name} if ! $name;
623 43 100       91 $META{$name}{locked} = $meta->{locked} if (defined $meta->{locked});
624 43 100       92 $PRO{requires}($name)(ref $meta->{requires} eq 'ARRAY' ? @{$meta->{requires}} : keys %{$meta->{requires}}) if ($meta->{requires});
  1 100       4  
  1         5  
625 43 100       88 $PRO{extends}($name)(@{$meta->{extends}}) if ($meta->{extends});
  1         3  
626 43 100       90 $PRO{with}($name)(@{$meta->{with}}) if ($meta->{with});
  1         3  
627 43 100       171 $PRO{properties}($name)(ref $meta->{properties} eq 'ARRAY' ? @{$meta->{properties}} : %{$meta->{properties}}) if ($meta->{properties});
  7 100       22  
  34         95  
628 43 100       322 $PRO{keyword}($name, 'INITIALISE', $meta->{INITIALISE}) if $meta->{INITIALISE};
629 43 100       87 $PRO{keyword}($name, 'INITIALISED', $meta->{INITIALISED}) if $meta->{INITIALISED};
630             }
631              
632             sub clear_meta {
633 2     2 1 323 my ($self, $name) = @_;
634 2         22 $META{$name} = {
635             name => $name,
636             locked => 0,
637             properties => {},
638             requires => {},
639             keys => 0
640             };
641             }
642              
643             sub clear_property {
644 6     6 0 14 my ($self, $name, $prop) = @_;
645 6         22 delete $META{$name}{properties}{$prop};
646             }
647              
648             sub set_property {
649 2     2 0 1642 my ($self, $name, $prop, $property) = @_;
650 2         8 $META{$name}{properties}{$prop} = $property;
651             }
652              
653              
654             1;
655              
656             __END__