File Coverage

blib/lib/App/CELL.pm
Criterion Covered Total %
statement 73 82 89.0
branch 13 20 65.0
condition 7 10 70.0
subroutine 22 24 91.6
pod 9 9 100.0
total 124 145 85.5


line stmt bran cond sub pod time code
1             # *************************************************************************
2             # Copyright (c) 2014-2020, SUSE LLC
3             #
4             # All rights reserved.
5             #
6             # Redistribution and use in source and binary forms, with or without
7             # modification, are permitted provided that the following conditions are met:
8             #
9             # 1. Redistributions of source code must retain the above copyright notice,
10             # this list of conditions and the following disclaimer.
11             #
12             # 2. Redistributions in binary form must reproduce the above copyright
13             # notice, this list of conditions and the following disclaimer in the
14             # documentation and/or other materials provided with the distribution.
15             #
16             # 3. Neither the name of SUSE LLC nor the names of its contributors may be
17             # used to endorse or promote products derived from this software without
18             # specific prior written permission.
19             #
20             # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21             # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23             # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24             # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25             # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26             # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27             # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28             # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29             # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30             # POSSIBILITY OF SUCH DAMAGE.
31             # *************************************************************************
32              
33             package App::CELL;
34              
35 9     9   142500 use strict;
  9         54  
  9         213  
36 9     9   38 use warnings;
  9         16  
  9         167  
37 9     9   122 use 5.012;
  9         23  
38              
39 9     9   43 use Carp;
  9         14  
  9         641  
40 9     9   3259 use App::CELL::Config qw( $meta $core $site );
  9         23  
  9         788  
41 9     9   3964 use App::CELL::Load;
  9         24  
  9         297  
42 9     9   50 use App::CELL::Log qw( $log );
  9         16  
  9         676  
43 9     9   50 use App::CELL::Status;
  9         15  
  9         242  
44 9     9   39 use App::CELL::Util qw( stringify_args utc_timestamp );
  9         16  
  9         352  
45 9     9   43 use Params::Validate qw( :all );
  9         16  
  9         1001  
46 9     9   75 use Scalar::Util qw( blessed );
  9         17  
  9         497  
47              
48              
49             =head1 NAME
50              
51             App::CELL - Configuration, Error-handling, Localization, and Logging
52              
53              
54              
55             =head1 VERSION
56              
57             Version 0.231
58              
59             =cut
60              
61             our $VERSION = '0.231';
62              
63              
64              
65             =head1 SYNOPSIS
66              
67             # imagine you have a script/app called 'foo' . . .
68              
69             use Log::Any::Adapter ( 'File', "/var/tmp/foo.log" );
70             use App::CELL qw( $CELL $log $meta $site );
71              
72             # load config params and messages from sitedir
73             my $status = $CELL->load( sitedir => '/etc/foo' );
74             return $status unless $status->ok;
75              
76             # set appname to FOO_APPNAME (a config param just loaded from sitedir)
77             $CELL->appname( $CELL->FOO_APPNAME || "foo" );
78              
79             # write to the log
80             $log->notice("Configuration loaded from /etc/foo");
81              
82             # get value of site configuration parameter FOO_PARAM
83             my $val = $site->FOO_PARAM;
84              
85             # get a list of all supported languages
86             my @supp_lang = $CELL->supported_languages;
87              
88             # determine if a language is supported
89             print "sk supported" if $CELL->language_supported('sk');
90              
91             # get message object and text in default language
92             $status = $CELL->msg('FOO_INFO_MSG');
93             my $fmsg = $status->payload if $status->ok;
94             my $text = $fmsg->text;
95              
96             # get message object and text in default language
97             # (message that takes arguments)
98             $fmsg = $CELL->msg('BAR_ARGS_MSG', "arg1", "arg2");
99             print $fmsg->text, "\n";
100              
101             # get text of message in a different language
102             my $sk_text = $fmsg->lang('sk')->text;
103              
104              
105              
106              
107             =head1 DESCRIPTION
108              
109             This is the top-level module of App::CELL, the Configuration,
110             Error-handling, Localization, and Logging framework for applications (or
111             scripts) written in Perl.
112              
113             For details, read the POD in the L distro. For an introduction,
114             read L.
115              
116              
117              
118             =head1 EXPORTS
119              
120             This module provides the following exports:
121              
122             =over
123              
124             =item C<$CELL> - App::CELL singleton object
125              
126             =item C<$log> - App::CELL::Log singleton object
127              
128             =item C<$meta> - App::CELL::Config singleton object
129              
130             =item C<$core> - App::CELL::Config singleton object
131              
132             =item C<$site> - App::CELL::Config singleton object
133              
134             =back
135              
136             =cut
137              
138 9     9   48 use Exporter qw( import );
  9         15  
  9         4573  
139             our @EXPORT_OK = qw( $CELL $log $meta $core $site );
140              
141             our $CELL = bless {
142             appname => __PACKAGE__,
143             enviro => '',
144             }, __PACKAGE__;
145              
146             # ($log is imported from App::CELL::Log)
147             # ($meta, $core, and $site are imported from App::CELL::Config)
148              
149              
150              
151             =head1 METHODS
152              
153              
154             =head2 appname
155              
156             If no argument is given, returns the C -- i.e. the name of the
157             application or script that is using L for its configuration,
158             error handling, etc.
159              
160             If an argument is given, assumes that it denotes the desired C and sets
161             it. Also initializes the logger.
162              
163             =cut
164              
165             sub appname {
166 0     0 1 0 my @ARGS = @_;
167 0 0       0 return $CELL->{appname} if not @ARGS;
168 0         0 $CELL->{appname} = $ARGS[0];
169 0         0 $log->ident( $CELL->{'appname'} );
170             }
171              
172              
173             =head2 enviro
174              
175             Get the C attribute, i.e. the name of the environment variable
176             containing the sitedir
177              
178             =cut
179              
180 0     0 1 0 sub enviro { return $CELL->{enviro}; }
181              
182              
183             =head2 loaded
184              
185             Get the current load status, which can be any of the following:
186             0 nothing loaded yet
187             'SHARE' sharedir loaded
188             'BOTH' sharedir _and_ sitedir loaded
189              
190             =cut
191              
192             sub loaded {
193 7 100 100 7 1 407 return 'SHARE' if $App::CELL::Load::sharedir_loaded and not
194             @App::CELL::Load::sitedir;
195 4 100 66     21 return 'BOTH' if $App::CELL::Load::sharedir_loaded and
196             @App::CELL::Load::sitedir;
197 3         12 return 0;
198             }
199              
200              
201             =head2 sharedir
202              
203             Get the C attribute, i.e. the full path of the site configuration
204             directory (available only after sharedir has been successfully loaded)
205              
206             =cut
207              
208             sub sharedir {
209 2 100   2 1 949 return '' if not $App::CELL::Load::sharedir_loaded;
210 1         4 return $App::CELL::Load::sharedir;
211             }
212              
213              
214             =head2 sitedir
215              
216             Get the C attribute, i.e. the full path of the site configuration
217             directory (available only after sitedir has been successfully loaded)
218              
219             =cut
220              
221             sub sitedir {
222 1 50   1 1 6 return '' if not $App::CELL::Load::sitedir;
223 0         0 return $App::CELL::Load::sitedir;
224             }
225              
226              
227             =head2 supported_languages
228              
229             Get list of supported languages. Equivalent to:
230              
231             $site->CELL_SUPP_LANG || [ 'en ]
232              
233             =cut
234              
235             sub supported_languages {
236 3     3 1 12 return App::CELL::Message::supported_languages();
237             }
238              
239              
240             =head2 language_supported
241              
242             Determine if a given language is supported.
243              
244             =cut
245              
246             sub language_supported {
247 5     5 1 24 return App::CELL::Message::language_supported( $_[1] );
248             }
249              
250              
251             =head2 C
252              
253             Attempt to load messages and configuration parameters from the sharedir
254             and, possibly, the sitedir as well.
255              
256             Takes: a PARAMHASH that should include at least one of C or
257             C (if both are given, C takes precedence with C
258             as a fallback). The PARAMHASH can also include a C parameter
259             which, when set to a true value, causes the load routine to log more
260             verbosely.
261              
262             Returns: an C object, which could be any of the
263             following:
264             OK success
265             WARN previous call already succeeded, nothing to do
266             ERR failure
267              
268             On success, it also sets the C meta parameter.
269              
270             =cut
271              
272             sub load {
273 10     10 1 46 my $class = shift;
274 10         249 my ( %ARGS ) = validate( @_, {
275             enviro => { type => SCALAR, optional => 1 },
276             sitedir => { type => SCALAR, optional => 1 },
277             verbose => { type => SCALAR, default => 0 },
278             } );
279 10         43 my $status;
280              
281 10         84 $log->info( "CELL version $VERSION called from " . (caller)[0] .
282             " with arguments " . stringify_args( \%ARGS ),
283             cell => 1, suppress_caller => 1 );
284              
285             # we only get past this next call if at least the sharedir loads
286             # successfully (sitedir is optional)
287 10         47 $status = App::CELL::Load::init( %ARGS );
288 10 100       27 return $status unless $status->ok;
289 2 50       10 $log->info( "App::CELL has finished loading messages and site conf params",
290             cell => 1 ) if $meta->CELL_META_LOAD_VERBOSE;
291              
292 2         10 $log->show_caller( $site->CELL_LOG_SHOW_CALLER );
293 2         9 $log->debug_mode ( $site->CELL_DEBUG_MODE );
294              
295 2   50     10 $App::CELL::Message::supp_lang = $site->CELL_SUPP_LANG || [ 'en' ];
296 2   50     7 $App::CELL::Message::def_lang = $site->CELL_DEF_LANG || 'en';
297              
298 2         7 $meta->set( 'CELL_META_START_DATETIME', utc_timestamp() );
299 2         15 $log->info( "**************** App::CELL $VERSION loaded and ready ****************",
300             cell => 1, suppress_caller => 1 );
301              
302 2         5 return App::CELL::Status->ok;
303             }
304              
305              
306              
307             =head2 Status constructors
308              
309             The following "factory" makes a bunch of status constructor methods
310             (wrappers for App::CELL::Status->new )
311              
312             =cut
313              
314             BEGIN {
315 9     9   150 foreach (@App::CELL::Log::permitted_levels) {
316 9     9   57 no strict 'refs';
  9         16  
  9         1391  
317 135         272 my $level_uc = $_;
318 135         192 my $level_lc = lc $_;
319 135         1479 *{"status_$level_lc"} = sub {
320 22     22   61 my ( $self, $code, @ARGS ) = @_;
321 22 50       69 if ( @ARGS % 2 ) { # odd number of arguments
322 0         0 $log->warn( "status_$level_lc called with odd number (" .
323             scalar @ARGS .
324             ") of arguments; discarding the arguments!" );
325 0         0 @ARGS = ();
326             }
327 22         38 my %ARGS = @ARGS;
328 22         121 return App::CELL::Status->new(
329             level => $level_uc,
330             code => $code,
331             caller => [ CORE::caller() ],
332             %ARGS,
333             );
334             }
335 135         486 }
336             }
337              
338             =head3 status_crit
339              
340             Constructor for 'CRIT' status objects
341              
342             =head3 status_critical
343              
344             Constructor for 'CRIT' status objects
345              
346             =head3 status_debug
347              
348             Constructor for 'DEBUG' status objects
349              
350             =head3 status_emergency
351              
352             Constructor for 'DEBUG' status objects
353              
354             =head3 status_err
355              
356             Constructor for 'ERR' status objects
357              
358             =head3 status_error
359              
360             Constructor for 'ERR' status objects
361              
362             =head3 status_fatal
363              
364             Constructor for 'FATAL' status objects
365              
366             =head3 status_info
367              
368             Constructor for 'INFO' status objects
369              
370             =head3 status_inform
371              
372             Constructor for 'INFORM' status objects
373              
374             =head3 status_not_ok
375              
376             Constructor for 'NOT_OK' status objects
377              
378             =head3 status_notice
379              
380             Constructor for 'NOTICE' status objects
381              
382             =head3 status_ok
383              
384             Constructor for 'OK' status objects
385              
386             =head3 status_trace
387              
388             Constructor for 'TRACE' status objects
389              
390             =head3 status_warn
391              
392             Constructor for 'WARN' status objects
393              
394             =head3 status_warning
395              
396             Constructor for 'WARNING' status objects
397              
398              
399             =head2 msg
400              
401             Construct a message object (wrapper for App::CELL::Message::new)
402              
403             =cut
404              
405             sub msg {
406 4     4 1 12 my ( $self, $code, @ARGS ) = @_;
407 4         16 my $status = App::CELL::Message->new( code => $code, args => [ @ARGS ] );
408 4 50       13 return if $status->not_ok; # will return undef in scalar mode
409 4 50       12 return $status->payload if blessed $status->payload;
410 0           return;
411             }
412              
413              
414              
415              
416             =head1 LICENSE AND COPYRIGHT
417              
418             Copyright (c) 2014-2020, SUSE LLC
419              
420             All rights reserved.
421              
422             Redistribution and use in source and binary forms, with or without
423             modification, are permitted provided that the following conditions are met:
424              
425             1. Redistributions of source code must retain the above copyright notice,
426             this list of conditions and the following disclaimer.
427              
428             2. Redistributions in binary form must reproduce the above copyright
429             notice, this list of conditions and the following disclaimer in the
430             documentation and/or other materials provided with the distribution.
431              
432             3. Neither the name of SUSE LLC nor the names of its contributors may be
433             used to endorse or promote products derived from this software without
434             specific prior written permission.
435              
436             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
437             AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
438             IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
439             ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
440             LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
441             CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
442             SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
443             INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
444             CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
445             ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
446             POSSIBILITY OF SUCH DAMAGE.
447              
448             =cut
449              
450             # END OF CELL MODULE
451             1;