File Coverage

blib/lib/Catalyst/Plugin/MapComponentDependencies/Utils.pm
Criterion Covered Total %
statement 39 79 49.3
branch 12 20 60.0
condition 4 11 36.3
subroutine 21 41 51.2
pod 10 21 47.6
total 86 172 50.0


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::MapComponentDependencies::Utils;
2              
3 4     4   1734442 use Scalar::Util 'blessed';
  4         11  
  4         426  
4 4     4   33 use Exporter 'import';
  4         7  
  4         148  
5 4     4   24 use Catalyst::Utils;
  4         9  
  4         6759  
6              
7             our @EXPORT_OK = (qw/FromModel FromView FromController
8             FromComponent FromCode ConfigLoaderSubstitutions
9             FromContext FromRequest FromResponse FromLog
10             FromApplication/);
11              
12             our %EXPORT_TAGS = (All => \@EXPORT_OK, ALL => \@EXPORT_OK);
13              
14 14     14 0 67 sub model_ns { __PACKAGE__ .'::MODEL' }
15 12     12 0 35 sub view_ns { __PACKAGE__ .'::VIEW' }
16 12     12 0 31 sub controller_ns { __PACKAGE__ .'::CONTROLLER' }
17 12     12 0 38 sub component_ns { __PACKAGE__ .'::COMPONENT' }
18 15     15 0 72 sub code_ns { __PACKAGE__ .'::CODE' }
19              
20             sub _is {
21 61     61   71 my ($possible, $target_ns) = @_;
22 61 100 100     752 return (defined($possible) and
23             blessed($possible) and
24             $possible->isa($target_ns)) ?
25             $$possible : 0;
26             }
27              
28 13     13 0 40 sub is_model($) { return _is(shift, model_ns) }
29 12     12 0 34 sub is_view($) { return _is(shift, view_ns) }
30 12     12 0 33 sub is_controller($) { return _is(shift, controller_ns) }
31 12     12 0 35 sub is_component($) { return _is(shift, component_ns) }
32 12     12 0 30 sub is_code($) { return _is(shift, code_ns) }
33              
34 1     1 1 31883 sub FromModel($) { my $v = shift; return bless \$v, model_ns }
  1         7  
35 0     0 1 0 sub FromView($) { my $v = shift; return bless \$v, view_ns }
  0         0  
36 0     0 1 0 sub FromController($) { my $v = shift; return bless \$v, controller_ns }
  0         0  
37 0     0 0 0 sub FromComponent($) { my $v = shift; return bless \$v, component_ns }
  0         0  
38 3     3 1 6 sub FromCode(&) { my $v = shift; return bless \$v, code_ns }
  3         8  
39              
40             sub FromContext {
41             return FromCode {
42 2     2   4 my ($c, $name, $config) = @_;
43 2 100       20 return blessed $c ? $c : undef;
44 1     1 1 8 };
45             }
46              
47             sub FromRequest {
48             return FromCode {
49 0     0   0 my ($c, $name, $config) = @_;
50 0 0       0 return blessed $c ? $c->request : undef;
51 0     0 1 0 };
52             }
53              
54             sub FromResponse {
55             return FromCode {
56 0     0   0 my ($c, $name, $config) = @_;
57 0 0       0 return blessed $c ? $c->request : undef;
58 0     0 1 0 };
59             }
60              
61             sub FromLog {
62             return FromCode {
63 0     0   0 my ($c_or_app, $name, $config) = @_;
64 0         0 return $c->log; # log is application and context
65 0     0 1 0 };
66             }
67              
68             sub FromApplication {
69             return FromCode {
70 1     1   2 my ($c_or_app, $name, $config) = @_;
71 1 50       7 return blessed $c_or_app ? ref($c_or_app): $c_or_app;
72 1     1 1 9 };
73             }
74              
75             sub _expand_config {
76 14     14   28 my ($app_or_ctx, $component_name, $config) = @_;
77              
78 14         30 my $mapped_config = +{}; # shallow clone... might need something better than all this later
79 14         63 foreach my $key (keys %$config) {
80 13         31 my $value = $config->{$key};
81 13 100       44 if(my $m = is_model $value) {
    50          
    50          
    50          
    100          
82 1   50     14 $mapped_config->{$key} = $app_or_ctx->model($m) || die "$m is not a Model";
83             } elsif(my $v = is_view $value) {
84 0   0     0 $mapped_config->{$key} = $app_or_ctx->view($v) || die "$v is not a View";
85             } elsif(my $c = is_controller $value) {
86 0   0     0 $mapped_config->{$key} = $app_or_ctx->controller($c) || die "$c is not a Controller";
87             } elsif(my $c = is_component $value) {
88 0   0     0 $mapped_config->{$key} = $app_or_ctx->component($c) || die "$c is not a Component";
89             } elsif(my $cb = is_code $value) {
90 4         15 $mapped_config->{$key} = $cb->($app_or_ctx, $component_name, $config);
91             }
92             }
93              
94 14         118 return my $merged = Catalyst::Utils::merge_hashes($config, $mapped_config);
95             }
96              
97              
98            
99            
100              
101             sub ConfigLoaderSubstitutions {
102             return (
103 0     0     FromContext => sub { my $c = shift; FromContext },
  0            
104 0     0     FromRequest => sub { my $c = shift; FromRequest },
  0            
105 0     0     FromResponse => sub { my $c = shift; FromResponse },
  0            
106 0     0     FromLog => sub { my $c = shift; FromLog },
  0            
107 0     0     FromApplication => sub { my $c = shift; FromApplication },
  0            
108 0     0     FromModel => sub { my $c = shift; FromModel(@_) },
  0            
109 0     0     FromView => sub { my $c = shift; FromView(@_) },
  0            
110 0     0     FromController => sub { my $c = shift; FromController(@_) },
  0            
111 0     0     FromComponent => sub { my $c = shift; FromComponent(@_) },
  0            
112             FromCode => sub {
113 0     0     my $c = shift;
114 0           FromCode { eval shift };
  0            
115             },
116 0     0 1   );
117             }
118              
119             1;
120              
121             =head1 NAME
122              
123             Catalyst::Plugin::MapComponentDependencies::Utils - Utilities to integrate dependencies
124              
125             =head1 SYNOPSIS
126              
127             package MyApp;
128              
129             use Moose;
130             use Catalyst 'MapComponentDependencies;
131             use Catalyst::Plugin::MapComponentDependencies::Utils ':All';
132              
133             MyApp->config(
134             'Model::Bar' => { key => 'value' },
135             'Model::Foo' => {
136             bar => FromModel 'Bar',
137             baz => FromCode {
138             my ($app_or_ctx, $component_name) = @_;
139             return ...;
140             },
141             another_param => 'value',
142             },
143             );
144              
145             MyApp->setup;
146              
147             =head1 DESCRIPTION
148              
149             Utility functions to streamline integration of dynamic dependencies into your
150             global L<Catalyst> configuration.
151              
152             L<Catalyst::Plugin::MapComponentDependencies> offers a simple way to specify
153             configuration values for you components to be the value of other components
154             and to do so in a way that respects if your component does ACCEPT_CONTEXT.
155             We do this by providing a new namespace key in your configuration. However
156             you may prefer a 'flatter' configuration. These utility methods allow you to
157             'tag' a value in your configuration. This leads to a more simple configuration
158             setup, but it has the downside in that you must either use a Perl configuration
159             (as in the SYNOPSIS example) or if you are using L<Catalyst::Plugin::ConfigLoader>
160             you can install additional configuration substitutions like so:
161              
162             use Catalyst::Plugin::MapComponentDependencies::Utils ':All';
163              
164             __PACKAGE__->config->{ 'Plugin::ConfigLoader' }
165             ->{ substitutions } = { ConfigLoaderSubstitutions };
166              
167             See L<Catalyst::Plugin::MapComponentDependencies> for other options to declare
168             your component dependencies if this approach does not appeal.
169              
170             =head1 EXPORTS
171              
172             This package exports the following functions
173              
174             =head2 FromModel
175              
176             Creates a dependency to the named model.
177              
178             =head2 FromView
179              
180             Creates a dependency to the named model.
181              
182             =head2 FromController
183              
184             Creates a dependency to the named controller.
185              
186             =head2 FromCode
187              
188             An anonymouse coderef that must return the expected dependency.
189              
190             =head2 FromContext
191              
192             The current context, or undefined if the model does not ACCEPT_CONTEXT.
193              
194             B<NOTE>: Its really easy to create a circular reference when using the
195             context as a dependency. I recommend making sure the object which is
196             consuming it stores a weak reference. For example:
197              
198             package MyApp::Object;
199              
200             use Moose;
201              
202             has ctx => (is=>'ro', required=>1, weak_ref=>1);
203              
204             # rest of code...
205              
206             =head2 FromRequest
207              
208             The current L<Catalyst::Request> instance, or undefined if the model does not
209             ACCEPT_CONTEXT.
210              
211             =head2 FromResponse
212              
213             The current L<Catalyst::Response> instance, or undefined if the model does not
214             ACCEPT_CONTEXT.
215              
216             =head2 FromLog
217              
218             The current Log object.
219              
220             =head2 FromApplication
221              
222             You application class.
223              
224             =head2 ConfigLoaderSubstitutions
225              
226             Returns a Hash suitable for use as additional substitutions in
227             L<Catalyst::Plugin::ConfigLoader>.
228              
229             =head1 SEE ALSO
230              
231             L<Catalyst>, L<Catalyst::Plugin::MapComponentDependencies>,
232             L<Catalyst::Plugin::ConfigLoader>.
233              
234             =head1 AUTHOR
235            
236             John Napiorkowski L<email:jjnapiork@cpan.org>
237            
238             =head1 COPYRIGHT & LICENSE
239            
240             Copyright 2015, John Napiorkowski L<email:jjnapiork@cpan.org>
241            
242             This library is free software; you can redistribute it and/or modify it under
243             the same terms as Perl itself.
244              
245             =cut