File Coverage

blib/lib/mixin/with.pm
Criterion Covered Total %
statement 19 19 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 24 24 100.0


line stmt bran cond sub pod time code
1             package mixin::with;
2              
3 8     8   275936 use strict;
  8         20  
  8         329  
4 8     8   46 no strict 'refs';
  8         14  
  8         252  
5 8     8   45 use vars qw($VERSION);
  8         18  
  8         3408  
6             $VERSION = 0.07;
7              
8             =head1 NAME
9              
10             mixin::with - declaring a mix-in class
11              
12             =head1 SYNOPSIS
13              
14             package Dog::Retriever;
15             use mixin::with 'Dog';
16              
17              
18             =head1 DESCRIPTION
19              
20             mixin::with is used to declare mix-in classes.
21              
22              
23             =head2 When to use a mixin?
24              
25             Mixin classes useful for those that I to an
26             existing class. If you find yourself doing:
27              
28             package Foo::ExtraStuff;
29             use base 'Foo';
30             sub new_method { ... }
31              
32             package Bar;
33             use base qw(Foo Foo::ExtraStuff);
34              
35             it's a good indication that Foo::ExtraStuff might do better as a mixin.
36              
37             Instead of mixins, please consider using traits. See L for an implementaiton.
38              
39              
40             =head2 How?
41              
42             Basic usage is simple:
43              
44             package Foo::Extra;
45             use mixin::with 'Foo';
46              
47             sub new_thing {
48             my($self) = shift;
49             ...normal method...
50             }
51              
52             C is I to subclassing from 'Foo'.
53              
54             All public methods of Foo::Extra will be mixed in. mixin::with
55             considers all methods that don't start with an '_' as public.
56              
57              
58             =head2 Limitations of mixins
59              
60             There's one critical difference between a normal subclass and one
61             intended to be mixin. It can have no private methods. Instead, use lexical methods.
62              
63             my $private = sub { ... };
64             $self->$private(@args);
65              
66             instead of
67              
68             sub _private { ... }
69             $self->_private(@args);
70              
71             Don't worry, it's the same thing.
72              
73              
74             =cut
75              
76             my %Mixers = ();
77             my $Tmp_Counter = 0;
78             sub import {
79 9     9   67 my($class, $mixed_with) = @_;
80 9         18 my $mixin = caller;
81              
82 9         37 my $tmp_pkg = __PACKAGE__.'::tmp'.$Tmp_Counter++;
83 9         34 $Mixers{$mixin} = { mixed_with => $mixed_with,
84             tmp_pkg => $tmp_pkg,
85             };
86              
87 9         48 require base;
88              
89 9         594 eval sprintf q{
90             package %s;
91             base->import($mixed_with);
92             }, $mixin;
93              
94 9         6902 return 1;
95             }
96              
97              
98             sub __mixers {
99 10     10   25 my($class, $mixin) = @_;
100              
101 10         17 return @{$Mixers{$mixin}}{'mixed_with', 'tmp_pkg'};
  10         59  
102             }
103              
104              
105             =head1 FAQ
106              
107             =over 4
108              
109             =item What if I want to mixin with anything?
110              
111             Sometimes a mixin does not care what it mixes in with. Consider a
112             logging or error handling mixin. For these, simply mixin with
113             UNIVERSAL.
114              
115             package My::Errors;
116             use mixin::with qw(UNIVERSAL);
117              
118              
119             =item Why do I have to declare what I mixin with?
120              
121             Two reasons. One is technical, it allows C to work.
122              
123             The other is organizational. It 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.
124              
125              
126             =item Why use mixins instead of traits?
127              
128             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.
129              
130             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.
131              
132             If these advantages don't apply, proceed directly to traits.
133              
134              
135             =head1 AUTHOR
136              
137             Michael G Schwern
138              
139             =head1 SEE ALSO
140              
141             L, L from which I stole this idea.
142              
143             =cut
144              
145             1;
146