File Coverage

blib/lib/mixin/with.pm
Criterion Covered Total %
statement 22 22 100.0
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 28 28 100.0


line stmt bran cond sub pod time code
1             package mixin::with;
2              
3 8     8   160328 use strict;
  8         19  
  8         198  
4 8     8   40 use warnings;
  8         15  
  8         212  
5 8     8   37 no strict 'refs';
  8         18  
  8         224  
6 8     8   43 use vars qw($VERSION);
  8         15  
  8         1759  
7             $VERSION = 0.07;
8              
9             =head1 NAME
10              
11             mixin::with - declaring a mix-in class
12              
13             =head1 SYNOPSIS
14              
15             package Dog::Retriever;
16             use mixin::with 'Dog';
17              
18              
19             =head1 DESCRIPTION
20              
21             mixin::with is used to declare mix-in classes.
22              
23              
24             =head2 When to use a mixin?
25              
26             Mixin classes useful for those that I to an
27             existing class. If you find yourself doing:
28              
29             package Foo::ExtraStuff;
30             use base 'Foo';
31             sub new_method { ... }
32              
33             package Bar;
34             use base qw(Foo Foo::ExtraStuff);
35              
36             it's a good indication that Foo::ExtraStuff might do better as a mixin.
37              
38             Instead of mixins, please consider using traits. See L for an implementaiton.
39              
40              
41             =head2 How?
42              
43             Basic usage is simple:
44              
45             package Foo::Extra;
46             use mixin::with 'Foo';
47              
48             sub new_thing {
49             my($self) = shift;
50             ...normal method...
51             }
52              
53             C is I to subclassing from 'Foo'.
54              
55             All public methods of Foo::Extra will be mixed in. mixin::with
56             considers all methods that don't start with an '_' as public.
57              
58              
59             =head2 Limitations of mixins
60              
61             There's one critical difference between a normal subclass and one
62             intended to be mixin. It can have no private methods. Instead, use lexical methods.
63              
64             my $private = sub { ... };
65             $self->$private(@args);
66              
67             instead of
68              
69             sub _private { ... }
70             $self->_private(@args);
71              
72             Don't worry, it's the same thing.
73              
74              
75             =cut
76              
77             my %Mixers = ();
78             my $Tmp_Counter = 0;
79             sub import {
80 9     9   65 my($class, $mixed_with) = @_;
81 9         22 my $mixin = caller;
82              
83 9         27 my $tmp_pkg = __PACKAGE__.'::tmp'.$Tmp_Counter++;
84 9         33 $Mixers{$mixin} = { mixed_with => $mixed_with,
85             tmp_pkg => $tmp_pkg,
86             };
87              
88 9         43 require base;
89              
90 9         530 eval sprintf q{
91             package %s;
92             base->import($mixed_with);
93             }, $mixin;
94              
95 9         2134 return 1;
96             }
97              
98              
99             sub __mixers {
100 10     10   17 my($class, $mixin) = @_;
101              
102 10         20 return @{$Mixers{$mixin}}{'mixed_with', 'tmp_pkg'};
  10         55  
103             }
104              
105              
106             =head1 FAQ
107              
108             =over 4
109              
110             =item What if I want to mixin with anything?
111              
112             Sometimes a mixin does not care what it mixes in with. Consider a
113             logging or error handling mixin. For these, simply mixin with
114             UNIVERSAL.
115              
116             package My::Errors;
117             use mixin::with qw(UNIVERSAL);
118              
119              
120             =item Why do I have to declare what I mixin with?
121              
122             Two reasons. One is technical, it allows C to work.
123              
124             The other is organizational. It is rare that a mixin is intended to be mixed with any old class. It often uses methods as if it were a subclass. For this reason it is good that it declares this relationship explicitly else the mixee won't be aware of the mixin's expectations.
125              
126              
127             =item Why use mixins instead of traits?
128              
129             Good question. Traits are definately a better idea then mixins, but mixins have two advantages. They're simpler to explain, acting like a gateway drug to traits by introducing the concept of OO reuse by class composition rather than inheritance.
130              
131             The other is mixins work more like a drop-in replacement for multiple inheritance. In a large, hairy hierarchy mixins can often be used to trim the inheritance bush and make sense of things with a minimum of modification to the code. Once this basic repair is done, the work of converting to traits can begin.
132              
133             If these advantages don't apply, proceed directly to traits.
134              
135             =back
136              
137             =head1 AUTHOR
138              
139             Michael G Schwern
140              
141             =head1 LICENSE
142              
143             Copyright 2002-2010 by Michael G Schwern
144              
145             This library is free software; you can redistribute it and/or modify it
146             under the same terms as Perl itself.
147              
148             L
149              
150             =head1 SEE ALSO
151              
152             L, L from which I stole this idea.
153              
154             =cut
155              
156             1;
157