File Coverage

blib/lib/MooX/Prototype.pm
Criterion Covered Total %
statement 22 72 30.5
branch 0 22 0.0
condition 0 23 0.0
subroutine 6 14 42.8
pod 0 7 0.0
total 28 138 20.2


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