File Coverage

blib/lib/Bolts/Bag.pm
Criterion Covered Total %
statement 48 51 94.1
branch 15 18 83.3
condition 1 2 50.0
subroutine 8 8 100.0
pod 1 1 100.0
total 73 80 91.2


line stmt bran cond sub pod time code
1             package Bolts::Bag;
2             $Bolts::Bag::VERSION = '0.143171';
3             # ABSTRACT: Helper for creating bags containing artifacts
4              
5 11     11   56 use Moose;
  11         15  
  11         67  
6              
7 11     11   52200 use Carp;
  11         21  
  11         728  
8 11     11   59 use Moose::Util::MetaRole;
  11         14  
  11         217  
9 11     11   46 use Moose::Util::TypeConstraints;
  11         17  
  11         80  
10 11     11   16374 use Safe::Isa;
  11         19  
  11         1300  
11 11     11   60 use Scalar::Util qw( blessed reftype );
  11         15  
  11         4301  
12              
13              
14             sub start_bag {
15 55     55 1 576 my ($class, %params) = @_;
16              
17 55         88 my $package = $params{package};
18 55         84 my $meta_locator = $params{meta_locator};
19 55         79 my $such_that_each = $params{such_that_each};
20              
21 55         57 my $meta;
22 55         162 my %options = (superclasses => [ 'Moose::Object' ]);
23 55 50       141 if (defined $package) {
24 55         179 $meta = Moose::Util::find_meta($package);
25 55 100       481 if (defined $meta) {
26 23         83 return $meta;
27             }
28              
29 32         199 $meta = Moose::Meta::Class->create($package, %options);
30             }
31             else {
32 0         0 $meta = Moose::Meta::Class->create_anon_class(%options);
33             }
34              
35 32         61606 Moose::Util::MetaRole::apply_base_class_roles(
36             for => $meta,
37             roles => [ 'Bolts::Role::SelfLocator' ],
38             );
39              
40 32         34788 $meta = Moose::Util::MetaRole::apply_metaroles(
41             for => $meta,
42             class_metaroles => {
43             class => [
44             'Bolts::Meta::Class::Trait::Locator',
45             'Bolts::Meta::Class::Trait::Bag',
46             ],
47             },
48             );
49              
50 32 100       45952 if ($such_that_each) {
51 29         1381 my $such_that = $class->_expand_such_that($such_that_each);
52 29 100       98 if (defined $such_that->{does}) {
53 28         901 $meta->such_that_does($such_that->{does});
54             }
55 29 100       111 if (defined $such_that->{isa}) {
56 1         64 $meta->such_that_isa($such_that->{isa});
57             }
58             }
59              
60 32 50       212 if ($meta_locator) {
61 0         0 $meta->locator($meta_locator);
62             }
63              
64 32 50       165 Carp::cluck("bad meta @{[$meta->name]}") unless $meta->can('locator');
  0         0  
65              
66 32         148 return $meta;
67             }
68              
69             sub _expand_such_that {
70 29     29   51 my ($class, $such_that) = @_;
71              
72 29   50     68 $such_that //= {};
73 29         39 my %expanded_such_that;
74              
75 29 100       96 if (defined $such_that->{isa}) {
76 1         6 $expanded_such_that{isa} = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($such_that->{isa});
77             }
78              
79 29 100       179 if (defined $such_that->{does}) {
80 28         121 $expanded_such_that{does} = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($such_that->{does});
81             }
82              
83 29         3996 return \%expanded_such_that;
84             }
85              
86              
87             __PACKAGE__->meta->make_immutable;
88              
89             __END__
90              
91             =pod
92              
93             =encoding UTF-8
94              
95             =head1 NAME
96              
97             Bolts::Bag - Helper for creating bags containing artifacts
98              
99             =head1 VERSION
100              
101             version 0.143171
102              
103             =head1 SYNOPSIS
104              
105             use Bolts;
106              
107             my $meta = Bolts::Bag->start_bag(
108             package => 'MyApp::Holder',
109             );
110              
111             # In case the definition already ran...
112             unless ($meta->is_finished_bag) {
113             $meta->add_artifact(logger => Bolts::Artifact->new(
114             name => 'logger',
115             blueprint => $meta->locator->acquire('blueprint', 'factory', {
116             class => 'MyApp::Logger',
117             },
118             infer => 'acquisition',
119             scope => $meta->locator->acquire('scope', 'singleton'),
120             ));
121              
122             $meta->add_artifact(log_file => "var/messages.log");
123              
124             $meta->add_artifact(config => sub {
125             return YAML::LoadFile("etc/config.yml");
126             });
127              
128             $meta->finish_bag;
129             }
130              
131             my $bag = $meta->name->new;
132              
133             =head1 DESCRIPTION
134              
135             This is a helper for creating bag objects. Technically, any object may be treated as a bag. However, this is the way Bolts creates bags through the sugar API in L<Bolts> and some other internals. The primary benefit to creating this way is access to the bag meta locator during construction so you can use the standard blueprints, injectors, scopes, etc. in the standard way.
136              
137             =head1 METHODS
138              
139             =head2 start_bag
140              
141             my $meta = Bolts::Bag->start_bag(
142             package => 'MyApp::Bag',
143             meta_locator => Bolts::Meta::Locator->new,
144             such_that_each => {
145             does => 'MyApp::Role',
146             isa => 'MyApp::Thing',
147             },
148             );
149              
150             This returns a L<Class::MOP::Class> object representing the bag you want to define. The returned meta class will be created new if it does not yet exist. If it does already exist (as determined by L<Moose::Util/find_meta>, the existing class will be returned.
151              
152             It is good practice to always check to see if the definition of the bag has already been finished before continuing, which allows the definition code to be run more than once:
153              
154             if ($meta->is_finished_bag) {
155             # some ->add_artifact calls here...
156            
157             $meta->finish_bag;
158             }
159              
160             You can then use the meta class to get an instance like so:
161              
162             my $bag = $meta->name->new(%params);
163              
164             After getting the meta class returned from this class method, the remainder of the methods you need are found in L<Bolts::Meta::Class::Trait::Bag> and L<Bolts::Meta::Class::Trait::Locator>, which the returned object implement.
165              
166             This class method takes the following parameters:
167              
168             =over
169              
170             =item C<package>
171              
172             This is the package name to give the class within the Perl interpreter. If not given, the name will be anonymously chosen by L<Moose>. It will also never return a finished class.
173              
174             =item C<meta_locator>
175              
176             You may pass this in to customize the meta locator object to use with your class. This is L<Bolts::Meta::Locator> by default.
177              
178             =item C<such_that_each>
179              
180             This is used to limit the types of artifacts allowed within the bag. This is a hash that may contain one or both of these keys:
181              
182             =over
183              
184             =item C<does>
185              
186             This names a L<Moose::Role> that all artifacts returned from this bag must implement.
187              
188             =item C<isa>
189              
190             This names a Moose type constraint that all artifacts returned from this bag must match.
191              
192             =back
193              
194             =back
195              
196             =head1 AUTHOR
197              
198             Andrew Sterling Hanenkamp <hanenkamp@cpan.org>
199              
200             =head1 COPYRIGHT AND LICENSE
201              
202             This software is copyright (c) 2014 by Qubling Software LLC.
203              
204             This is free software; you can redistribute it and/or modify it under
205             the same terms as the Perl 5 programming language system itself.
206              
207             =cut