File Coverage

blib/lib/Config/Model/Exception.pm
Criterion Covered Total %
statement 213 260 81.9
branch 36 68 52.9
condition 8 23 34.7
subroutine 61 74 82.4
pod 1 19 5.2
total 319 444 71.8


line stmt bran cond sub pod time code
1             #
2             # This file is part of Config-Model
3             #
4             # This software is Copyright (c) 2005-2022 by Dominique Dumont.
5             #
6             # This is free software, licensed under:
7             #
8             # The GNU Lesser General Public License, Version 2.1, February 1999
9             #
10              
11             use warnings;
12 59     59   339 use strict;
  59         109  
  59         1623  
13 59     59   267 use Data::Dumper;
  59         103  
  59         1004  
14 59     59   238 use Mouse;
  59         102  
  59         2811  
15 59     59   286 use v5.20;
  59         127  
  59         310  
16 59     59   18992 use Carp;
  59         207  
17 59     59   333  
  59         115  
  59         3480  
18             use feature qw/postderef signatures/;
19 59     59   389 no warnings qw/experimental::postderef experimental::signatures/;
  59         137  
  59         8340  
20 59     59   354  
  59         128  
  59         3835  
21             @Carp::CARP_NOT=qw/Config::Model::Exception Config::Model::Exception::Any/;
22              
23             our $trace = 0;
24              
25             use Carp qw/longmess shortmess croak/;
26 59     59   333  
  59         143  
  59         4074  
27             use overload
28             '""' => \&full_msg_and_trace,
29 59         495 'bool' => \&is_error;
30 59     59   341  
  59         101  
31             has description => (
32             is => 'ro',
33             isa => 'Str',
34             lazy_build => 1
35             );
36              
37             my $self = shift;
38             return $self->_desc;
39 32     32   66 }
40 32         122  
41              
42             has object => ( is => 'rw', isa => 'Ref') ;
43 0     0   0 has info => (is => 'rw', isa =>'Str', default => '');
44             has message => (is => 'rw', isa =>'Str', default => '');
45             has error => (is => 'rw', isa =>'Str', default => '');
46             has trace => (is => 'rw', isa =>'Str', default => '');
47              
48             # need to keep these objects around: in some tests the error() method is
49             # called after the instance is garbage collected. Instances are kept
50             # as weak ref in node (and othe tree objects). When instance is
51             # garbage collected, it's destroyed so error() can no longer be invoked.
52             # Solution: keep instance as error attributes.
53             has instance => ( is => 'rw', isa => 'Ref') ;
54              
55             $self->instance($self->object->instance) if defined $self->object;
56             }
57              
58 143     143 1 7112 # without this overload, a test like if ($@) invokes '""' overload
  143         221  
  143         197  
59 143 100       1336  
60              
61             $trace = shift;
62             }
63 46     46 0 3794  
64             my $self = shift;
65             return $self->error || $self->message;
66             }
67 1     1 0 2968  
68             my $class = shift;
69             my $self = $class->new(@_);
70             # when an exception is thrown, caught and rethrown, the first full
71 11     11 0 20 # trace (provided by longmess) is clobbered by a second, shorter
72 11   66     66 # trace (also provided by longmess). To avoid that, the first
73             # trace must be stored.
74             $self->trace($trace ? longmess : '') ;
75             die $self;
76 143     143 0 279 }
77 143         2436  
78             my $self = shift;
79             die $self;
80             }
81              
82 143 100       808 my $self = shift;
83 143         2815 my $msg = $self->full_message;
84             $msg .= $self->trace;
85             return $msg;
86             }
87 2     2 0 5  
88 2         10 goto &full_msg_and_trace;
89             }
90              
91             my $self = shift;
92 29     29 0 1941  
93 29         123 my $obj = $self->object;
94 29         139 my $location = defined $obj ? $obj->name : '';
95 29         166 my $msg = "Configuration item ";
96             $msg .= "'$location' " if $location;
97             $msg .= "has a " . $self->description;
98             $msg .= ":\n\t" . ($self->error || $self->message) . "\n";
99 1     1 0 4 $msg .= $self->info . "\n" if $self->info;
100             return $msg;
101             }
102              
103 13     13 0 30  
104             use Mouse;
105 13         44 extends 'Config::Model::Exception';
106 13 100       62  
107 13         29  
108 13 100       62 use Mouse;
109 13         135 extends 'Config::Model::Exception::Fatal';
110 13   66     125  
111 13 100       67  
112 13         34  
113             use Mouse;
114             extends 'Config::Model::Exception::Any';
115              
116              
117 59     59   36812 ## old classes below
  59         142  
  59         256  
118              
119             use Mouse;
120             extends 'Config::Model::Exception::Any';
121              
122 59     59   20649  
  59         121  
  59         221  
123             has [qw/parsed_file parsed_line/] => (is => 'rw');
124              
125 2     2   15 my $self = shift;
126              
127             my $fn = $self->parsed_file || '?';
128             my $line = $self->parsed_line || '?';
129 59     59   20387 my $msg = "File $fn line $line ";
  59         125  
  59         258  
130             $msg .= "has a " . $self->description;
131 1     1   5 $msg .= ":\n\t" . $self->error_or_msg . "\n";
132              
133             return $msg;
134             }
135              
136              
137 59     59   19766 use Mouse;
  59         125  
  59         273  
138             extends 'Config::Model::Exception::User';
139              
140 0     0   0  
141             has wrong_data => (is => 'rw');
142              
143             my $self = shift;
144              
145 0     0 0 0 my $obj = $self->object;
146             my $location = defined $obj ? $obj->name : '';
147 0   0     0 my $msg = "Configuration item ";
148 0   0     0 my $d = Data::Dumper->new( [ $self->wrong_data ], ['wrong data'] );
149 0         0 $d->Sortkeys(1);
150 0         0 $msg .= "'$location' " if $location;
151 0         0 $msg .= "(class " . $obj->config_class_name . ") " if $obj->get_type eq 'node';
152             $msg .= "has a " . $self->description;
153 0         0 $msg .= ":\n\t" . $self->error_or_msg . "\n";
154             $msg .= $d->Dump;
155              
156             return $msg;
157             }
158 59     59   26440  
  59         130  
  59         227  
159              
160             use Carp;
161 0     0   0 use Mouse;
162             extends 'Config::Model::Exception::Fatal';
163              
164              
165              
166 0     0 0 0 my $self = shift;
167              
168 0         0 my $obj = $self->object
169 0 0       0 || croak "Internal error: no object parameter passed while throwing exception";
170 0         0 my $msg;
171 0         0 if ( $obj->isa('Config::Model::Node') ) {
172 0         0 $msg = "Node '" . $obj->name . "' of class " . $obj->config_class_name . ' ';
173 0 0       0 }
174 0 0       0 else {
175 0         0 my $element = $obj->element_name;
176 0         0 my $level = $obj->parent->get_element_property(
177 0         0 element => $element,
178             property => 'level'
179 0         0 );
180             my $location = $obj->location;
181             $msg = "In config class '" . $obj->parent->config_class_name. "',";
182             $msg .= " (location: $location)" if $location;
183             $msg .= " element '$element' (level $level) ";
184 59     59   29020 }
  59         163  
  59         3306  
185 59     59   355 $msg .= "has a " . $self->description;
  59         132  
  59         255  
186             $msg .= ":\n\t" . $self->error_or_msg . "\n";
187              
188 2     2   10 return $msg;
189             }
190              
191              
192 2     2 0 5 use Mouse;
193             extends 'Config::Model::Exception::User';
194 2   33     10  
195              
196 2         4 has command => (is => 'rw', isa => 'ArrayRef|Str');
197 2 50       18  
198 0         0 my $self = shift;
199              
200             my $location = defined $self->object ? $self->object->name : '';
201 2         9 my $msg = $self->description;
202 2         15 my $cmd = $self->command;
203             no warnings 'uninitialized';
204             my $cmd_str =
205             ref($cmd) ? join('',@$cmd)
206 2         18 : $cmd ? "'$cmd'"
207 2         14 : defined $cmd ? '<empty>'
208 2 50       10 : '<undef>';
209 2         10 $msg .= " in node '$location' " if $location;
210             $msg .= ':';
211 2         19 $msg .= "\n\tcommand: $cmd_str";
212 2         12 $msg .= "\n\t" . $self->error_or_msg . "\n";
213              
214 2         6 return $msg;
215             }
216              
217              
218             use Mouse;
219 59     59   31162 extends 'Config::Model::Exception::User';
  59         125  
  59         214  
220              
221              
222 9     9   39 has [qw/element function/] => (is => 'rw', isa => 'Str');
223              
224              
225             my $self = shift;
226              
227 9     9 0 15 my $obj = $self->object;
228             my $location = $obj->name;
229 9 100       57 my $msg = $self->description;
230 9         58 my $element = $self->element;
231 9         23 my $function = $self->function;
232 59     59   22827 my $unavail = $obj->fetch_element(
  59         228  
  59         8368  
233 9 0       59 name => $element,
    50          
    100          
234             check => 'no',
235             accept_hidden => 1
236             );
237             $msg .= " '$element' in node '$location'.\n";
238 9 100       32 $msg .= "\tError occurred when calling $function.\n" if defined $function;
239 9         19 $msg .= "\t" . $unavail->warp_error if $unavail->can('warp_error');
240 9         16  
241 9         24 $msg .= "\t" . $self->info . "\n" if defined $self->info;
242             return $msg;
243 9         18 }
244              
245              
246             use Mouse;
247             extends 'Config::Model::Exception::User';
248 59     59   380  
  59         118  
  59         292  
249              
250              
251 2     2   11  
252             use Mouse;
253             extends 'Config::Model::Exception::User';
254              
255              
256             has element => (is => 'rw', isa => 'Str');
257 2     2 0 3  
258             my $self = shift;
259 2         7  
260 2         8 my $obj = $self->object;
261 2         20 my $element = $self->element;
262 2         7 my $msg = $self->description;
263 2         5  
264 2         8 my $location = $obj->name;
265             my $help = $obj->get_help_as_text($element) || '';
266              
267             $msg .= " '$element' in node '$location'.\n";
268             $msg .= "\t$help\n";
269 2         9 $msg .= "\t" . $self->info . "\n" if defined $self->info;
270 2 50       7 return $msg;
271 2 50       29 }
272              
273 2 50       19  
274 2         5 use Carp;
275              
276             use Mouse;
277             extends 'Config::Model::Exception::User';
278              
279 59     59   30723  
  59         118  
  59         282  
280             has [qw/element function where/] => (is => 'rw');
281              
282 0     0   0 my $self = shift;
283              
284             my $obj = $self->object;
285              
286             confess "Exception::UnknownElement: object is ", ref($obj), ". Expected a node"
287 59     59   20336 unless ref($obj) && ($obj->isa('Config::Model::Node')
  59         120  
  59         228  
288             || $obj->isa('Config::Model::WarpedNode'));
289              
290 0     0   0 my $class_name = $obj->config_class_name;
291              
292             # class_name is undef if the warped_node is warped out
293             my @elements;
294             @elements = $obj->get_element_name(
295 0     0 0 0 class => $class_name,
296             ) if defined $class_name;
297 0         0  
298 0         0 my $msg = '';
299 0         0 $msg .= "Configuration path '" . $self->where . "': "
300             if defined $self->where;
301 0         0  
302 0   0     0 $msg .= "(function '" . $self->function . "') "
303             if defined $self->function;
304 0         0  
305 0         0 $msg = "object '" . $obj->name . "' error: " unless $msg;
306 0 0       0  
307 0         0 $msg .= $self->description . " '" . $self->element . "'.";
308              
309             # retrieve a support url from application info to guide user toward the right bug tracker
310             my $info = $obj->instance->get_support_info // 'to https://github.com/dod38fr/config-model/issues';
311             $msg .=
312 59     59   26872 " Either your file has an error or $class_name model is lagging behind. "
  59         143  
  59         3244  
313             . "In the latter case, please submit a bug report $info. See cme man "
314 59     59   340 . "page for details.\n";
  59         126  
  59         239  
315              
316             if (@elements) {
317 4     4   40 $msg .= "\tExpected elements: '" . join( "','", @elements ) . "'\n";
318             }
319             else {
320             $msg .= " (node is warped out)\n";
321             }
322 2     2 0 4  
323             my @match_keys = $obj->can('accept_regexp') ? $obj->accept_regexp() : ();
324 2         7 if (@match_keys) {
325             $msg .= "\tor an acceptable parameter matching '" . join( "','", @match_keys ) . "'\n";
326 2 50 33     21 }
      33        
327              
328             # inform about available elements after a change of warp master value
329             if ( defined $obj->parent ) {
330 2         7 my $parent = $obj->parent;
331             my $element_name = $obj->element_name;
332              
333 2         5 if ( $parent->element_type($element_name) eq 'warped_node' ) {
334 2 50       12 $msg .= "\t"
335             . $parent->fetch_element(
336             name => $element_name,
337             qw/check no accept_hidden 1/
338 2         8 )->warp_error;
339 2 50       13 }
340             }
341              
342 2 50       18 $msg .= "\t" . $self->info . "\n" if ( defined $self->info );
343              
344             return $msg;
345 2 50       8 }
346              
347 2         46  
348             use Mouse;
349             extends 'Config::Model::Exception::User';
350 2   50     20  
351 2         62  
352              
353             use Mouse;
354             extends 'Config::Model::Exception::Any';
355              
356 2 50       7  
357 2         12  
358              
359             use Mouse;
360 0         0 extends 'Config::Model::Exception::User';
361              
362              
363 2 50       30 has [qw/element id function where/] => (is => 'rw', isa => 'Str');
364 2 50       7  
365 0         0 my $self = shift;
366              
367             my $obj = $self->object;
368              
369 2 50       10 my $element = $self->element;
370 0         0 my $id_str = "'" . join( "','", $obj->fetch_all_indexes() ) . "'";
371 0         0  
372             my $msg = '';
373 0 0       0 $msg .= "In function " . $self->function . ": "
374 0         0 if defined $self->function;
375              
376             $msg .= "In " . $self->where . ": "
377             if defined $self->where;
378              
379             $msg .=
380             $self->description . " '"
381             . $self->id() . "'"
382 2 50       27 . " for element '"
383             . $obj->location
384 2         9 . "'\n\texpected: $id_str\n";
385              
386             return $msg;
387             }
388              
389 59     59   45268  
  59         119  
  59         232  
390             use Mouse;
391             extends 'Config::Model::Exception::User';
392 0     0   0  
393              
394              
395              
396 59     59   20278 use Mouse;
  59         144  
  59         270  
397             extends 'Config::Model::Exception::User';
398              
399 1     1   4  
400             has [qw/function got_type/] => (is => 'rw', isa => 'Str');
401             has [qw/expected_type/] => (is => 'rw');
402              
403             my $self = shift;
404 59     59   19801  
  59         121  
  59         550  
405             my $obj = $self->object;
406              
407 1     1   9 my $msg = '';
408             $msg .= "In function " . $self->function . ": "
409             if defined $self->function;
410              
411             my $type = $self->expected_type;
412 1     1 0 2  
413             $msg .=
414 1         4 $self->description
415             . " for element '"
416 1         4 . $obj->location
417 1         6 . "'\n\tgot type '"
418             . $self->got_type
419 1         3 . "', expected '"
420 1 50       8 . (ref $type ? join("' or '",@$type) : $type) . "' "
421             . $self->info . "\n";
422              
423 1 50       6 return $msg;
424             }
425              
426 1         9  
427             use Mouse;
428             extends 'Config::Model::Exception::User';
429              
430              
431              
432             use Mouse;
433 1         4 use Mouse::Util::TypeConstraints;
434              
435             extends 'Config::Model::Exception::ConfigFile';
436              
437              
438 59     59   28651 subtype 'ExcpPathTiny', as 'Object', where {$_->isa('Path::Tiny')} ;
  59         141  
  59         264  
439              
440             has file => (is => 'rw', isa => 'Str | ExcpPathTiny' );
441 8     8   38  
442             my $self = shift;
443              
444             return "Error: cannot find configuration file " . $self->file . "\n";
445             }
446 59     59   19889  
  59         137  
  59         262  
447              
448             use Mouse;
449 1     1   15 extends 'Config::Model::Exception::Model';
450              
451              
452              
453             use Mouse;
454             extends 'Config::Model::Exception::Fatal';
455 1     1 0 2  
456              
457 1         4 1;
458              
459 1         2 # ABSTRACT: Exception mechanism for configuration model
460 1 50       9  
461              
462             =pod
463 1         5  
464             =encoding UTF-8
465 1 50       12  
466             =head1 NAME
467              
468             Config::Model::Exception - Exception mechanism for configuration model
469              
470             =head1 VERSION
471              
472             version 2.152
473              
474             =head1 SYNOPSIS
475 1         3  
476             use Config::Model::Exception;
477              
478             # later
479             my $kaboom = 1;
480 59     59   27768 Config::Model::Exception::Model->throw(
  59         145  
  59         244  
481             error => "Went kaboom",
482             object => $self
483 0     0   0 ) if $kaboom;
484              
485             =head1 DESCRIPTION
486              
487 59     59   19897 This module creates exception classes used by L<Config::Model>.
  59         141  
  59         273  
488 59     59   17792  
  59         130  
  59         412  
489             All exception class name begins with C<Config::Model::Exception>
490              
491             The exception classes are:
492 0     0   0  
493             =over
494              
495             =item C<Config::Model::Exception>
496              
497             Base class. It accepts an C<object> argument. The user must pass the
498             reference of the object where the exception occurred. The object name
499 0     0 0 0 is used to generate the error message.
500              
501 0         0 =back
502              
503             TODO: list all exception classes and hierarchy.
504              
505             =head1 How to get trace
506 59     59   13008  
  59         114  
  59         296  
507             By default, most of the exceptions do not print out the stack
508             trace. For debug purpose, you can force a stack trace for all
509 0     0   0 exception classes:
510              
511             Config::Model::Exception->Trace(1) ;
512              
513 59     59   19799 =head1 AUTHOR
  59         137  
  59         257  
514              
515             Dominique Dumont, (ddumont at cpan dot org)
516 1     1   6  
517             =head1 SEE ALSO
518              
519             L<Config::Model>,
520             L<Config::Model::Instance>,
521             L<Config::Model::Node>,
522             L<Config::Model::Value>
523              
524             =head1 AUTHOR
525              
526             Dominique Dumont
527              
528             =head1 COPYRIGHT AND LICENSE
529              
530             This software is Copyright (c) 2005-2022 by Dominique Dumont.
531              
532             This is free software, licensed under:
533              
534             The GNU Lesser General Public License, Version 2.1, February 1999
535              
536             =cut