New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
Reporter.pm in vendors/lib/FCM/Util – NEMO

source: vendors/lib/FCM/Util/Reporter.pm @ 10669

Last change on this file since 10669 was 10669, checked in by nicolasmartin, 5 years ago

Import latest FCM release from Github into the repository for testing

File size: 10.0 KB
Line 
1# ------------------------------------------------------------------------------
2# (C) British Crown Copyright 2006-17 Met Office.
3#
4# This file is part of FCM, tools for managing and building source code.
5#
6# FCM is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# FCM is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with FCM. If not, see <http://www.gnu.org/licenses/>.
18# ------------------------------------------------------------------------------
19use strict;
20use warnings;
21
22# ------------------------------------------------------------------------------
23package FCM::Util::Reporter;
24use base qw{FCM::Class::CODE};
25
26use Scalar::Util qw{reftype};
27
28use constant {TYPE_OUT => 1, TYPE_ERR => 2};
29
30use constant {  DEFAULT => 1,
31    FAIL  => 0, WARN    => 1,
32    QUIET => 0, LOW     => 1, MEDIUM => 2, HIGH => 3, DEBUG => 4,
33};
34
35use constant {
36    PREFIX_DONE => q{[done] },
37    PREFIX_FAIL => q{[FAIL] },
38    PREFIX_INFO => q{[info] },
39    PREFIX_INIT => q{[init] },
40    PREFIX_NULL => q{},
41    PREFIX_QUIT => q{[quit] },
42    PREFIX_WARN => q{[WARN] },
43};
44
45# Creates the class.
46__PACKAGE__->class(
47    {ctx_of => '%'},
48    {   init => sub {
49            my ($attrib_ref) = @_;
50            %{$attrib_ref->{ctx_of}} = (
51                stderr => FCM::Util::Reporter::Context->new_err(),
52                stdout => FCM::Util::Reporter::Context->new(),
53            );
54        },
55        action_of => {
56            add_ctx           => \&_add_ctx,
57            del_ctx           => \&_del_ctx,
58            get_ctx           => \&_get_ctx,
59            get_ctx_of_stderr => sub {$_[0]->{ctx_of}->{stderr}},
60            get_ctx_of_stdout => sub {$_[0]->{ctx_of}->{stdout}},
61            report            => \&_report,
62        }
63    },
64);
65
66# Adds a named reporter context.
67sub _add_ctx {
68    my ($attrib_ref, $key, @args) = @_;
69    if (exists($attrib_ref->{ctx_of}->{$key})) {
70        return;
71    }
72    $attrib_ref->{ctx_of}->{$key} = FCM::Util::Reporter::Context->new(@args);
73}
74
75# Deletes a named reporter context.
76sub _del_ctx {
77    my ($attrib_ref, $key) = @_;
78    if (!exists($attrib_ref->{ctx_of}->{$key})) {
79        return;
80    }
81    delete($attrib_ref->{ctx_of}->{$key});
82}
83
84# Returns a named reporter context.
85sub _get_ctx {
86    my ($attrib_ref, $key) = @_;
87    if (!exists($attrib_ref->{ctx_of}->{$key})) {
88        return;
89    }
90    $attrib_ref->{ctx_of}->{$key};
91}
92
93# Reports message.
94sub _report {
95    my ($attrib_ref, @args) = @_;
96    if (!@args) {
97        return;
98    }
99    my %option = (
100        delimiter => "\n",
101        level     => DEFAULT,
102        prefix    => undef,
103        type      => TYPE_OUT,
104    );
105    if (ref($args[0]) && reftype($args[0]) eq 'HASH') {
106        %option = (%option, %{shift(@args)});
107    }
108    # Auto remove ctx with closed file handle
109    while (my ($key, $ctx) = each(%{$attrib_ref->{ctx_of}})) {
110        if (!defined(fileno($ctx->get_handle()))) {
111            delete($attrib_ref->{ctx_of}->{$key});
112        }
113    }
114    # Selects handles
115    my @ctx_and_prefix_list
116        =   map  {
117                my $prefix = defined($option{prefix})
118                    ? $option{prefix} : $_->get_prefix();
119                if (ref($prefix) && reftype($prefix) eq 'CODE') {
120                    $prefix = $prefix->($option{level}, $option{type});
121                }
122                [$_, $prefix],
123            }
124            grep {  (!$_->get_type() || $_->get_type() eq $option{type})
125                &&  $_->get_verbosity() >= $option{level}
126            }
127            values(%{$attrib_ref->{ctx_of}});
128    if (!@ctx_and_prefix_list) {
129        return;
130    }
131    for my $arg (@args) {
132        for (@ctx_and_prefix_list) {
133            my ($ctx, $prefix) = @{$_};
134            my $handle = $ctx->get_handle();
135            if ($option{delimiter}) {
136                for my $item (
137                    map {grep {$_ ne "\n"} split(qr{(\n)}msx)} (
138                          !ref($arg)               ? ($arg)
139                        : reftype($arg) eq 'ARRAY' ? @{$arg}
140                        : reftype($arg) eq 'CODE'  ? $arg->($ctx->get_verbosity())
141                        :                            ($arg)
142                    )
143                ) {
144                    print({$handle} $prefix . $item . $option{delimiter});
145                }
146            }
147            else {
148                print({$handle} $arg);
149            }
150        }
151    }
152    1;
153}
154
155# ------------------------------------------------------------------------------
156package FCM::Util::Reporter::Context;
157use base qw{FCM::Class::HASH};
158
159# Creates the class.
160__PACKAGE__->class(
161    {   handle    => {isa => '*', default => \*STDOUT                     },
162        prefix    => {            default => sub {\&_prefix}              },
163        type      => {isa => '$', default => FCM::Util::Reporter->TYPE_OUT},
164        verbosity => {isa => '$', default => FCM::Util::Reporter->DEFAULT },
165    },
166);
167
168# Returns a new reporter context to STDERR.
169sub new_err {
170    my ($class, $attrib_ref) = @_;
171    $class->new({
172        handle => \*STDERR,
173        type   => FCM::Util::Reporter->TYPE_ERR,
174        (defined($attrib_ref) ? %{$attrib_ref} : ()),
175    });
176}
177
178# The default prefix function.
179sub _prefix {
180    my ($level, $type) = @_;
181      $type eq FCM::Util::Reporter->TYPE_OUT ? FCM::Util::Reporter->PREFIX_INFO
182    : $level > FCM::Util::Reporter->FAIL     ? FCM::Util::Reporter->PREFIX_WARN
183    :                                          FCM::Util::Reporter->PREFIX_FAIL
184    ;
185}
186
187# ------------------------------------------------------------------------------
1881;
189__END__
190
191=head1 NAME
192
193FCM::Reporter
194
195=head1 SYNOPSIS
196
197    use FCM::Util::Reporter;
198    $reporter = FCM::Util::Reporter->new({verbosity => $verbosity});
199    $reporter->($message);
200    $reporter->(\@messages);
201    $reporter->(sub {return @some_strings});
202    $reporter->({level => $reporter->MEDIUM}, $message);
203
204=head1 DESCRIPTION
205
206A simple message reporter.
207
208This module is part of L<FCM::Util|FCM::Util>. See also the description of the
209$u->report() method in L<FCM::Util|FCM::Util>.
210
211=head1 METHODS
212
213=over 4
214
215=item $class->new(\%attrib)
216
217Returns a new instance of this class, which is a CODE reference. %attrib can
218contain the following:
219
220=over 4
221
222=item ctx_of
223
224A HASH containing a map to the named reporter contexts. At initialisation, a new
225ctx for "stdout" and a new ctx for "stderr" is created automatically.
226
227=back
228
229=item $reporter->add_ctx($key,%option)
230
231Creates a new reporter context, and adds it to the ctx_of HASH, if a context
232with the same $key does not already exist. The %option is given to the
233constructir of L</FCM::Util::Reporter::Context>. Return the context on success.
234
235=item $reporter->del_ctx($key)
236
237Removes a new reporter context named $key. Return the context on success.
238
239=item $reporter->get_ctx($key)
240
241Returns a named reporter context L</FCM::Util::Reporter::Context>.
242
243=item $reporter->get_ctx_of_stderr()
244
245Shorthand for $reporter->get_ctx('stderr').
246
247=item $reporter->get_ctx_of_stdout()
248
249Shorthand for $reporter->get_ctx('stdout').
250
251=item $reporter->report(\%option,$message)
252
253Reports the message. If %option is not given, reports using the default options.
254In the form, the following %options can be specified:
255
256=over 4
257
258=item delimiter
259
260The delimiter of each message in the list. The default is "\n". If the delimiter
261is set to the empty string, the items in $message will be treated as raw
262strings, i.e. it will also ignore any "prefix" options.
263
264=item level
265
266The level of the current message. The default is DEFAULT.
267
268=item prefix
269
270The message prefix. It can be a string or a CODE reference. If it is a string,
271it is simply preprended to the message. If it is a code reference, it is calls
272as $prefix_ref->($option{level}, $option{type}), and its result (if defined) is
273prepended to the message.
274
275=item type
276
277The message type. It can be REPORT_ERR or REPORT_OUT (default).
278
279=back
280
281=back
282
283=head1 CONSTANTS
284
285=over 4
286
287=item $reporter->FAIL, $reporter->QUIET
288
289The verbosity level 0.
290
291=item $reporter->DEFAULT, $reporter->LOW, $reporter->WARN
292
293The verbosity level 1.
294
295=item $reporter->MEDIUM
296
297The verbosity level 2.
298
299=item $reporter->HIGH
300
301The verbosity level 3.
302
303=item $reporter->DEBUG
304
305The verbosity level 4.
306
307=item $reporter->PREFIX_DONE
308
309The prefix for a task "done" message.
310
311=item $reporter->PREFIX_FAIL
312
313The prefix for a fatal error message.
314
315=item $reporter->PREFIX_INFO
316
317The prefix for an "info" message.
318
319=item $reporter->PREFIX_INIT
320
321The prefix for a task "init" message.
322
323=item $reporter->PREFIX_NULL
324
325An empty string.
326
327=item $reporter->PREFIX_QUIT
328
329The prefix for a quit/abort message.
330
331=item $reporter->PREFIX_WARN
332
333The prefix for a warning message.
334
335=item $reporter->REPORT_ERR
336
337The message type for exception message.
338
339=item $reporter->REPORT_OUT
340
341The message type for info message.
342
343=back
344
345=head1 FCM::Util::Reporter::Context
346
347An instance of this class represents the context for a reporter for the
348L<FCM::Util->report()|FCM::Util>. This class is a sub-class of
349L<FCM::Class::HASH|FCM::Class::HASH>. It has the following attributes:
350
351=over 4
352
353=item handle
354
355The file handle for info messages. (Default=\*STDOUT)
356
357=item prefix
358
359The message prefix. It can be a string or a CODE reference. If it is a string,
360it is simply preprended to the message. If it is a code reference, it is calls
361as $prefix_ref->($option{level}, $option{type}), and its result (if defined) is
362prepended to the message. The default is a CODE that returns PREFIX_INFO for
363TYPE_OUT messages, PREFIX_WARN for TYPE_ERR messages at WARN level or above or
364PREFIX_FAIL for TYPE_ERR messages at FAIL level.
365
366=item type
367
368Reporter type. (Default=TYPE_OUT)
369
370=item verbosity
371
372The verbosity of the reporter. Only messages at a level above or equal to the
373verbosity will be reported. The default is DEFAULT.
374
375=back
376
377
378=head1 COPYRIGHT
379
380(C) Crown copyright Met Office. All rights reserved.
381
382=cut
Note: See TracBrowser for help on using the repository browser.