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.142930';
3             # ABSTRACT: Helper for creating bags containing artifacts
4              
5 8     8   35 use Moose;
  8         12  
  8         49  
6              
7 8     8   38458 use Carp;
  8         18  
  8         513  
8 8     8   38 use Moose::Util::MetaRole;
  8         11  
  8         157  
9 8     8   33 use Moose::Util::TypeConstraints;
  8         9  
  8         54  
10 8     8   11939 use Safe::Isa;
  8         14  
  8         994  
11 8     8   42 use Scalar::Util qw( blessed reftype );
  8         10  
  8         2815  
12              
13              
14             sub start_bag {
15 49     49 1 882 my ($class, %params) = @_;
16              
17 49         95 my $package = $params{package};
18 49         107 my $meta_locator = $params{meta_locator};
19 49         61 my $such_that_each = $params{such_that_each};
20              
21 49         57 my $meta;
22 49         158 my %options = (superclasses => [ 'Moose::Object' ]);
23 49 50       109 if (defined $package) {
24 49         170 $meta = Moose::Util::find_meta($package);
25 49 100       499 if (defined $meta) {
26 23         84 return $meta;
27             }
28              
29 26         166 $meta = Moose::Meta::Class->create($package, %options);
30             }
31             else {
32 0         0 $meta = Moose::Meta::Class->create_anon_class(%options);
33             }
34              
35 26         52724 Moose::Util::MetaRole::apply_base_class_roles(
36             for => $meta,
37             roles => [ 'Bolts::Role::SelfLocator' ],
38             );
39              
40 26         30484 $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 26 100       40596 if ($such_that_each) {
51 23         1177 my $such_that = $class->_expand_such_that($such_that_each);
52 23 100       78 if (defined $such_that->{does}) {
53 22         740 $meta->such_that_does($such_that->{does});
54             }
55 23 100       93 if (defined $such_that->{isa}) {
56 1         33 $meta->such_that_isa($such_that->{isa});
57             }
58             }
59              
60 26 50       268 if ($meta_locator) {
61 0         0 $meta->locator($meta_locator);
62             }
63              
64 26 50       130 Carp::cluck("bad meta @{[$meta->name]}") unless $meta->can('locator');
  0         0  
65              
66 26         135 return $meta;
67             }
68              
69             sub _expand_such_that {
70 23     23   42 my ($class, $such_that) = @_;
71              
72 23   50     73 $such_that //= {};
73 23         35 my %expanded_such_that;
74              
75 23 100       77 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 23 100       207 if (defined $such_that->{does}) {
80 22         106 $expanded_such_that{does} = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($such_that->{does});
81             }
82              
83 23         3376 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.142930
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