File Coverage

blib/lib/DBIx/Class/Carp.pm
Criterion Covered Total %
statement 47 48 97.9
branch 22 22 100.0
condition 15 17 88.2
subroutine 9 10 90.0
pod n/a
total 93 97 95.8


line stmt bran cond sub pod time code
1             package # hide from pause
2             DBIx::Class::Carp;
3              
4 385     410   3620 use strict;
  385         1106  
  385         11184  
5 385     385   1905 use warnings;
  385         1107  
  385         9072  
6              
7             # load Carp early to prevent tickling of the ::Internal stash being
8             # interpreted as "Carp is already loaded" by some braindead loader
9 385     385   2276 use Carp ();
  385         1151  
  385         219964  
10             $Carp::Internal{ (__PACKAGE__) }++;
11              
12             sub __find_caller {
13 3445     3445   60561 my ($skip_pattern, $class) = @_;
14              
15 3445 100 66     95909 my $skip_class_data = $class->_skip_namespace_frames
16             if ($class and $class->can('_skip_namespace_frames'));
17              
18 3445 100       90801 $skip_pattern = qr/$skip_pattern|$skip_class_data/
19             if $skip_class_data;
20              
21 3445         7547 my $fr_num = 1; # skip us and the calling carp*
22              
23 3445         6014 my (@f, $origin);
24 3445         15221 while (@f = caller($fr_num++)) {
25              
26             next if
27 36587 100 100     781609 ( $f[3] eq '(eval)' or $f[3] =~ /::__ANON__$/ );
28              
29             $origin ||= (
30             $f[3] =~ /^ (.+) :: ([^\:]+) $/x
31             and
32 32402 100 100     219268 ! $Carp::Internal{$1}
      100        
33             and
34             #############################
35             # Need a way to parameterize this for Carp::Skip
36             $1 !~ /^(?: DBIx::Class::Storage::BlockRunner | Context::Preserve | Try::Tiny | Class::Accessor::Grouped | Class::C3::Componentised | Module::Runtime )$/x
37             and
38             $2 !~ /^(?: throw_exception | carp | carp_unique | carp_once | dbh_do | txn_do | with_deferred_fk_checks)$/x
39             #############################
40             ) ? $f[3] : undef;
41              
42 32402 100 66     568055 if (
43             $f[0]->can('_skip_namespace_frames')
44             and
45             my $extra_skip = $f[0]->_skip_namespace_frames
46             ) {
47 22239         2079055 $skip_pattern = qr/$skip_pattern|$extra_skip/;
48             }
49              
50 32402 100       310374 last if $f[0] !~ $skip_pattern;
51             }
52              
53 3445 100       15609 my $site = @f # if empty - nothing matched - full stack
54             ? "at $f[1] line $f[2]"
55             : Carp::longmess()
56             ;
57 3445   100     11625 $origin ||= '{UNKNOWN}';
58              
59             return (
60 3445 100       26048 $site,
61             $origin =~ /::/ ? "$origin(): " : "$origin: ", # cargo-cult from Carp::Clan
62             );
63             };
64              
65             my $warn = sub {
66             my ($ln, @warn) = @_;
67             @warn = "Warning: something's wrong" unless @warn;
68              
69             # back-compat with Carp::Clan - a warning ending with \n does
70             # not include caller info
71             warn (
72             @warn,
73             $warn[-1] =~ /\n$/ ? '' : " $ln\n"
74             );
75             };
76              
77             sub import {
78 6284     6284   20860 my (undef, $skip_pattern) = @_;
79 6284         19695 my $into = caller;
80              
81 6284 100       186232 $skip_pattern = $skip_pattern
82             ? qr/ ^ $into $ | $skip_pattern /x
83             : qr/ ^ $into $ /x
84             ;
85              
86 385     385   3231 no strict 'refs';
  385         1089  
  385         119951  
87              
88 6284         44148 *{"${into}::carp"} = sub {
89 185     185   1460 $warn->(
90             __find_caller($skip_pattern, $into),
91             @_
92             );
93 6284         40775 };
94              
95 6284         16888 my $fired = {};
96 6284         33149 *{"${into}::carp_once"} = sub {
97 13 100   13   1438 return if $fired->{$_[0]};
98 9         38 $fired->{$_[0]} = 1;
99              
100 9         35 $warn->(
101             __find_caller($skip_pattern, $into),
102             @_,
103             );
104 6284         27960 };
105              
106 6284         12707 my $seen;
107 6284         196179 *{"${into}::carp_unique"} = sub {
108 66     66   289 my ($ln, $calling) = __find_caller($skip_pattern, $into);
109 66         292 my $msg = join ('', $calling, @_);
110              
111             # unique carping with a hidden caller makes no sense
112 66         227 $msg =~ s/\n+$//;
113              
114 66 100       355 return if $seen->{$ln}{$msg};
115 44         186 $seen->{$ln}{$msg} = 1;
116              
117 44         176 $warn->(
118             $ln,
119             $msg,
120             );
121 6284         29688 };
122             }
123              
124             sub unimport {
125 0     0     die (__PACKAGE__ . " does not implement unimport yet\n");
126             }
127              
128             1;
129              
130             __END__
131              
132             =head1 NAME
133              
134             DBIx::Class::Carp - Provides advanced Carp::Clan-like warning functions for DBIx::Class internals
135              
136             =head1 DESCRIPTION
137              
138             Documentation is lacking on purpose - this an experiment not yet fit for
139             mass consumption. If you use this do not count on any kind of stability,
140             in fact don't even count on this module's continuing existence (it has
141             been noindexed for a reason).
142              
143             In addition to the classic interface:
144              
145             use DBIx::Class::Carp '^DBIx::Class'
146              
147             this module also supports a class-data based way to specify the exclusion
148             regex. A message is only carped from a callsite that matches neither the
149             closed over string, nor the value of L</_skip_namespace_frames> as declared
150             on any callframe already skipped due to the same mechanism. This is to ensure
151             that intermediate callsites can declare their own additional skip-namespaces.
152              
153             =head1 CLASS ATTRIBUTES
154              
155             =head2 _skip_namespace_frames
156              
157             A classdata attribute holding the stringified regex matching callsites that
158             should be skipped by the carp methods below. An empty string C<q{}> is treated
159             like no setting/C<undef> (the distinction is necessary due to semantics of the
160             class data accessors provided by L<Class::Accessor::Grouped>)
161              
162             =head1 EXPORTED FUNCTIONS
163              
164             This module export the following 3 functions. Only warning related C<carp*>
165             is being handled here, for C<croak>-ing you must use
166             L<DBIx::Class::Schema/throw_exception> or L<DBIx::Class::Exception>.
167              
168             =head2 carp
169              
170             Carps message with the file/line of the first callsite not matching
171             L</_skip_namespace_frames> nor the closed-over arguments to
172             C<use DBIx::Class::Carp>.
173              
174             =head2 carp_unique
175              
176             Like L</carp> but warns once for every distinct callsite (subject to the
177             same ruleset as L</carp>).
178              
179             =head2 carp_once
180              
181             Like L</carp> but warns only once for the life of the perl interpreter
182             (regardless of callsite).
183              
184             =head1 FURTHER QUESTIONS?
185              
186             Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
187              
188             =head1 COPYRIGHT AND LICENSE
189              
190             This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
191             by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
192             redistribute it and/or modify it under the same terms as the
193             L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
194              
195             =cut