File Coverage

blib/lib/DCI/Meta/Context.pm
Criterion Covered Total %
statement 79 83 95.1
branch 15 20 75.0
condition 11 17 64.7
subroutine 26 27 96.3
pod 9 11 81.8
total 140 158 88.6


line stmt bran cond sub pod time code
1             package DCI::Meta::Context;
2 15     15   588423 use strict;
  15         27  
  15         505  
3 15     15   73 use warnings;
  15         30  
  15         416  
4              
5 15     15   77 use base 'DCI::Meta';
  15         29  
  15         6853  
6              
7 15     15   81 use Carp qw/croak confess/;
  15         26  
  15         920  
8 15     15   86 use Scalar::Util qw/blessed/;
  15         27  
  15         740  
9 15     15   73 use Exporter::Declare qw/export_to default_export import/;
  15         25  
  15         109  
10             require DCI::Context;
11              
12 14     14   106 default_export cast => sub { caller->dci_meta->cast( @_ ) };
13 12     12   90 default_export casting => sub { caller->dci_meta->casting( @_ )};
14 32     32   485 default_export sugar => sub { caller->dci_meta->sugar( @_ ) };
15              
16 3     3   39 default_export maybe_cast => sub { caller->dci_meta->maybe_cast( @_ ) };
17 3     3   24 default_export maybe_casting => sub { caller->dci_meta->maybe_casting( @_ )};
18              
19 23     23 0 255 sub base { 'DCI::Context' };
20              
21             sub init {
22 23     23 0 44 my $self = shift;
23 23         268 %$self = (
24             %$self,
25             roles => {},
26             maybe => {},
27             sugar => {},
28             );
29             }
30              
31 32     32 1 85 sub roles { keys %{ shift->{roles}}};
  32         327  
32 32     32 1 115 sub maybe_roles { keys %{ shift->{maybe}}};
  32         212  
33              
34             sub get_role_cast {
35 0     0 1 0 my $self = shift;
36 0         0 my ( $role ) = @_;
37 0   0     0 return $self->{roles}->{ $role }
38             || $self->{maybe}->{ $role };
39             }
40              
41             sub _add_role_method {
42 58     58   73 my $self = shift;
43 58         102 my ( $name, $cast ) = @_;
44 58         186 my $target = $self->target;
45              
46             $self->inject( $target, $name => sub {
47 212     212   9350 my $context = shift;
48 212 50       2879 croak "Cannot call '$name' on unblessed '$context'"
49             unless blessed( $context );
50              
51 212 100       1025 if ( @_ ) {
52 76         156 my ($val, @extra) = @_;
53 76 50       227 croak "Extra arguments provided to '$name'"
54             if @extra;
55              
56 76         316 $context->{$name} = $self->_normalize_core(
57             $context, $cast, $val
58             );
59             }
60              
61 212         2321 return $context->{$name};
62 58         517 });
63             }
64              
65             sub _normalize_core {
66 76     76   114 my $self = shift;
67 76         153 my ( $context, $cast, $val ) = @_;
68              
69             # No restrictions on core
70 76 100       282 return $val unless defined $cast;
71              
72             # Val meets restrictions
73 50 100 100     1115 return $val if blessed $val && $val->isa( $cast );
74              
75             # Val can be wrapped used in cast
76             return $cast->dci_new( $val, $context )
77 42 50       80 if eval { $cast->isa( 'DCI::Cast' )};
  42         1106  
78              
79 0         0 croak "'$val' is not a '$cast', and '$cast' is not a Cast type";
80             }
81              
82             sub cast {
83 14     14 1 25 my $self = shift;
84 14         50 $self->_cast( $self->{roles}, @_ );
85             }
86              
87             sub maybe_cast {
88 3     3 1 12 my $self = shift;
89 3         9 $self->_cast( $self->{maybe}, @_ );
90             }
91              
92             sub _cast {
93 32     32   47 my $self = shift;
94 32         108 my ( $store, %roles ) = @_;
95 32         99 for my $role ( keys %roles ) {
96 58 50       168 croak "role $role already defined for '" . $self->target . "'"
97             if $store->{$role};
98              
99 58         111 my $cast = $roles{$role};
100              
101 58 100 66     368 if ( $cast && !blessed( $cast ) && ref $cast eq 'HASH' ) {
      100        
102 6         39 $cast = DCI::Meta::Cast->anonymous( %$cast );
103             }
104              
105 58         129 $store->{$role} = $cast;
106 58         153 $self->_add_role_method( $role, $cast );
107             }
108             }
109              
110             sub casting {
111 12     12 1 30 my $self = shift;
112 12         56 $self->_cast( $self->{roles}, map {( $_ => undef )} @_ );
  21         111  
113             }
114              
115             sub maybe_casting {
116 3     3 1 9 my $self = shift;
117 3         9 $self->_cast( $self->{maybe}, map {( $_ => undef )} @_ );
  6         42  
118             }
119              
120             sub sugar {
121 32     32 1 53 my $self = shift;
122              
123 32 50       96 croak "sugar() called without args" unless @_;
124              
125 32         98 my ( $name, @args ) = @_;
126 32 100       146 my %params = @args > 1 ? @args : ( method => @args );
127              
128 32   33     88 my $method = $params{method} || croak "No method specified for sugar";
129 32   100     139 my $ordered = $params{ordered} || [];
130 32         165 my $target = $self->target;
131              
132             $self->{sugar}->{$name} = sub {
133 63         1406 $target->new(
134 31     31   120559 (map {( $_ => shift( @_ ) )} @$ordered),
135             @_,
136             )->$method;
137             }
138 32         288 }
139              
140             sub dci_exports {
141 20     20 1 173 my $self = shift;
142 20         33 return %{ $self->{sugar} }
  20         127  
143             }
144              
145             1;
146              
147             __END__