File Coverage

lib/Class/Dot/Policy.pm
Criterion Covered Total %
statement 144 155 92.9
branch 36 40 90.0
condition 10 12 83.3
subroutine 28 31 90.3
pod 10 12 83.3
total 228 250 91.2


line stmt bran cond sub pod time code
1             # $Id$
2             # $Source: /opt/CVS/Getopt-LL/lib/Class/Dot.pm,v $
3             # $Author$
4             # $HeadURL$
5             # $Revision$
6             # $Date$
7             package Class::Dot::Policy;
8              
9 14     14   78 use strict;
  14         26  
  14         966  
10 14     14   76 use warnings;
  14         27  
  14         415  
11 14     14   66 use version qw(qv);
  14         25  
  14         73  
12 14     14   807 use 5.006000;
  14         41  
  14         968  
13              
14             our $VERSION = qv('2.0.0_15');
15             our $AUTHORITY = 'cpan:ASKSH';
16              
17             # Set to true if Class::Dot::XS loads OK.
18 14     14   83 use vars qw($XSokay); ## no critic
  14         23  
  14         729  
19              
20 14     14   75 use Carp qw(carp croak confess);
  14         33  
  14         1304  
21 14     14   76 use Scalar::Util qw(blessed);
  14         40  
  14         1286  
22 14     14   14723 use Class::Plugin::Util qw(require_class);
  14         165330  
  14         126  
23 14     14   801 use English qw(-no_match_vars);
  14         29  
  14         99  
24 14     14   41154 use Params::Util qw(_HASHLIKE);
  14         92639  
  14         1221  
25              
26 14     14   11627 use Class::Dot::Typemap qw(:std);
  14         64  
  14         113  
27              
28             # The global registry.
29 14     14   101 use Class::Dot::Registry;
  14         26  
  14         744  
30             our $REGISTRY = Class::Dot::Registry->new();
31              
32 14         92 use Class::Dot::Meta::Method qw(
33             install_sub_from_class
34             install_sub_from_coderef
35 14     14   97 );
  14         31  
36 14         91 use Class::Dot::Meta::Type qw(
37             _NEWSCHOOL_TYPE _OLDSCHOOL_TYPE
38 14     14   78 );
  14         24  
39              
40 14     14   80 use Class::Dot::Devel::Sub::Name qw(subname);
  14         34  
  14         156  
41              
42             # Try to load the Class::Dot::XS speed-up module.
43             {
44 14     14   83 no warnings 'all'; ## no critic
  14         37  
  14         41527  
45             $Class::Dot::XS::MAGIC_COOKIE = q{Knock. Knock. It's Class::Dot.};
46             if (require_class('Class::Dot::XS')) {
47             Class::Dot::XS->import();
48             }
49             }
50              
51             my @STD_EXPORT = qw(
52             property after_property_set after_property_get
53             extends composite composites has
54             );
55             my @ALWAYS_EXPORT_TO_POLICIES = (@STD_EXPORT, qw(
56             properties_for_class
57             finalize_class
58             ));
59              
60             push @STD_EXPORT, @Class::Dot::Typemap::STD_TYPES;
61              
62             my %EXPORT_CLASS = (
63             ':std' => [@STD_EXPORT],
64             ':new' => [@STD_EXPORT, qw(-new)],
65             ':fast' => [@STD_EXPORT, qw(-new -optimized)],
66             );
67              
68             # The list of allowed option tags.
69             my %ALLOWED_CLASS_OPTIONS = map { $_ => 1 } qw(
70             -new
71             -rebuild
72             -getter_prefix
73             -setter_prefix
74             -accessor_type
75             -metaclass
76             -constrained
77             -chained
78             -optimized
79             -override
80             -delegator
81             );
82              
83             my %DEFAULT_OPTIONS = (
84             '-getter_prefix' => q{},
85             '-setter_prefix' => 'set_',
86             '-metaclass' => 'Class::Dot::Meta::Class',
87             '-override' => undef,
88             );
89              
90             my @DELEGATOR_APPENDS_EXPORTS = qw(
91             delegates to using
92             );
93              
94             sub import {
95 15     15   43 my ($this_class) = @_;
96 15         41 my $caller_class = caller 0;
97              
98 15         113 for my $sub_name (@ALWAYS_EXPORT_TO_POLICIES) {
99 135         452 install_sub_from_class(
100             ($this_class, $sub_name) => $caller_class
101             );
102             };
103              
104 15         8052 return;
105             }
106              
107             sub _create_policy {
108 16     16   41 my ($this_class, $push_policy_ref, @args) = @_;
109              
110 16         40 my %mapped_args = map { $_ => 1 } @args;
  6         23  
111 16         32 for my $push_policy (@{ $push_policy_ref }) {
  16         37  
112 138         235 $mapped_args{$push_policy} = 1;
113             }
114 16         120 @args = keys %mapped_args;
115              
116 16 50       79 if ($mapped_args{-delegator}) {
117 0         0 push @args, @DELEGATOR_APPENDS_EXPORTS;
118             }
119              
120 16         121 return @args;
121             }
122              
123             sub _dotify_class {
124 33     33   95 my ($this_class, $caller_class, @args) = @_;
125              
126 33         47 my $export_class;
127             my @subs;
128 33         70 for my $arg (@args) {
129 178 100       349 if ($arg =~ m/^:/xms) {
130 14 100       245 croak( 'Only one export class can be used. '
131             ."(Used already: [$export_class] now: [$arg])")
132             if $export_class;
133              
134 13         35 $export_class = $arg;
135             }
136             else {
137 164         257 push @subs, $arg;
138             }
139             }
140              
141             my @subs_to_export
142 12         70 = $export_class && $EXPORT_CLASS{$export_class}
143 32 100 66     214 ? (@{ $EXPORT_CLASS{$export_class} }, @subs)
144             : @subs;
145              
146 32         179 my $options = $REGISTRY->get_options_for(
147             $caller_class, \%DEFAULT_OPTIONS
148             );
149 32         70 for my $sub_to_export (@subs_to_export) {
150 372 100       939 if ($sub_to_export =~ m/^-/xms) {
151 55         75 my $option = $sub_to_export;
152 55         78 my $value = 1;
153             # Can set values on the use-line with '=' assignment.
154 55 100       143 if ($option =~ m/=/xms) {
155 5         19 ($option, $value) = split m/=/xms, $option, 2;
156             }
157 55 50       140 croak __PACKAGE__.": Unknown class option: [$option]"
158             if not exists $ALLOWED_CLASS_OPTIONS{$option};
159 55         144 $options->{$option} = $value;
160             }
161             else {
162 317         780 install_sub_from_class($this_class,
163             $sub_to_export => $caller_class
164             );
165             }
166             }
167              
168             # ### Register the class.
169 32         147 $REGISTRY->register_class($caller_class);
170              
171             # ### Initialize metaclass for this class.
172 32 100       94 if (! $options->{'-new'}) {
173 3         7 $options->{'-no_constructor'} = 1;
174             }
175              
176 32         148 my $metaclass = $REGISTRY->init_metaclass_for(
177             $caller_class, $options->{'-metaclass'}, $options
178             );
179              
180 32         1389684 return;
181             }
182              
183             sub finalize_class {
184 2     2 1 4 my ($opt_class) = @_;
185 2 100       7 my $class = $opt_class ? $opt_class
186             : caller 0;
187 2         6 my $metaclass = $REGISTRY->get_metaclass_for($class);
188              
189 2         9 my $isa_cache =
190             $metaclass->property->traverse_isa_for_property($class);
191              
192 2         8 return $REGISTRY->finalize_class($class, $isa_cache);
193             }
194              
195             sub properties_for_class {
196 9     9 1 7016 my ($self, $class) = @_;
197 9         37 my $metaclass = $REGISTRY->get_metaclass_for($class);
198            
199 9         37 return $metaclass->property->properties_for_class($class);
200             }
201              
202             sub has ($;%) { ## no critic
203 90     90 1 677 my ($property, @args) = @_;
204 90         190 my $caller_class = caller 0;
205 90         528 my $metaclass = $REGISTRY->get_metaclass_for($caller_class);
206              
207 90 100       234 confess 'Property needs name'
208             if not defined $property;
209              
210 89         97 my $isa;
211              
212             # Decide what kind of args this is.
213             # If it's a newschool type or it's only one arg it is
214             # taken as the property's type.
215 89 100 100     340 if (_NEWSCHOOL_TYPE($args[0]) || scalar @args == 1) {
216 58         229 $isa = shift @args;
217             }
218              
219 89         118 my %options;
220 89 100       216 if (not scalar @args % 2) { # is even number.
    50          
221 87         228 %options = @args;
222             }
223             elsif (_HASHLIKE($args[-1])) {
224 2         3 %options = %{$args[-1]};
  2         6  
225             }
226              
227 89 100       224 if (defined $options{isa}) {
228 30         53 $isa = $options{isa};
229 30         51 my $default = $options{default};
230              
231             # Type names containing '::', means that we should composite the class
232             # with the class of that name. (see design/keywords.pm)
233 30 100 66     195 if (defined $isa && $isa =~ m{::}xms) {
234             # Class names that does not really have '::' in their name
235             # will have '::' tacked on the end, so remove it.
236 2         7 $isa =~ s{::$}{}xms;
237 2         10 return $metaclass->composites($property, $isa);
238             }
239            
240 28 50       76 if ($isa) {
241 28         185 my $type_init = Class::Dot::Typemap->get_type($isa);
242 28 100       95 confess "Unknown type constraint: $isa" if not $type_init;
243 27 100       119 $isa = defined $default ? $type_init->($default) : $type_init->();
244             }
245             }
246              
247             # Privacy is either 'privacy' or 'is'. It's the same thing, for now.
248 86   100     369 $options{privacy} ||= $options{is};
249              
250             # Get privacy option
251 86 100       275 if ($property =~ s/^-//xms) {
252 1         2 $options{privacy} = 'ro';
253             }
254 86 100       196 if ($property =~ s/^!//xms) {
255 1         2 $options{privacy} = 'xx';
256             }
257              
258              
259 86         251 return $metaclass->property->define_property(
260             $property, $isa => $caller_class, {
261             %options,
262             }
263             );
264             }
265              
266             sub property (@) { ## no critic
267 78     78 1 917 goto &has;
268             }
269              
270             sub extends (@;) { ## no critic
271 5     5 1 33 my (@superclasses) = @_;
272 5         14 my $inheritor = caller 0;
273 5         22 my $meta_class = $REGISTRY->get_metaclass_for($inheritor);
274              
275 5         24 return $meta_class->superclasses_for(
276             $inheritor => @superclasses
277             );
278             }
279              
280             sub composites (@;) { ## no critic
281 1     1 1 3 my ($attribute_name, $composite_class) = @_;
282 1         2 my $caller_class = caller 0;
283 1         4 my $metaclass = $REGISTRY->get_metaclass_for($caller_class);
284              
285 1         6 return $metaclass->composites($attribute_name, $composite_class);
286             };
287              
288             sub composite (@;) { ## no critic
289 1     1 1 3 goto &composites;
290             }
291              
292             sub after_property_get (@&) { ## no critic
293 1     1 1 3 my ($property, $func_ref) = @_;
294 1         3 my $caller_class = caller;
295              
296 1         6 my $class_meta = $REGISTRY->get_meta_for($caller_class);
297 1         12 my $getter_name = $class_meta->{$property}->getter_name();
298 1         5 install_sub_from_coderef($func_ref => $caller_class, $getter_name);
299              
300 1         4 return;
301             }
302              
303             sub after_property_set (@&) { ## no critic
304 1     1 1 3 my ($property, $func_ref) = @_;
305 1         3 my $caller_class = caller;
306              
307 1         5 my $class_meta = $REGISTRY->get_meta_for($caller_class);
308 1         9 my $setter_name = $class_meta->{$property}->setter_name();
309 1         7 install_sub_from_coderef($func_ref => $caller_class, $setter_name);
310              
311 1         4 return;
312             }
313              
314             # syntactic sugar.
315 0     0 1   sub to (@;) { @_ }
316 0     0 0   sub using (@;) { @_ }
317              
318             sub delegates ($) {
319 0     0 0   my ($to, $using) = @_;
320 0           my $class = caller 0;
321              
322 0           my @mods;
323 0           for my $alternative (@{ $using }) {
  0            
324 0           push @mods, modules_matching($_);
325             }
326            
327 0           $class->dot::meta::is_delegator($using, @mods);
328              
329 0           return;
330             }
331              
332             1;
333              
334             __END__