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