File Coverage

lib/MooseX/DIC/ServiceFactory/Moose.pm
Criterion Covered Total %
statement 44 47 93.6
branch 9 14 64.2
condition n/a
subroutine 12 13 92.3
pod 0 2 0.0
total 65 76 85.5


line stmt bran cond sub pod time code
1             package MooseX::DIC::ServiceFactory::Moose;
2              
3 5     5   2673 use Moose;
  5         17  
  5         41  
4             with 'MooseX::DIC::ServiceFactory';
5 5     5   38971 use namespace::autoclean;
  5         15  
  5         67  
6              
7             with 'MooseX::DIC::Loggable';
8              
9 5     5   458 use aliased 'MooseX::DIC::UnregisteredServiceException';
  5         15  
  5         42  
10 5     5   1079 use aliased 'MooseX::DIC::ContainerConfigurationException';
  5         16  
  5         24  
11 5     5   915 use aliased 'MooseX::DIC::ServiceCreationException';
  5         14  
  5         22  
12 5     5   771 use Try::Tiny;
  5         21  
  5         3233  
13              
14             has container => ( is => 'ro', does => 'MooseX::DIC::Container', required => 1 );
15              
16             sub build_service {
17 22     22 0 71 my ( $self, $service_meta ) = @_;
18              
19 22         89 my %dependencies = $self->build_dependencies_for($service_meta);
20              
21 21         52 my $service;
22             try {
23 21     21   2171 $service = $service_meta->class_name->new(%dependencies);
24             } catch {
25 0     0   0 MooseX::DIC::ServiceCreationException->throw(
26             message => "Error while building an injected service: $_" );
27 21         206 };
28              
29 21         10402 return $service;
30             }
31              
32             sub build_dependencies_for {
33 22     22 0 62 my ($self,$service_meta) = @_;
34              
35 22         1043 my $class_meta = $service_meta->class_name->meta;
36              
37             # Build the to-be-injected dependencies of
38             # the object
39 22         620 my %dependencies = ();
40              
41 22         58 while(my ($name,$dependency) = each(%{$service_meta->dependencies})) {
  27         1338  
42 6         321 my $attribute = $class_meta->get_attribute($dependency->name);
43 6         350 my $service_type = $attribute->type_constraint->name;
44              
45 6 50       593 if($self->container->has_service($service_type)) {
46              
47 6 100       317 if( $dependency->scope eq 'object' ) {
    50          
48 3         113 $dependencies{ $dependency->name } = $self->container->get_service($service_type);
49             } elsif( $dependency->scope eq 'request') {
50             # It is a configuration error to ask for a request-injection of
51             # a singleton object. It may indicate a misconception or a config
52             # typo.
53 3         143 my $attribute_service_meta = $self->container->get_service_metadata($service_type);
54 3 100       155 ContainerConfigurationException->throw( message =>
55             "A singleton-scoped service cannot be injected into a request-injected attribute"
56             ) if $attribute_service_meta->scope eq 'singleton';
57              
58             # Replace the getter with a custom proxy function
59 2         22 $attribute->remove_accessors;
60             $class_meta->add_method(
61             $dependency->name,
62             sub {
63 4     4   29 my ( $object, $value ) = @_;
        4      
        4      
64              
65             # This is only a setter. Trying to write is an error
66 4 50       25 ContainerException->throw( message =>
67             "A request-injected service accessor is read-only, it cannot be used as a setter"
68             ) if $value;
69              
70 4         198 return $self->container->get_service($service_type);
71             }
72 2         651 );
73              
74             # We must pass a valid attribute value in case the attribute is required. It will never
75             # get used, though.
76 2 100       273 if( $attribute->is_required) {
77 1         61 $dependencies{ $dependency->name } = $self->container->get_service($service_type);
78             }
79             } else {
80 0         0 ContainerConfigurationException->throw( message => "Injection scope of dependencies can only
81             be of type 'request' or 'object'" );
82             }
83             } else {
84 0 0       0 UnregisteredServiceException->throw(service => $service_type )
85             if ( $attribute->is_required );
86             }
87             }
88              
89 21         94 return %dependencies;
90              
91             }
92              
93             __PACKAGE__->meta->make_immutable;
94              
95             1;