File Coverage

blib/lib/MooseX/ConstructInstance.pm
Criterion Covered Total %
statement 24 31 77.4
branch 3 10 30.0
condition n/a
subroutine 8 8 100.0
pod 1 1 100.0
total 36 50 72.0


line stmt bran cond sub pod time code
1             package MooseX::ConstructInstance;
2              
3 4     4   100865 use 5.008;
  4         15  
  4         155  
4 4     4   22 use strict;
  4         6  
  4         129  
5 4     4   19 use warnings;
  4         13  
  4         120  
6              
7 4     4   2950 use Moo::Role;
  4         164800  
  4         34  
8 4     4   8549 no warnings qw( void once uninitialized );
  4         8  
  4         726  
9              
10             # Allow import method to work, yet hide it from role method list.
11             our @ISA = do {
12             package # Hide from CPAN indexer too.
13             MooseX::ConstructInstance::__ANON__::0001;
14             sub import {
15 2     2   28 my $class = shift;
16 2         5 my $caller = caller;
17 2 100       19 if ($_[0] eq '-with') {
18 1         4 "Moo::Role"->apply_roles_to_package(
19             $caller,
20             $class,
21             );
22             }
23             }
24             __PACKAGE__;
25             };
26              
27             BEGIN {
28 4     4   11 $MooseX::ConstructInstance::AUTHORITY = 'cpan:TOBYINK';
29 4         754 $MooseX::ConstructInstance::VERSION = '0.006';
30             }
31              
32             # If push comes to shove, you can locally change the name
33             # of the constructor.
34             #
35             our $CONSTRUCTOR = 'new';
36              
37             sub construct_instance {
38 9     9 1 55563 my (undef, $class, @args) = @_;
39            
40 9 50       39 if ( my $ref = ref($class) )
41             {
42 0 0       0 if ($ref ne 'CODE')
43             {
44 0         0 require overload;
45 0         0 require Scalar::Util;
46 0         0 require Carp;
47            
48 0 0       0 Carp::croak("Cannot construct instance from reference $class")
49             unless Scalar::Util::blessed($class);
50            
51 0 0       0 Carp::croak("Cannot construct instance from object $class")
52             unless overload::Method($class, '&{}');
53             }
54            
55 0         0 return $class->(@args);
56             }
57            
58 9         95 $class->$CONSTRUCTOR(@args);
59             }
60              
61             1;
62              
63             __END__
64              
65             =pod
66              
67             =encoding utf8
68              
69             =for stopwords backlinks
70              
71             =head1 NAME
72              
73             MooseX::ConstructInstance - small wrapper method for instantiating helper objects
74              
75             =head1 SYNOPSIS
76              
77             This role consists of a single method:
78              
79             sub construct_instance {
80             my (undef, $class, @args) = @_;
81             $class->new(@args);
82             }
83              
84             (Actually, since 0.006, it's a little more complex.)
85              
86             =begin trustme
87              
88             =item construct_instance
89              
90             =end trustme
91              
92             =head1 DESCRIPTION
93              
94             Normally you would build an LWP::UserAgent something like this:
95              
96             sub _build_ua {
97             my $self = shift;
98             LWP::UserAgent->new(...);
99             }
100              
101             Following the principles of dependency injection, you may prefer not to
102             hard-code the class name (see also L<MooseX::RelatedClasses>):
103              
104             has ua_class => (is => 'ro', default => 'LWP::UserAgent');
105            
106             sub _build_ua {
107             my $self = shift;
108             $self->ua_class->new(...);
109             }
110              
111             This module allows you to take it to a further level of abstraction:
112              
113             has ua_class => (is => 'ro', default => 'LWP::UserAgent');
114            
115             sub _build_ua {
116             my $self = shift;
117             $self->construct_instance($self->ua_class, ...);
118             }
119              
120             Why? What benefit do we accrue from constructing all our helper objects via
121             a seemingly redundant object method call? How about this:
122              
123             {
124             package Authentication;
125             use Moose::Role;
126             around construct_instance => sub {
127             my ($orig, $self, $class, @args) = @_;
128             my $instance = $self->$orig($class, @args);
129             if ($instance->DOES('LWP::UserAgent')) {
130             $instance->credentials('', '', 'username', 'password');
131             }
132             return $instance;
133             };
134             }
135            
136             Moose::Util::ensure_all_roles($something, 'Authentication');
137              
138             Now whenever C<< $something >> constructs an LWP::UserAgent object, it will
139             automatically have authentication credentials supplied.
140              
141             MooseX::ConstructInstance can be used to apply policies such as:
142              
143             =over
144              
145             =item *
146              
147             If C<< $foo >> has a C<< dbh >> attribute, and it constructs an object
148             C<< $bar >>, then C<< $bar >> should inherit C<< $foo >>'s database
149             handle.
150              
151             =item *
152              
153             All node objects must be have "backlinks" to the parent node that created
154             them.
155              
156             =back
157              
158             Despite the name, MooseX::ConstructInstance is actually a L<Moo::Role>.
159             You can apply MooseX::ConstructInstance to Moose classes using:
160              
161             package MyClass;
162             use Moose;
163             with qw( MooseX::ConstructInstance );
164              
165             You can apply it to Moo classes using:
166              
167             package MyClass;
168             use Moo;
169             with qw( MooseX::ConstructInstance );
170              
171             You can apply it to other classes using:
172              
173             package MyClass;
174             use MooseX::ConstructInstance -with;
175              
176             As of version 0.006 of MooseX::ConstructInstance, C<< $class >> may be
177             a coderef or a blessed object overloading C<< &{} >>. The
178             C<construct_instance> method acts a bit like this:
179              
180             sub construct_instance {
181             my (undef, $class, @args) = @_;
182             if ( is_codelike($class) ) {
183             return $class->(@args);
184             }
185             else {
186             $class->new(@args);
187             }
188             }
189              
190             =head1 FAQ
191              
192             =head2 What if I need to use a constructor which is not called C<new>?
193              
194             Aye; there's the rub.
195              
196             For now, this works, though it's not an especially elegant solution...
197              
198             sub _build_document {
199             my $self = shift;
200             local $MooseX::ConstructInstance::CONSTRUCTOR = 'new_from_file';
201             $self->construct_instance($self->document_class, ...);
202             }
203              
204             =head1 BUGS
205              
206             Please report any bugs to
207             L<http://rt.cpan.org/Dist/Display.html?Queue=MooseX-ConstructInstance>.
208              
209             =head1 SEE ALSO
210              
211             L<Moose>,
212             L<MooseX::RelatedClasses>.
213              
214             =head1 AUTHOR
215              
216             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
217              
218             =head1 COPYRIGHT AND LICENCE
219              
220             This software is copyright (c) 2012-2013 by Toby Inkster.
221              
222             This is free software; you can redistribute it and/or modify it under
223             the same terms as the Perl 5 programming language system itself.
224              
225             =head1 DISCLAIMER OF WARRANTIES
226              
227             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
228             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
229             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
230