File Coverage

blib/lib/Rope.pm
Criterion Covered Total %
statement 83 102 81.3
branch 12 30 40.0
condition 2 11 18.1
subroutine 12 13 92.3
pod n/a
total 109 156 69.8


line stmt bran cond sub pod time code
1             package Rope;
2              
3 4     4   276486 use 5.006; use strict; use warnings;
  4     4   44  
  4     4   24  
  4         6  
  4         91  
  4         19  
  4         6  
  4         185  
4             our $VERSION = '0.01';
5              
6 4     4   1707 use Rope::Object;
  4         10  
  4         214  
7             my (%META, %PRO);
8             BEGIN {
9             %PRO = (
10             keyword => sub {
11 36         68 my ($caller, $method, $cb) = @_;
12 4     4   24 no strict 'refs';
  4         14  
  4         4556  
13 36         43 *{"${caller}::${method}"} = $cb;
  36         3502  
14             },
15             scope => sub {
16 5         17 my ($self, %props) = @_;
17 5         9 for (keys %{$props{properties}}) {
  5         18  
18 13         18 $props{properties}->{$_} = {%{$props{properties}{$_}}};
  13         67  
19 13 100 66     102 if ($props{properties}{$_}{value} && ref $props{properties}{$_}{value} eq 'CODE') {
20 11         21 my $cb = $props{properties}{$_}{value};
21 11         40 $props{properties}{$_}{value} = sub { $cb->($self, @_) };
  10         27  
22             }
23             }
24 5         39 return \%props;
25             },
26             clone => sub {
27 32         38 my $obj = shift;
28 32         42 my $ref = ref $obj;
29 32 100       79 return $obj if !$ref;
30 12 50       21 return [ map { $PRO{clone}->($_) } @{$obj} ] if $ref eq 'ARRAY';
  0         0  
  0         0  
31 12 100       21 return { map { $_ => $PRO{clone}->($obj->{$_}) } keys %{$obj} } if $ref eq 'HASH';
  30         66  
  8         19  
32 4         13 return $obj;
33             },
34             property => sub {
35 6         11 my ($caller) = shift;
36             return sub {
37 1     1   13 my ($prop, @options) = @_;
38 1 50       6 if (scalar @options % 2) {
39 0         0 $prop = shift @options;
40             }
41 1         6 $META{$caller}{properties}{$prop} = {
42             @options,
43             class => $caller
44             };
45 6         40 };
46             },
47             prototyped => sub {
48 6         13 my ($caller) = shift;
49             return sub {
50 5     5   219 my ($proto) = @_;
51 5         7 for (keys %{$proto}) {
  5         18  
52 7 50       25 if ($META{$caller}{properties}{$_}) {
53 0 0       0 if ($META{$caller}{properties}{$_}{writeable}) {
    0          
54 0         0 $META{$caller}{properties}{$_}{value} = $proto->{$_};
55 0         0 $META{$caller}{properties}{$_}{class} = $caller;
56             } elsif ($META{$caller}{properties}{configurable}) {
57 0 0 0     0 if ((ref($META{$caller}{properties}{$_}{value}) || "") eq (ref($proto->{$_}) || "")) {
      0        
58 0         0 $META{$caller}{properties}{$_}{value} = $proto->{$_};
59 0         0 $META{$caller}{properties}{$_}{class} = $caller;
60             } else {
61 0         0 die "Cannot inherit $META{$caller}{properties}{$_}{class} and change property $_ type";
62             }
63             } else {
64 0         0 die "Cannot inherit $META{$caller}{properties}{$_}{class} and change property $_ type";
65             }
66             } else {
67             $META{$caller}{properties}{$_} = {
68 7         34 value => $proto->{$_},
69             writable => 1,
70             enumerable => 1,
71             configurable => 1,
72             class => $caller
73             };
74             }
75             }
76             }
77 6         23 },
78             extends => sub {
79 6         13 my ($caller) = shift;
80             return sub {
81 2     2   16 my (@extends) = @_;
82 2         9 for my $extend (@extends) {
83 2 100       15 if (!$META{$extend}) {
84 1         3 (my $name = $extend) =~ s!::!/!g;
85 1         2 $name .= ".pm";
86 1         327 CORE::require($name);
87             }
88 2         12 my $initial = $META{$caller};
89 2         11 my $merge = $PRO{clone}($META{$extend});
90 2         6 $merge->{name} = $initial->{name};
91 2         12 $merge->{locked} = $initial->{locked};
92 2         4 for (keys %{$initial->{properties}}) {
  2         5  
93 0 0       0 if ($merge->{properties}->{$_}) {
94 0 0       0 if ($merge->{properties}->{writeable}) {
    0          
95 0         0 $merge->{properties}->{$_} = $initial->{properties}->{$_};
96             } elsif ($merge->{properties}->{configurable}) {
97 0 0 0     0 if ((ref($merge->{properties}->{$_}->{value}) || "") eq (ref($initial->{properties}->{$_}->{value} || ""))) {
      0        
98 0         0 $merge->{properties}->{$_} = $initial->{properties}->{$_};
99             } else {
100 0         0 die "Cannot inherit $extend and change property $_ type";
101             }
102             } else {
103 0         0 die "Cannot inherit $extend and override property $_";
104             }
105             } else {
106 0         0 $merge->{properties}->{$_} = $initial->{properties}->{$_};
107             }
108             }
109 2         9 $META{$caller} = $merge;
110             }
111             }
112 6         21 },
113             new => sub {
114 6         12 my ($caller) = shift;
115             return sub {
116 5     5   1109 my ($class, %params) = @_;
117 5         20 my $self = \{
118             prototype => {},
119             };
120 5         15 $self = bless $self, $caller;
121 5         9 tie %{${$self}->{prototype}}, 'Rope::Object', $PRO{scope}($self, %{$META{$caller}});
  5         8  
  5         125  
  5         50  
122 5         21 for (keys %params) {
123 2         5 $self->{$_} = $params{$_};
124             }
125 5         16 return $self;
126 6         21 };
127             }
128 4     4   852 );
129             }
130              
131             sub import {
132 6     6   66 my ($pkg, $options, $caller) = (shift, {}, caller());
133 6 50       31 if (!$META{$caller}) {
134 6         22 $META{$caller} = {
135             name => $caller,
136             locked => 0,
137             properties => {}
138             };
139             }
140 6     0   35 $PRO{keyword}($caller, '((', sub {});
141             $PRO{keyword}($caller, '(%{}', sub {
142 20     20   4448 ${$_[0]}->{prototype};
  20         115  
143 6         23 });
144             $PRO{keyword}($caller, $_, $PRO{$_}($caller))
145 6         21 for qw/property prototyped extends new/;
146             }
147              
148             1;
149              
150             __END__