File Coverage

lib/MooseX/DIC/Container/DefaultImpl.pm
Criterion Covered Total %
statement 73 82 89.0
branch 16 22 72.7
condition 1 3 33.3
subroutine 18 19 94.7
pod 0 5 0.0
total 108 131 82.4


line stmt bran cond sub pod time code
1             package MooseX::DIC::Container::DefaultImpl;
2              
3 5     5   3497 use MooseX::DIC::Types;
  5         21  
  5         284  
4 5     5   43 use aliased 'MooseX::DIC::UnregisteredServiceException';
  5         12  
  5         45  
5 5     5   598 use aliased 'MooseX::DIC::ServiceRegistry';
  5         12  
  5         34  
6 5     5   599 use aliased 'MooseX::DIC::PackageNotFoundException';
  5         12  
  5         31  
7 5     5   579 use aliased 'MooseX::DIC::ContainerException';
  5         12  
  5         29  
8 5     5   3037 use MooseX::DIC::ServiceFactoryFactory 'build_factory';
  5         14  
  5         284  
9 5     5   30 use Module::Load;
  5         11  
  5         18  
10 5     5   208 use Try::Tiny;
  5         12  
  5         203  
11              
12 5     5   30 use Moose;
  5         11  
  5         35  
13             with 'MooseX::DIC::Container';
14             with 'MooseX::DIC::Loggable';
15              
16             has environment => ( is => 'ro', isa => 'Str', default => 'default' );
17             has registry => (is => 'ro', isa => 'MooseX::DIC::ServiceRegistry', required => 1);
18             has singletons => (is => 'ro', isa => 'HashRef[HashRef[Any]]', default => sub { { default => {} } });
19             has service_factories => ( is => 'ro', isa => 'HashRef[ServiceFactory]', default => sub { {} } );
20              
21             sub has_service {
22 6     6 0 20 my ( $self, $interface_name ) = @_;
23              
24 6         174 return $self->registry->has_service($interface_name);
25             }
26              
27             sub build_class {
28 4     4 0 5850 my ($self,$package_name) = @_;
29              
30 4         127 $self->logger->debug("I'm going to build an instance of $package_name");
31            
32 4         34 my $dependencies = $self->get_package_dependencies($package_name);
33              
34             my $instance =
35 2     2   81 try { $package_name->new(%$dependencies) }
36             catch {
37 0     0   0 my $error = "Could not create an instance for package $package_name via "
38             ."Moose constructor: $_";
39 0         0 $self->logger->error($error);
40 0         0 ContainerException->throw(message => $error);
41 2         16 };
42            
43 2         2369 return $instance;
44             }
45              
46             sub get_service {
47 34     34 0 25851 my ( $self, $package_name,$original_environment ) = @_;
48 34   33     1290 my $environment = $original_environment || $self->environment;
49              
50             # Check it is a registered service
51 34         990 my $meta = $self->registry->get_service_definition($package_name,$environment);
52 34 100       108 UnregisteredServiceException->throw( service => $package_name )
53             unless $meta;
54              
55 33         55 my $service;
56              
57             # If it is a singleton, there's a chance it has already been built
58 33 100       1039 if ( $meta->scope eq 'singleton' ) {
59              
60             # First retrieve it from the environment, then from default environment
61 26         917 $service = $self->singletons->{ $meta->environment }->{$package_name};
62 26 100       579 $service = $self->singletons->{'default'}->{$package_name}
63             unless $service;
64             }
65 33 100       205 return $service if $service;
66              
67             # If the service hasn't been built yet, use the builder class to do it
68 23         762 my $service_factory = $self->_get_service_factory( $meta->builder );
69 23         107 $service = $service_factory->build_service($meta);
70              
71             # Cache the service if it's a singleton
72 22 100       811 if ( $meta->scope eq 'singleton' ) {
73 15         461 $self->singletons->{ $meta->environment }->{$package_name} = $service;
74             }
75              
76 22         100 return $service;
77             }
78              
79             sub get_service_metadata {
80 3     3 0 8 my ($self,$interface_name,$environment) = @_;
81              
82 3         76 return $self->registry->get_service_definition($interface_name,$environment);
83             }
84              
85             sub get_package_dependencies {
86 4     4 0 10 my ($self,$package_name) = @_;
87              
88 4         97 $self->logger->debug("Fetching dependencies for $package_name");
89              
90             try {
91 4     4   153 load $package_name;
92             } catch {
93 1     1   412 $self->logger->debug("The package $package_name could not be loaded $_");
94 1         25 PackageNotFoundException->throw(package_name=>$package_name);
95 4         43 };
96              
97 3 100       11993 ContainerException->throw(message => "The package $package_name is not a valid Moose class,"
98             ." it's dependencies cannot be injected") unless $package_name->can('meta');
99              
100 2         5 my %dependencies = ();
101              
102 2         8 foreach my $attribute ($package_name->meta->get_all_attributes){
103             # We can only inject an attribute that defines a constraint
104 4 50       216 if($attribute->type_constraint){
105 4         140 my $service_type = $attribute->type_constraint->name;
106 4         126 my $service = $self->get_service($service_type);
107              
108 4 50       14 unless($service) {
109 0         0 $self->logger->error("Could not find service $service_type for mandatory attribute "
110             .$attribute->name
111             ." while building class $package_name");
112 0 0       0 UnregisteredServiceException->throw(service=>$service_type) if($attribute->is_required);
113             }
114 4         17 $dependencies{$attribute->name} = $service;
115             } else {
116 0 0       0 if($attribute->is_required) {
117 0         0 my $error = "Could not inject the required attribute "
118             .$attribute->name
119             ." of the class $package_name because it has no type constraint";
120 0         0 $self->logger->error($error);
121              
122 0         0 ContainerException->throw(message => $error);
123             }
124             }
125             }
126              
127 2         52 $self->logger->debug("Dependencies for $package_name fetched");
128              
129 2         16 return \%dependencies;
130             }
131              
132             sub _get_service_factory {
133 23     23   55 my ( $self, $factory_type ) = @_;
134              
135 23         719 my $service_factory = $self->service_factories->{$factory_type};
136 23 100       62 unless ($service_factory) {
137 9         66 $service_factory = build_factory( $factory_type, $self );
138 9         310 $self->service_factories->{$factory_type} = $service_factory;
139             }
140              
141 23         57 return $service_factory;
142             }
143              
144             1;