File Coverage

blib/lib/JOAP/Proxy/Package/Class.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             # JOAP::Proxy::Package::Class -- Base package for JOAP Class classes
2             #
3             # Copyright (c) 2003, Evan Prodromou
4             #
5             # This library is free software; you can redistribute it and/or
6             # modify it under the terms of the GNU Lesser General Public
7             # License as published by the Free Software Foundation; either
8             # version 2.1 of the License, or (at your option) any later version.
9             #
10             # This library is distributed in the hope that it will be useful,
11             # but WITHOUT ANY WARRANTY; without even the implied warranty of
12             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13             # Lesser General Public License for more details.
14             #
15             # You should have received a copy of the GNU Lesser General Public
16             # License along with this library; if not, write to the Free Software
17             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18              
19             # tag: JOAP proxy class base class
20              
21 1     1   2402 use 5.008;
  1         4  
  1         50  
22 1     1   7 use strict;
  1         2  
  1         38  
23 1     1   6 use warnings;
  1         2  
  1         46  
24              
25             package JOAP::Proxy::Package::Class;
26 1     1   56 use JOAP::Proxy::Package;
  0            
  0            
27             use JOAP::Proxy::Class;
28             use JOAP::Proxy::Instance;
29             use JOAP::Proxy::Error;
30             use Symbol;
31             use base qw/JOAP::Proxy::Package JOAP::Proxy::Class JOAP::Proxy::Instance/;
32              
33             our %EXPORT_TAGS = ( 'all' => [ qw// ] );
34             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
35             our @EXPORT = qw//;
36              
37             our $VERSION = $JOAP::VERSION;
38              
39             JOAP::Proxy::Package::Class->mk_classdata('Address');
40             JOAP::Proxy::Package::Class->mk_classdata('Superclasses');
41              
42             JOAP::Proxy::Package::Class->Address('');
43             JOAP::Proxy::Package::Class->Superclasses([]);
44              
45             sub superclasses {
46             my $self = shift;
47             return $self->Superclasses(@_);
48             }
49              
50             sub address {
51             my $self = shift;
52             if (!ref($self)) {
53             return $self->Address(@_);
54             } else {
55             return $self->JOAP::Proxy::Instance::address(@_);
56             }
57             }
58              
59             sub add {
60              
61             my $self = shift;
62              
63             if (ref($self)) {
64             throw JOAP::Proxy::Error::Local("Can't add to an instance.");
65             } else {
66             $self->SUPER::add(@_);
67             }
68             }
69              
70             # we meddle with this so we can return our own instance instead of a generic JOAP::Proxy::Instance
71              
72             sub _get_instance {
73              
74             my $self = shift;
75             my $addr = shift;
76              
77             return $self->get($addr);
78             }
79              
80             sub search {
81              
82             my $self = shift;
83              
84             if (ref($self)) {
85             throw JOAP::Proxy::Error::Local("Can't search an instance.");
86             } else {
87             $self->SUPER::search(@_);
88             }
89             }
90              
91             sub delete {
92              
93             my $self = shift;
94              
95             if (!ref($self)) {
96             throw JOAP::Proxy::Error::Local("Can't call delete on a class.");
97             } else {
98             $self->SUPER::delete(@_);
99             }
100             }
101              
102             sub can {
103              
104             my($self) = shift;
105             my($name) = shift;
106             my($func) = $self->UNIVERSAL::can($name); # See if it's findable by standard lookup.
107              
108             if (!defined($func)) { # if not, see if it's something we should make ourselves.
109             if (my $methdesc = $self->_method_descriptor($name)) {
110             if ($methdesc->{allocation} eq 'class') {
111             $func = $self->_proxy_method($methdesc);
112             } elsif (ref($self)) {
113             $func = $self->_proxy_instance_method($methdesc);
114             }
115             } elsif (my $attrdesc = $self->_attribute_descriptor($name)) {
116             if (ref($self) && $attrdesc->{allocation} ne 'class') {
117             $func = $self->_proxy_instance_accessor($attrdesc);
118             } elsif ($attrdesc->{allocation} eq 'class') {
119             $func = $self->_proxy_class_accessor($attrdesc);
120             }
121             }
122             }
123              
124             return $func;
125             }
126              
127             # internal setter
128              
129             sub _set {
130              
131             my $self = shift;
132             my $name = shift;
133             my $value = shift;
134             my $allocation = $self->_attribute_descriptor($name)->{allocation};
135              
136             if ($allocation eq 'class') {
137             my $pkg = ref($self) || $self;
138             my $globref = qualify_to_ref($pkg . "::" . $name);
139             my $sref = *$globref{SCALAR};
140             $$sref = $value;
141             } elsif (ref($self)) {
142             $self->{$name} = $value;
143             }
144             }
145              
146             sub _describe {
147              
148             my $self = shift;
149             my $resp = $self->SUPER::_describe(@_);
150             my $describe = $resp->GetQuery;
151              
152             my @supers = $describe->GetSuperclass;
153              
154             $self->Superclasses(\@supers);
155              
156             return $resp;
157             }
158              
159             # We need to overload this to get only instance or class attributes,
160             # depending on the type of self.
161              
162             sub _default_edit_attrs {
163              
164             my $self = shift;
165              
166             if (ref($self)) {
167             return $self->JOAP::Proxy::Instance::_default_edit_attrs;
168             } else {
169             return $self->JOAP::Proxy::Class::_default_edit_attrs;
170             }
171             }
172              
173             sub _proxy_instance_accessor {
174              
175             my $self = shift;
176             my $descriptor = shift;
177              
178             my $name = $descriptor->{name};
179             my $writable = $descriptor->{writable};
180             my $type = $descriptor->{type};
181              
182             my $acc = $self->JOAP::Proxy::Instance::_proxy_accessor($descriptor);
183              
184             my $func = sub {
185             my $self = shift;
186             if (!ref($self)) {
187             throw JOAP::Proxy::Error::Local("Can't use instance accessor on a class.");
188             }
189             return $self->$acc(@_);
190             };
191              
192             return $func;
193             }
194              
195             sub _proxy_instance_method {
196              
197             my $self = shift;
198             my $descriptor = shift;
199              
200             my $meth = $self->JOAP::Proxy::Instance::_proxy_method($descriptor);
201              
202             my $func = sub {
203             my $self = shift;
204             if (!ref($self)) {
205             throw JOAP::Proxy::Error::Local("Can't use instance method on a class.");
206             }
207             return $self->$meth(@_);
208             };
209              
210             return $func;
211             }
212              
213             sub _proxy_class_accessor {
214              
215             my $self = shift;
216             my $descriptor = shift;
217             my $pkg = ref($self) || $self;
218              
219             my $name = $descriptor->{name};
220             my $writable = $descriptor->{writable};
221             my $type = $descriptor->{type};
222              
223             my $globref = qualify_to_ref($pkg . "::" . $name);
224             my $sref = *$globref{SCALAR};
225              
226             my $func = undef;
227              
228             # This is kind of wordy, but we need to unwrap the $writable
229             # stuff at compile time rather than run time.
230              
231             # XXX: choose a coercion function at compile-time
232              
233             if ($writable) {
234             $func = sub {
235             my($self) = shift;
236             return (@_) ? $$sref = JOAP->coerce($type, @_) : $$sref;
237             };
238             } else {
239             $func = sub {
240             my($self) = shift;
241             throw JOAP::Proxy::Error::Local("Read-only attribute $name") if @_;
242             return $$sref;
243             };
244             }
245              
246             return $func;
247             }
248              
249             sub instance_method {
250             my $self = shift;
251             my $name = shift;
252              
253             my $desc = $self->_method_descriptor($name);
254             my $method = $self->_proxy_instance_method($desc);
255             }
256              
257             sub class_method {
258             my $self = shift;
259             my $name = shift;
260              
261             my $desc = $self->_method_descriptor($name);
262             my $method = $self->_proxy_method($desc);
263             }
264              
265             sub instance_accessor {
266             my $self = shift;
267             my $name = shift;
268              
269             my $desc = $self->_attribute_descriptor($name);
270             my $accessor = $self->_proxy_instance_accessor($desc);
271             }
272              
273             sub class_accessor {
274             my $self = shift;
275             my $name = shift;
276              
277             my $desc = $self->_attribute_descriptor($name);
278             my $accessor = $self->_proxy_class_accessor($desc);
279             }
280              
281             1; # the loneliest number
282              
283             __END__