File Coverage

blib/lib/Class/TransparentFactory.pm
Criterion Covered Total %
statement 18 18 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 23 23 100.0


line stmt bran cond sub pod time code
1             package Class::TransparentFactory;
2              
3 2     2   48479 use warnings;
  2         4  
  2         60  
4 2     2   10 use strict;
  2         4  
  2         328  
5              
6             =head1 NAME
7              
8             Class::TransparentFactory - Transparently choose a provider class with an automatic facade
9              
10             =cut
11              
12             our $VERSION = '0.02';
13              
14             =head1 SYNOPSIS
15              
16             package LooksLikeOneClass;
17             use Class::TransparentFactory qw(new foo bar);
18             sub impl {
19             $class = today_is_a_weekday() ? "WeekdayProvider" : "WeekendProvider";
20             require $class;
21             return $class;
22             }
23              
24             package UserCode;
25             use LooksLikeOneClass;
26             LooksLikeOneClass->foo(); # WeekdayProvider::foo or WeekendProvider::foo
27             # depending on whether today_is_a_weekday().
28              
29              
30             =head1 DESCRIPTION
31              
32             This module is intended for developers who find they need to refactor
33             code away from one provider of functionality to a factory + set of
34             API-compatible providers. It's not that factories are very difficult to
35             write or maintain, but code that uses them tends to be somewhat cluttered.
36              
37             With Class-TransparentFactory, your user code remains exactly as it was
38             before you split off to several providers; the original module class
39             turns into a facade in which class methods are automatically turned into
40             proxies for the appropriate provider class.
41              
42             To use Class-TransparentFactory in user code, no change is needed. (That
43             is the point!) To use it in your libraries, you need to follow these
44             steps:
45              
46             =over 4
47              
48             =item Move all your actual implementation into another module.
49              
50             Its name is not important to Class::TransparentFactory, but let's call
51             it C here. The old namespace by which the implementation
52             was known we will call C.
53              
54             =item Declare C as a transparent factory.
55              
56             See I below for details. For a typical OOPish module with no
57             special class methods, this will suffice:
58              
59             package Facade;
60             use Class::TransparentFactory qw(new);
61              
62             =item Implement your factory.
63              
64             See I for details. Here is where you put the business logic
65             that determines which provider is suitable and should be used for this
66             particular call.
67              
68             =back
69              
70             =head1 FUNCTIONS
71              
72             =head2 import
73              
74             The import directive is your declarative way of specifying which class
75             methods belong to the transparently facaded API. Supply a simple list of
76             names. Instance methods need not be specified here, since subsequent
77             method dispatches on objects created by provider classes will presumably
78             go to the correct place directly.
79              
80             =cut
81              
82             sub import {
83 5     5   4651 my($c, @funcs) = @_;
84 5         10 my $caller = caller;
85 5         29 for my $name (@funcs) {
86             my $code = sub {
87 5     5   2973 my($class, @args) = @_;
88              
89             # the following is necessary since otherwise peeking at
90             # (caller(1))[3] in impl won't work.
91             # See http://perlmonks.org/?node_id=304883 .
92 5         20 local *__ANON__ = $name;
93              
94 5         21 return $class->impl(@args)->$name(@args);
95 5         22 };
96 2     2   12 no strict;
  2         8  
  2         195  
97 5         8 *{"$caller\::$name"} = $code;
  5         4313  
98             }
99             }
100              
101             =head2 impl
102              
103             This is not a method of Class::TransparentFactory, but rather one that
104             you must implement in your facade class yourself.
105              
106             It is here that you do the actual factorty work. You have the actual
107             class method call arguments for your inspection if you need them. C
108             must do the following:
109              
110             =over 4
111              
112             =item Determine the appropriate provider for this call
113              
114             You may base this decision on the method arguments, the call stack,
115             phase of the moon, or whatever you wish. Only you know why you needed
116             a variety of providers, so you should know how to pick among them.
117              
118             =item Make sure it is loaded
119              
120             You can use a C or any other means. (In a static setup, it is
121             perfectly reasonable to say C etc. at
122             the top of the facade class and not worry about this step in C.)
123              
124             =item Return it
125              
126             Simply arrange for C to return a string with the class
127             name. Class::TransparentFactory will handle the dispatching.
128              
129             =back
130              
131             =head1 EXPERIMENTATIONAL STATUS
132              
133             This module is highly experimental! I am looking for improvements, from
134             ideas for a better name via clever features. Please contact me at the
135             address below if you have a suggestion.
136              
137             =head1 AUTHOR
138              
139             Gaal Yahas, C<< >>
140              
141             =head1 BUGS
142              
143             Please report any bugs or feature requests to
144             C, or through the web interface at
145             L.
146             I will be notified, and then you'll automatically be notified of progress on
147             your bug as I make changes.
148              
149             =head1 SUPPORT
150              
151             You can find documentation for this module with the perldoc command.
152              
153             perldoc Class::TransparentFactory
154              
155             You can also look for information at:
156              
157             =over 4
158              
159             =item * AnnoCPAN: Annotated CPAN documentation
160              
161             L
162              
163             =item * CPAN Ratings
164              
165             L
166              
167             =item * RT: CPAN's request tracker
168              
169             L
170              
171             =item * Search CPAN
172              
173             L
174              
175             =back
176              
177             =head1 ACKNOWLEDGEMENTS
178              
179             Thanks to Zsban Ambrus for pointing me at the *__ANON__ hack for naming
180             closures, and to Yitzchak Scott-Thoennes for posting about it here:
181             L.
182              
183             Thanks also to Yuval Kogman, C<< >> for some
184             discussion. I stole none of his good ideas yet, so all suckage here is
185             my fault.
186              
187             =head1 COPYRIGHT (The "MIT" License)
188              
189             Copyright 2006 Gaal Yahas.
190              
191             Permission is hereby granted, free of charge, to any person obtaining a
192             copy of this software and associated documentation files (the "Software"),
193             to deal in the Software without restriction, including without limitation
194             the rights to use, copy, modify, merge, publish, distribute, sublicense,
195             and/or sell copies of the Software, and to permit persons to whom the
196             Software is furnished to do so, subject to the following conditions:
197              
198             The above copyright notice and this permission notice shall be included
199             in all copies or substantial portions of the Software.
200              
201             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
202             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
203             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
204             THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
205             OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
206             ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
207             OTHER DEALINGS IN THE SOFTWARE.
208              
209             =cut
210              
211             1; # End of Class::TransparentFactory