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   359 use strict;
  59         94  
  59         1657  
13 59     59   283 use Data::Dumper;
  59         92  
  59         941  
14 59     59   253 use Mouse;
  59         101  
  59         2773  
15 59     59   296 use v5.20;
  59         120  
  59         317  
16 59     59   18982 use Carp;
  59         219  
17 59     59   316  
  59         146  
  59         3535  
18             use feature qw/postderef signatures/;
19 59     59   392 no warnings qw/experimental::postderef experimental::signatures/;
  59         149  
  59         8215  
20 59     59   348  
  59         126  
  59         3745  
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   343  
  59         124  
  59         4217  
27             use overload
28             '""' => \&full_msg_and_trace,
29 59         545 'bool' => \&is_error;
30 59     59   358  
  59         100  
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   69 }
40 32         116  
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 7067 # without this overload, a test like if ($@) invokes '""' overload
  143         220  
  143         183  
59 143 100       1258  
60              
61             $trace = shift;
62             }
63 46     46 0 4125  
64             my $self = shift;
65             return $self->error || $self->message;
66             }
67 1     1 0 2895  
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 19 # trace (provided by longmess) is clobbered by a second, shorter
72 11   66     68 # 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 699 }
77 143         2459  
78             my $self = shift;
79             die $self;
80             }
81              
82 143 100       813 my $self = shift;
83 143         2828 my $msg = $self->full_message;
84             $msg .= $self->trace;
85             return $msg;
86             }
87 2     2 0 5  
88 2         9 goto &full_msg_and_trace;
89             }
90              
91             my $self = shift;
92 29     29 0 1835  
93 29         124 my $obj = $self->object;
94 29         94 my $location = defined $obj ? $obj->name : '';
95 29         162 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 7 $msg .= $self->info . "\n" if $self->info;
100             return $msg;
101             }
102              
103 13     13 0 47  
104             use Mouse;
105 13         42 extends 'Config::Model::Exception';
106 13 100       66  
107 13         34  
108 13 100       61 use Mouse;
109 13         137 extends 'Config::Model::Exception::Fatal';
110 13   66     125  
111 13 100       84  
112 13         34  
113             use Mouse;
114             extends 'Config::Model::Exception::Any';
115              
116              
117 59     59   36337 ## old classes below
  59         131  
  59         283  
118              
119             use Mouse;
120             extends 'Config::Model::Exception::Any';
121              
122 59     59   20016  
  59         164  
  59         255  
123             has [qw/parsed_file parsed_line/] => (is => 'rw');
124              
125 2     2   21 my $self = shift;
126              
127             my $fn = $self->parsed_file || '?';
128             my $line = $self->parsed_line || '?';
129 59     59   20460 my $msg = "File $fn line $line ";
  59         138  
  59         251  
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   19857 use Mouse;
  59         129  
  59         292  
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   26301  
  59         113  
  59         266  
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   28812 }
  59         148  
  59         3121  
185 59     59   344 $msg .= "has a " . $self->description;
  59         120  
  59         265  
186             $msg .= ":\n\t" . $self->error_or_msg . "\n";
187              
188 2     2   9 return $msg;
189             }
190              
191              
192 2     2 0 6 use Mouse;
193             extends 'Config::Model::Exception::User';
194 2   33     13  
195              
196 2         4 has command => (is => 'rw', isa => 'ArrayRef|Str');
197 2 50       19  
198 0         0 my $self = shift;
199              
200             my $location = defined $self->object ? $self->object->name : '';
201 2         10 my $msg = $self->description;
202 2         16 my $cmd = $self->command;
203             no warnings 'uninitialized';
204             my $cmd_str =
205             ref($cmd) ? join('',@$cmd)
206 2         20 : $cmd ? "'$cmd'"
207 2         12 : defined $cmd ? '<empty>'
208 2 50       11 : '<undef>';
209 2         8 $msg .= " in node '$location' " if $location;
210             $msg .= ':';
211 2         21 $msg .= "\n\tcommand: $cmd_str";
212 2         12 $msg .= "\n\t" . $self->error_or_msg . "\n";
213              
214 2         5 return $msg;
215             }
216              
217              
218             use Mouse;
219 59     59   31841 extends 'Config::Model::Exception::User';
  59         130  
  59         223  
220              
221              
222 9     9   35 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       49 my $msg = $self->description;
230 9         59 my $element = $self->element;
231 9         25 my $function = $self->function;
232 59     59   22550 my $unavail = $obj->fetch_element(
  59         129  
  59         8825  
233 9 0       37 name => $element,
    50          
    100          
234             check => 'no',
235             accept_hidden => 1
236             );
237             $msg .= " '$element' in node '$location'.\n";
238 9 100       30 $msg .= "\tError occurred when calling $function.\n" if defined $function;
239 9         15 $msg .= "\t" . $unavail->warp_error if $unavail->can('warp_error');
240 9         17  
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   382  
  59         123  
  59         292  
249              
250              
251 2     2   10  
252             use Mouse;
253             extends 'Config::Model::Exception::User';
254              
255              
256             has element => (is => 'rw', isa => 'Str');
257 2     2 0 5  
258             my $self = shift;
259 2         5  
260 2         6 my $obj = $self->object;
261 2         17 my $element = $self->element;
262 2         7 my $msg = $self->description;
263 2         7  
264 2         7 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         8 $msg .= "\t" . $self->info . "\n" if defined $self->info;
270 2 50       5 return $msg;
271 2 50       19 }
272              
273 2 50       14  
274 2         4 use Carp;
275              
276             use Mouse;
277             extends 'Config::Model::Exception::User';
278              
279 59     59   30806  
  59         121  
  59         263  
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   20360 unless ref($obj) && ($obj->isa('Config::Model::Node')
  59         134  
  59         247  
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   26742 " Either your file has an error or $class_name model is lagging behind. "
  59         132  
  59         3245  
313             . "In the latter case, please submit a bug report $info. See cme man "
314 59     59   361 . "page for details.\n";
  59         117  
  59         252  
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 3  
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         8 my $parent = $obj->parent;
331             my $element_name = $obj->element_name;
332              
333 2         4 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         7 )->warp_error;
339 2 50       15 }
340             }
341              
342 2 50       20 $msg .= "\t" . $self->info . "\n" if ( defined $self->info );
343              
344             return $msg;
345 2 50       7 }
346              
347 2         46  
348             use Mouse;
349             extends 'Config::Model::Exception::User';
350 2   50     20  
351 2         64  
352              
353             use Mouse;
354             extends 'Config::Model::Exception::Any';
355              
356 2 50       8  
357 2         13  
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       6  
365 0         0 my $self = shift;
366              
367             my $obj = $self->object;
368              
369 2 50       12 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       49 . " for element '"
383             . $obj->location
384 2         10 . "'\n\texpected: $id_str\n";
385              
386             return $msg;
387             }
388              
389 59     59   43927  
  59         108  
  59         222  
390             use Mouse;
391             extends 'Config::Model::Exception::User';
392 0     0   0  
393              
394              
395              
396 59     59   20283 use Mouse;
  59         132  
  59         261  
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   19435  
  59         131  
  59         590  
405             my $obj = $self->object;
406              
407 1     1   13 my $msg = '';
408             $msg .= "In function " . $self->function . ": "
409             if defined $self->function;
410              
411             my $type = $self->expected_type;
412 1     1 0 3  
413             $msg .=
414 1         5 $self->description
415             . " for element '"
416 1         5 . $obj->location
417 1         8 . "'\n\tgot type '"
418             . $self->got_type
419 1         3 . "', expected '"
420 1 50       11 . (ref $type ? join("' or '",@$type) : $type) . "' "
421             . $self->info . "\n";
422              
423 1 50       6 return $msg;
424             }
425              
426 1         14  
427             use Mouse;
428             extends 'Config::Model::Exception::User';
429              
430              
431              
432             use Mouse;
433 1         5 use Mouse::Util::TypeConstraints;
434              
435             extends 'Config::Model::Exception::ConfigFile';
436              
437              
438 59     59   28412 subtype 'ExcpPathTiny', as 'Object', where {$_->isa('Path::Tiny')} ;
  59         157  
  59         251  
439              
440             has file => (is => 'rw', isa => 'Str | ExcpPathTiny' );
441 8     8   48  
442             my $self = shift;
443              
444             return "Error: cannot find configuration file " . $self->file . "\n";
445             }
446 59     59   19556  
  59         151  
  59         269  
447              
448             use Mouse;
449 1     1   20 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         3 # ABSTRACT: Exception mechanism for configuration model
460 1 50       11  
461              
462             =pod
463 1         5  
464             =encoding UTF-8
465 1 50       14  
466             =head1 NAME
467              
468             Config::Model::Exception - Exception mechanism for configuration model
469              
470             =head1 VERSION
471              
472             version 2.151
473              
474             =head1 SYNOPSIS
475 1         3  
476             use Config::Model::Exception;
477              
478             # later
479             my $kaboom = 1;
480 59     59   27141 Config::Model::Exception::Model->throw(
  59         135  
  59         281  
481             error => "Went kaboom",
482             object => $self
483 0     0   0 ) if $kaboom;
484              
485             =head1 DESCRIPTION
486              
487 59     59   19668 This module creates exception classes used by L<Config::Model>.
  59         159  
  59         245  
488 59     59   17246  
  59         126  
  59         392  
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   12893  
  59         150  
  59         272  
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   19629 =head1 AUTHOR
  59         143  
  59         233  
514              
515             Dominique Dumont, (ddumont at cpan dot org)
516 1     1   5  
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