File Coverage

blib/lib/MooX/Prototype.pm
Criterion Covered Total %
statement 88 89 98.8
branch 19 28 67.8
condition 12 23 52.1
subroutine 17 18 94.4
pod 0 7 0.0
total 136 165 82.4


line stmt bran cond sub pod time code
1             # ABSTRACT: Prototype-based Programming
2             package MooX::Prototype;
3              
4 3     3   33469 use Carp;
  3         6  
  3         321  
5              
6             our $VERSION = '0.02'; # VERSION
7              
8             sub import {
9 3     3   19 my $class = shift;
10 3         5 my $target = caller;
11              
12 3     3   16 no strict 'refs';
  3         4  
  3         1696  
13 3         25 *{"${target}::extend"} = $class->can('build_clone');
  3         14  
14 3         9 *{"${target}::object"} = $class->can('build_object');
  3         16  
15              
16 3         3509 return;
17             }
18              
19             sub build_args {
20 22 50   22 0 1105 my $left = shift or return;
21 22 50       37 my $right = shift or return;
22 22         16 my $data;
23              
24 22         38 my $hash = {%$left};
25 22 50       46 return $hash unless 'HASH' eq ref $right;
26              
27 22         50 while (my($key, $val) = each %$right) {
28 43 100       69 if ('HASH' eq ref $val) {
    100          
29 4         8 $hash->{$key} = build_args({}, $val);
30             }
31             elsif ('ARRAY' eq ref $val) {
32 6 50       16 $hash->{$key} = [
33 2         4 map { 'HASH' eq ref $_ ? build_args({}, $_) : $_ } @$val
34             ];
35             }
36             else {
37 37         83 $hash->{$key} = $val;
38             }
39             }
40              
41 22         70 return $hash;
42             }
43              
44             sub build_attribute ($$$) {
45 20     20 0 1099 my $class = shift;
46 20         19 my $key = shift;
47 20         13 my $value = shift;
48              
49 20   33     63 $class = ref($class) || $class;
50 20 100       47 my @default = (default => $value) if defined $value;
51 20         156 $class->can('has')->($key => (is => 'rw', @default));
52              
53 20         3491 return $value;
54             }
55              
56             my $serial = 0;
57             sub build_class (;$) {
58 13     13 0 5877 my $base = shift;
59 13         31 my $class = join '::', __PACKAGE__, 'Instance';
60              
61 13   66     42 $base //= $class;
62              
63 13         54 my $name = sprintf '%s::__ANON__::%04d', $class, ++$serial;
64 13   66     104 my $modern = $base->isa($class) || $base eq $class;
65 13 50       38 my $inherit = $modern ? "extends '$base'" : "use base '$base'";
66              
67 3     3   1958 eval join ';', ("package $name", "use Moo", $inherit);
  3     3   36922  
  3     3   14  
  3     3   20  
  3     1   3  
  3         14  
  3         13  
  3         4  
  3         10  
  3         15  
  3         5  
  3         10  
  1         5  
  1         1  
  1         4  
  13         996  
68 13 50       45104 croak $@ if $@;
69              
70 13         54 return $name;
71             }
72              
73             sub build_clone (@) {
74 8     8 0 16501 my $class = shift;
75 8         23 my $common = join '::', __PACKAGE__, 'Instance';
76              
77 8   33     39 my $base = ref($class) || $class;
78 8 50       17 my $args = ref($class) ? {%{$class}} : {};
  8         32  
79 8         20 build_properties(my $name = build_class($base), @_);
80              
81 8         21 return $name->new(
82 8 50       37 $base->isa($common) ? (%{build_args(build_args({},$args), {@_})}) : @_
83             );
84             }
85              
86             sub build_method ($$$) {
87 8     8 0 3596 my $class = shift;
88 8         6 my $key = shift;
89 8         10 my $value = shift;
90              
91 8   33     33 $class = ref($class) || $class;
92 8 50       17 return unless 'CODE' eq ref $value;
93              
94 3     3   19 no strict 'refs';
  3         8  
  3         126  
95 3     3   17 no warnings 'redefine';
  3         5  
  3         646  
96 8         9 *{"${class}::$key"} = $value;
  8         39  
97              
98 8         34 return $value;
99             }
100              
101             sub build_properties ($;@) {
102 12     12 0 19 my $class = shift;
103 12         35 my %properties = @_;
104              
105 12   33     45 $class = ref($class) || $class;
106 12         37 while (my ($key, $val) = each %properties) {
107 26         42 my $is_code = 'CODE' eq ref $val;
108 26 100 50     98 build_method $class, $key, $val and next if $val and $is_code;
      100        
109 19 100   0   51 build_attribute $class, $key, ref $val ? sub { $val } : $val;
  0         0  
110             }
111              
112 12         22 return;
113             }
114              
115             sub build_object (@) {
116 3     3 0 1966 build_properties(my $name = build_class, @_);
117 3         11 return $name->new;
118             }
119              
120             1;
121              
122             __END__