File Coverage

blib/lib/Class/Mix.pm
Criterion Covered Total %
statement 68 68 100.0
branch 28 30 93.3
condition 22 27 81.4
subroutine 13 13 100.0
pod 2 2 100.0
total 133 140 95.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Class::Mix - dynamic class mixing
4              
5             =head1 SYNOPSIS
6              
7             use Class::Mix qw(mix_class);
8              
9             $foobar_object = mix_class("Foo", "Bar")->new;
10             $digest_class = mix_class("Foo", "Bar", {prefix=>"Digest::"});
11              
12             use Class::Mix qw(genpkg);
13              
14             $package = genpkg;
15             $package = genpkg("Digest::Foo::");
16              
17             =head1 DESCRIPTION
18              
19             The C function provided by this module dynamically generates
20             `anonymous' classes with specified inheritance.
21              
22             =cut
23              
24             package Class::Mix;
25              
26 3     3   85172 { use 5.006; }
  3         12  
  3         146  
27 3     3   16 use warnings;
  3         5  
  3         78  
28 3     3   27 use strict;
  3         28  
  3         158  
29              
30 3     3   16 use constant _DO_MRO => "$]" >= 5.009005;
  3         5  
  3         294  
31              
32 3     3   23 use Carp qw(croak);
  3         6  
  3         245  
33 3     3   4057 use Params::Classify 0.000 qw(is_undef is_string is_ref);
  3         7599  
  3         309  
34 3     3   3176 use if _DO_MRO, "mro";
  3         31  
  3         15  
35              
36             our $VERSION = "0.005";
37              
38 3     3   4629 use parent "Exporter";
  3         8  
  3         21  
39             our @EXPORT_OK = qw(mix_class genpkg);
40              
41             BEGIN {
42 3     3   345 if(_DO_MRO) {
43 3         1832 *_get_mro = \&mro::get_mro;
44             } else {
45             *_get_mro = sub ($) { "dfs" };
46             }
47             }
48              
49             my $prefix_rx = qr/(?:[a-zA-Z_][0-9a-zA-Z_]*::(?:[0-9a-zA-Z_]+::)*)?/;
50              
51             =head1 FUNCTIONS
52              
53             =over
54              
55             =item mix_class(ITEMS ...)
56              
57             This function is used to dynamically generate `anonymous' classes by
58             mixing pre-existing classes. This is useful where an incomplete class
59             requires use of a mixin in order to become instantiable, several suitable
60             mixins are available, and it is desired to make the choice between mixins
61             at runtime.
62              
63             Each I in the argument list is either the name of a class to inherit
64             from (a parent class) or a reference to a hash of options. The C<@ISA>
65             list of the mixture class is set to the list of parent class names,
66             in the order supplied. The options that may be supplied are:
67              
68             =over
69              
70             =item B
71              
72             Specifies the desired method resolution order (MRO) of the mixture class.
73             See L for details of the valid values and the default determined
74             by Perl. Typically, this should be set to B if mixing into an
75             existing C3-based class hierarchy.
76              
77             =item B
78              
79             Specifies where the resulting package will go. May be C to
80             indicate that the caller doesn't care (which is the default state).
81             Otherwise it must be either the empty string (to create a top-level
82             package) or a bareword followed by "::" (to create a package under
83             that name). For example, "Digest::" could be specified to ensure that
84             the resulting package has a name starting with "Digest::", so that C<<
85             Digest->new >> will accept it as the name of a message digest algorithm.
86              
87             =back
88              
89             The function generates a class of the form described by the arguments, and
90             returns its name. The same class will be returned by repeated invocations
91             with the same parent class list and options. The returned name may be
92             used to call a constructor or other class methods of the mixed class.
93              
94             A class name must be returned because there is no such thing as an
95             anonymous class in Perl. Classes are referenced by name. The names
96             that are generated by this function are unique and insignificant.
97             See C below for more information.
98              
99             If fewer than two classes to inherit from are specified, the function
100             tries to avoid generating a separate class for the mixture. If only
101             one parent class is specified then that class may be returned, and if
102             no parent classes are specified then C may be returned.
103             This provides the desired inheritance without creating superfluous
104             classes. These special cases only apply if the options are compatible
105             with the pre-existing class.
106              
107             This function relies on the classes it returns remaining unmodified in
108             order to be returned by future invocations. If you want to modify your
109             dynamically-generated `anonymous' classes, use C (below).
110              
111             =cut
112              
113             sub genpkg(;$);
114              
115             my %mixtures;
116             sub mix_class(@) {
117 62     62 1 40461 my @parents;
118             my %options;
119 62         147 foreach(@_) {
120 110 100       263 if(is_string($_)) {
    100          
121 63         178 push @parents, $_;
122             } elsif(is_ref($_, "HASH")) {
123 45         138 foreach my $k (keys %$_) {
124 39 50       100 croak "clashing option `$k'"
125             if exists $options{$k};
126 39         172 $options{$k} = $_->{$k};
127             }
128             } else {
129 2         305 croak "bad argument for mix_class";
130             }
131             }
132 60         140 foreach(keys %options) {
133 39 100       378 croak "bad option `$_' for mix_class"
134             unless /\A(?:mro|prefix)\z/;
135             }
136 58 100       194 $options{mro} = "dfs" unless exists $options{mro};
137 58 100       1403 croak "bad mro value" unless is_string($options{mro});
138 52 100       150 $options{prefix} = undef unless exists $options{prefix};
139 52 100 66     479 croak "bad prefix value" unless
      66        
140             is_undef($options{prefix}) ||
141             (is_string($options{prefix}) &&
142             $options{prefix} =~ /\A$prefix_rx\z/o);
143 50 100 100     880 return "UNIVERSAL" if @parents == 0 &&
      100        
      66        
144             $options{mro} eq _get_mro("UNIVERSAL") &&
145             (is_undef($options{prefix}) || $options{prefix} eq "");
146 43 100 100     507 return $parents[0] if @parents == 1 &&
      100        
      66        
147             $options{mro} eq _get_mro($parents[0]) &&
148             (is_undef($options{prefix}) ||
149             $parents[0] =~ /\A\Q$options{prefix}\E[^:]*\z/);
150 28 100       102 $options{prefix} = "Class::Mix::" unless defined $options{prefix};
151 28         64 my $recipe = join("", map { length($_)."_".$_ }
  95         242  
152             $options{mro}, $options{prefix}, @parents);
153 28   66     158 return $mixtures{$recipe} ||= do {
154 16         52 my $pkg = genpkg($options{prefix});
155 3     3   19 no strict "refs";
  3         29  
  3         516  
156 16         22 @{$pkg."::ISA"} = @parents;
  16         317  
157 16 100       111 mro::set_mro($pkg, $options{mro}) if $options{mro} ne "dfs";
158 13         73 $pkg;
159             };
160             }
161              
162             =item genpkg([PREFIX])
163              
164             This function selects and returns a package name that has not been
165             previously used. The name returned is an ordinary bareword-form package
166             name, and can be used as the second argument to C and in all
167             other ways that package names are used. The package is initially empty.
168              
169             The package names returned by this function are of a type that should not
170             be used as ordinary fixed module names. However, it is not possible to
171             entirely prevent a clash. This function checks that the package name it
172             is about to return has not already been used, and will avoid returning
173             such names, but it cannot guarantee that a later-loaded module will not
174             create a clash.
175              
176             PREFIX, if present, specifies where the resulting package will go.
177             It must be either the empty string (to create a top-level package)
178             or a bareword followed by "::" (to create a package under that name).
179             For example, "Digest::" could be specified to ensure that the resulting
180             package has a name starting with "Digest::", so that C<< Digest->new >>
181             will accept it as the name of a message digest algorithm. If the PREFIX
182             is not supplied, the caller is not expressing any preference.
183              
184             =cut
185              
186             my $n = 0;
187             sub genpkg(;$) {
188 22     22 1 43 my($prefix) = @_;
189 22 100       55 $prefix = "Class::Mix::" unless defined $prefix;
190 22 50       224 croak "`$prefix' is not a valid module name prefix"
191             unless $prefix =~ /\A$prefix_rx\z/o;
192 3     3   15 no strict "refs";
  3         7  
  3         344  
193 22         31 my $pkgtail;
194 25 100       127 do {
195 25         51 $pkgtail = "__GP".$n++;
196 22         26 } while(exists ${$prefix || "::"}{$pkgtail."::"});
197 22         44 my $pkgname = $prefix.$pkgtail;
198 22         30 %{$pkgname."::"} = ();
  22         183  
199 22         71 return $pkgname;
200             }
201              
202             =back
203              
204             =head1 SEE ALSO
205              
206             L,
207             L
208              
209             =head1 AUTHOR
210              
211             Andrew Main (Zefram)
212              
213             =head1 COPYRIGHT
214              
215             Copyright (C) 2004, 2006, 2009, 2010, 2011
216             Andrew Main (Zefram)
217              
218             =head1 LICENSE
219              
220             This module is free software; you can redistribute it and/or modify it
221             under the same terms as Perl itself.
222              
223             =cut
224              
225             1;