File Coverage

blib/lib/Bolts/Injector.pm
Criterion Covered Total %
statement 28 28 100.0
branch 12 14 85.7
condition 0 3 0.0
subroutine 5 5 100.0
pod 4 4 100.0
total 49 54 90.7


line stmt bran cond sub pod time code
1             package Bolts::Injector;
2             $Bolts::Injector::VERSION = '0.143171';
3             # ABSTRACT: inject options and parameters into artifacts
4              
5 11     11   4760 use Moose::Role;
  11         19  
  11         79  
6              
7             our @CARP_NOT = qw(
8             Bolts::Injector::Parameter::ByName
9             Bolts::Artifact
10             );
11              
12              
13             has init_locator => (
14             is => 'ro',
15             isa => 'Bolts::Role::Locator',
16             weak_ref => 1,
17             );
18              
19             #with 'Bolts::Role::Initializer';
20              
21              
22             has key => (
23             is => 'ro',
24             isa => 'Str',
25             required => 1,
26             );
27              
28              
29             has blueprint => (
30             is => 'ro',
31             does => 'Bolts::Blueprint::Role::Injector',
32             required => 1,
33             traits => [ 'Bolts::Initializer' ],
34             );
35              
36              
37             has does => (
38             accessor => 'does_type',
39             isa => 'Moose::Meta::TypeConstraint',
40             );
41              
42              
43             has isa => (
44             accessor => 'isa_type',
45             isa => 'Moose::Meta::TypeConstraint',
46             );
47              
48              
49             # not actually required, we use duck-typing to determine what kind of injection
50             # to perform.
51             #requires 'pre_inject_value';
52             #requires 'post_inject_value';
53              
54              
55             sub pre_inject {
56 1051     1051 1 1058 my ($self, $loc, $options, $param) = @_;
57              
58 1051 100       2939 return unless $self->can('pre_inject_value');
59 997 100       1450 return unless $self->exists($loc, $options);
60              
61 529         1073 my $value = $self->get($loc, $options);
62 528         1282 $self->pre_inject_value($loc, $value, $param);
63             }
64              
65              
66             sub post_inject {
67 1049     1049 1 949 my ($self, $loc, $options, $artifact) = @_;
68              
69 1049 100       2937 return unless $self->can('post_inject_value');
70 54 50       118 return unless $self->exists($loc, $options);
71              
72 54         103 my $value = $self->get($loc, $options);
73 54         155 $self->post_inject_value($loc, $value, $artifact);
74             }
75              
76              
77             sub exists {
78 1051     1051 1 931 my ($self, $loc, $options) = @_;
79              
80 1051         25480 my $blueprint = $self->blueprint;
81 1051         24131 my $key = $self->key;
82              
83 1051         3088 return $blueprint->exists($loc, $key, %$options);
84             }
85              
86              
87             sub get {
88 583     583 1 573 my ($self, $loc, $options) = @_;
89              
90 583         13813 my $blueprint = $self->blueprint;
91 583         13005 my $key = $self->key;
92              
93 583         1602 my $value = $blueprint->get($loc, $key, %$options);
94              
95 583         15540 my $isa = $self->isa_type;
96 583         15506 my $does = $self->does_type;
97              
98 583         468 my $msg;
99 583 100       1090 $msg = $isa->validate($value) if defined $isa;
100 583 50 0     27556 $msg //= $does->validate($value) if defined $does;
101              
102 583 100       988 Carp::croak(qq[Value for injection at key "$key" has the wrong type: $msg]) if $msg;
103              
104 582         924 return $value;
105             }
106              
107             1;
108              
109             __END__
110              
111             =pod
112              
113             =encoding UTF-8
114              
115             =head1 NAME
116              
117             Bolts::Injector - inject options and parameters into artifacts
118              
119             =head1 VERSION
120              
121             version 0.143171
122              
123             =head1 SYNOPSIS
124              
125             package MyApp::CustomInjector;
126             use Moose;
127              
128             with 'Bolts::Injector';
129              
130             sub pre_inject_value {
131             my ($self, $loc, $value, $param) = @_;
132             $param->set($self->key, $value);
133             }
134              
135             sub post_inject_value {
136             my ($self, $loc, $value, $artifact) = @_;
137             $artifact->set($self->key, $value);
138             }
139              
140             =head1 DESCRIPTION
141              
142             Defines the interface that injectors use to inject dependencies into an artifact
143             being resolved. While the locator finds the object for the caller and the
144             blueprint determines how to construct the artifact, the injector helps the
145             blueprint by passing through any parameters or settings needed to complete the
146             construction.
147              
148             This is done in two phases, with most injectors only implementing one of them:
149              
150             =over
151              
152             =item 1.
153              
154             B<Pre-injection.> Allows the injector to configure the parameters sent through
155             to blueprint's builder method, such as might be needed when constructing a new
156             object.
157              
158             =item 2.
159              
160             B<Post-injection.> This phase gives the injector access to the newly constructed
161             but partially incomplete object to perform additional actions on the object,
162             such as calling methods to set additional attributes or activate state on the
163             object.
164              
165             =back
166              
167             This role provides the tools necessary to allow the injection implementations to
168             focus only on the injection process without worrying about the value being
169             injected.
170              
171             =head1 ATTRIBUTES
172              
173             =head2 init_locator
174              
175             If provided with a reference to the meta-locator for the bag to which the injector is going to be attached, the L<blueprint> may be given as initializers.
176              
177             =head2 key
178              
179             This is the key used to desribe what the injector is injecting. This might be a parameter name, an array index, or method name (or any other descriptive string).
180              
181             =head2 blueprint
182              
183             This is the blueprint that defines how the value being injected will be constructed. So, not only is the injector part of the process of construction, but it has its own blueprint for constructing the value needed to perform the injection.
184              
185             All the injector needs to worry about is the L</get> method, which handles the process of getting and validating the value for you.
186              
187             Instead of passing the blueprint object in directly, you can provide an initializer in an array reference, similar to what you would pass to C<acquire> to get the blueprint from the meta-locator, e.g.:
188              
189             blueprint => bolts_init('blueprint', 'acquire', {
190             path => [ 'foo' ],
191             }),
192              
193             If so, you must provide an L</init_locator>.
194              
195             =head2 does
196              
197             This is a type constraint describing what value is expected for injection. This is checked within L</get>.
198              
199             =head2 isa
200              
201             This is a type constraint describing what value is expected for injection. This is checked within L</get>.
202              
203             =head1 OVERRIDDEN METHODS
204              
205             =head2 pre_inject_value
206              
207             $injector->pre_inject_value($loc, $value, $param);
208              
209             This method is called first, before the artifact has been constructed by the parent blueprint.
210              
211             The C<$loc> provides the context for the injector. It is the bag that contains the artifact being constructed. The C<$value> is the value to be injected. The C<$param> is the value to inject into, which will be passed through to the blueprint for use during construction.
212              
213             If your injector does not provide any pre-injection, do not implement this method.
214              
215             =head2 post_inject_value
216              
217             $injector->post_inject_value($loc, $value, $artifact);
218              
219             This method is called after the blueprint has already constructed the object for additional modification.
220              
221             The C<$loc> provides the context for the injector. It is the bag that contains the artifact being constructed. The C<$value> is the value to be injected. The C<$artifact> is the constructed artifact to be injected into.
222              
223             If your injector does not provide any post-injection, do not implement this method.
224              
225             =head1 METHODS
226              
227             =head2 pre_inject
228              
229             $injector->pre_inject($loc, $options, $param);
230              
231             Performs the complete process of pre-injection, calling L</pre_inject_value>, if needed.
232              
233             =head2 post_inject
234              
235             $injector->post_inject($loc, $options, $artifact);
236              
237             Performs the complete process of post-injection, calling L</post_inject_value>, if needed.
238              
239             =head2 exists
240              
241             my $exists = $injector->exists($loc, $options);
242              
243             Returns true if the blueprint reports the value for injection exists. Injection is skipped if it does not exists.
244              
245             =head2 get
246              
247             my $value = $injector->get($loc, $options);
248              
249             These are used by L</pre_inject> and L</post_inject> to acquire the value to be injected.
250              
251             =head1 AUTHOR
252              
253             Andrew Sterling Hanenkamp <hanenkamp@cpan.org>
254              
255             =head1 COPYRIGHT AND LICENSE
256              
257             This software is copyright (c) 2014 by Qubling Software LLC.
258              
259             This is free software; you can redistribute it and/or modify it under
260             the same terms as the Perl 5 programming language system itself.
261              
262             =cut