File Coverage

blib/lib/Rope/Object.pm
Criterion Covered Total %
statement 130 132 98.4
branch 78 86 90.7
condition 37 43 86.0
subroutine 19 21 90.4
pod 0 5 0.0
total 264 287 91.9


line stmt bran cond sub pod time code
1             package Rope::Object;
2              
3 55     55   297 use strict;
  55         84  
  55         1445  
4 55     55   173 use warnings;
  55         71  
  55         2027  
5              
6 55     55   19962 use Const::XS qw/make_readonly/;
  55         26711  
  55         87535  
7              
8             sub TIEHASH {
9 6385     6385   9433 my ($class, $obj) = @_;
10 6385   50     12125 my $self = bless $obj || {}, $class;
11             $self->{properties}->{ROPE_init} = {
12 6385     6385   9864 value => sub { $self->init }
13 6385         24776 };
14 6385         13584 return $self;
15             }
16              
17             sub init {
18 6385     6385 0 7251 my ($self) = @_;
19             $self->set_value(
20             $_,
21             $self->{properties}->{$_}->{value},
22             $self->{properties}->{$_}
23 6385         6529 ) for keys %{$self->{properties}};
  6385         21718  
24 6383         12287 $self->compile();
25 6382         12242 delete $self->{properties}->{ROPE_init};
26 6382         8123 $self;
27             }
28              
29             sub compile {
30 6385     6385 0 6902 my ($self) = @_;
31 6385         5760 $self->{keys} = scalar keys %{$self->{properties}};
  6385         10243  
32             $self->{sort_keys} = [sort {
33             $self->{properties}->{$a}->{index} <=> $self->{properties}->{$b}->{index}
34 6385         6422 } grep { $self->{properties}->{$_}->{enumerable} } keys %{$self->{properties}}];
  14128         34312  
  33020         45663  
  6385         10800  
35 6385 50       11226 if ($self->{requires}) {
36 6385         5813 for (keys %{$self->{requires}}) {
  6385         13328  
37             die sprintf "Failed to instantiate %s object requires property %s", $self->{name}, $_
38             unless $self->{properties}->{$_}
39 8 100 66     43 && defined $self->{properties}->{$_}->{value};
40             }
41             }
42 6384         6766 return $self;
43             }
44              
45             sub set_value {
46 45526     45526 0 56892 my ($self, $key, $value, $spec) = @_;
47 45526 100       55072 if ($spec->{trigger}) {
48 4186         7592 $value = $spec->{trigger}->($value);
49             }
50 45526 100 100     79506 if (ref($value || "") ne 'CODE') {
51 30375         31475 for (qw/before around after/) {
52 91125 100       119316 if ($spec->{$_}) {
53 69         158 my $val = $spec->{$_}->($value);
54 69 50       406 if (defined $val) {
55 69         99 $value = $val;
56             }
57             }
58             }
59             }
60 45526 100 66     58946 if ($spec->{type} && defined $value) {
61 27         161 $value = eval {
62             $spec->{coerce_type}
63             ? $spec->{type}->coerce($value)
64 27 50       104 : $spec->{type}->($value);
65             };
66 27 100       960 if ($@) {
67 3         22 my @caller = caller(1);
68 3 100       8 if ($caller[0] eq 'Rope::Object') {
69 1         4 die sprintf("Failed to instantiate object (%s) property (%s) failed type validation. %s", $self->{name}, $key, $@);
70             }
71 2         13 die sprintf("Cannot set property (%s) in object (%s) failed type validation on line %s file %s: %s", $key, $self->{name}, $caller[2], $caller[1], $@);
72             }
73             }
74              
75 45523 100       51837 if ($spec->{readonly}) {
76 6         13 make_readonly($value);
77             }
78              
79 45523 100       46998 if ($spec->{handles_via}) {
80 4         214 eval "require $spec->{handles_via}";
81 4         15 my $href = ref $value;
82 4 50       20 $spec->{value} = $spec->{handles_via}->new($href eq 'ARRAY' ? @{$value} : $href eq 'HASH' ? %{$value} : $value);
  2 100       14  
  2         13  
83             } else {
84 45519         50123 $spec->{value} = $value;
85             }
86              
87 45523 100 100     57513 if ($spec->{required} && ! defined $spec->{value}) {
88 1         12 die sprintf "Required property (%s) in object (%s) not set", $key, $self->{name};
89             }
90 45522         67169 return $spec->{value};
91             }
92            
93             sub STORE {
94 12540     12540   18722 my ($self, $key, $value) = @_;
95              
96 12540 100       16337 if ($key eq 'locked') {
97 4         6 $self->{locked} = $value;
98 4         9 return;
99             }
100 12536         14513 my $k = $self->{properties}->{$key};
101              
102 12536 100       14624 if ($k) {
    100          
103 12525 100       15607 if ($k->{private}) {
104 1         3 my $priv = $self->private_names;
105 1 50       3 if ( $self->current_caller !~ m/^($priv)$/) {
106 1         10 die "Cannot access Object ($self->{name}) property ($key) as it is private";
107             }
108             }
109              
110 12524 100       17799 if ($k->{writeable}) {
    100          
111 8226         13337 $self->set_value($key, $value, $k);
112             } elsif ($k->{configurable}) {
113 4287 100 100     13541 if ((ref($value) || "") eq (ref($k->{value}) || "")) {
      50        
114 4286         5851 $self->set_value($key, $value, $k);
115             } else {
116 1         10 die "Cannot change Object ($self->{name}) property ($key) type";
117             }
118             } else {
119 11         94 die "Cannot set Object ($self->{name}) property ($key) it is only readable";
120             }
121             } elsif (! $self->{locked}) {
122             $self->{properties}->{$key} = {
123             ((ref $value || "") eq 'HASH' && grep { defined $value->{$_} } qw/initable writeable configurable enumerable/) ? (
124             index => ++$self->{keys},
125 1         4 %{$value}
126             ) : (
127             value => $value,
128             initable => 1,
129             writeable => 1,
130             configurable => 1,
131             enumerable => 1,
132             index => ++$self->{keys}
133             )
134 7 100 100     74 };
135 7         14 push @{$self->{sort_keys}}, $key;
  7         19  
136             } else {
137 4         31 die "Object ($self->{name}) is locked you cannot extend with new properties";
138             }
139 12517         20817 return $self;
140             }
141            
142             sub FETCH {
143 25181     25181   41747 my ($self, $key) = @_;
144 25181   100     49869 my $k = $self->{properties}->{$key} || $self->{handles}->{$key} && $self->{properties}->{$self->{handles}->{$key}};
145 25181 100       68831 return undef unless defined $k->{value};
146 18756 100       24507 if ($k->{private}) {
147 7         14 my $priv = $self->private_names;
148 7 100       14 if ( $self->current_caller !~ m/^($priv)$/) {
149 2         30 die "Cannot access Object ($self->{name}) property ($key) as it is private";
150             }
151             }
152            
153 18754 100 100     56498 if (!$k->{writeable} && !$k->{configurable} && (ref($k->{value}) || '') eq 'CODE') {
      100        
      100        
154 7130 100 100     20059 if ($k->{before} || $k->{after} || $k->{around}) {
      100        
155             return sub {
156 75     75   129 my (@params) = @_;
157 75         94 my @new_params;
158 75 100       191 @new_params = $k->{before}->(@params) if $k->{before};
159 75 100       152 @params = @new_params if scalar @new_params;
160 75 100       180 if ($k->{around}) {
161 41         134 @params = $k->{around}->($k->{value}, @params);
162             } else {
163 34         101 @params = $k->{value}->(@params);
164             }
165 75 100       1235 if ($k->{after}) {
166 33         101 @new_params = ($k->{after}->(@params));
167 31 50       219 @params = @new_params if scalar @new_params;
168             }
169 73 100       399 return wantarray ? @params : $params[0];
170 89         642 };
171             }
172             }
173            
174 18665 100 66     30316 if ($self->{handles}->{$key} && !$self->{properties}->{ROPE_init}) {
175 20         25 my $meth = $k->{handles}->{$key};
176 20 50       33 if ($k->{value}) {
177 20     13   100 return sub { $k->{value}->$meth(@_) };
  13         53  
178             }
179             }
180              
181 18645         46631 return $k->{value};
182             }
183            
184             sub FIRSTKEY {
185 11     11   42 goto &NEXTKEY;
186             }
187            
188             sub NEXTKEY {
189 32     32   41 return (each @{$_[0]->{sort_keys}})[1];
  32         111  
190             }
191            
192             sub EXISTS {
193 3     3   14 exists $_[0]->{properties}->{$_[1]};
194             }
195            
196             sub DELETE {
197 3     3   7 my $k = $_[0]->{properties}->{$_[1]};
198 3 100       8 if ($k->{delete_trigger}) {
199 1         4 $k->{delete_trigger}->($k->{value});
200             }
201 3 100 66     17 my $del = !$_[0]->{locked} && $k->{writeable} ? delete $_[0]->{properties}->{$_[1]} : undef;
202 3 100       7 $_[0]->compile() if $del;
203 3         8 return $del;
204             }
205            
206             sub CLEAR {
207 0     0   0 return;
208             #%{$_[0]->{properties}} = ()
209             }
210            
211             sub SCALAR {
212 1     1   2 scalar keys %{$_[0]->{properties}}
  1         3  
213             }
214              
215       0     sub DESTROY { }
216              
217             sub private_names {
218 8     8 0 12 my $self = shift;
219 8 50       57 return $self->{name} . ($self->{with} ? ('|' . join('|', @{$self->{with}})) : '') . ($self->{extends} ? ('|' . join('|', @{$self->{extends}})) : '');
  0 100       0  
  3         13  
220             }
221              
222             sub current_caller {
223 8     8 0 12 my ($n, $caller) = (0, '');
224 8         28 while (my $call = scalar caller($n)) {
225 22 100       83 if ($call !~ m/Rope(::(Object|Autoload|Monkey))?/) {
226 8         165 return $call;
227             }
228 14         46 $n++;
229             }
230             }
231              
232             1;
233              
234             __END__