line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# License: http://creativecommons.org/publicdomain/zero/1.0/ |
2
|
|
|
|
|
|
|
# (CC0 or Public Domain). To the extent possible under law, the author, |
3
|
|
|
|
|
|
|
# Jim Avera (email jim.avera at gmail dot com) has waived all copyright and |
4
|
|
|
|
|
|
|
# related or neighboring rights to this document. Attribution is requested |
5
|
|
|
|
|
|
|
# but not required. |
6
|
4
|
|
|
4
|
|
1131244
|
use strict; use warnings FATAL => 'all'; use utf8; |
|
4
|
|
|
4
|
|
17
|
|
|
4
|
|
|
4
|
|
178
|
|
|
4
|
|
|
|
|
32
|
|
|
4
|
|
|
|
|
17
|
|
|
4
|
|
|
|
|
151
|
|
|
4
|
|
|
|
|
22
|
|
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
32
|
|
7
|
4
|
|
|
4
|
|
140
|
use feature qw(say state lexical_subs current_sub); |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
398
|
|
8
|
4
|
|
|
4
|
|
25
|
no warnings qw(experimental::lexical_subs); |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
338
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
package Spreadsheet::Edit::Log; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# Allow "use <thismodule. VERSION ..." in development sandbox to not bomb |
13
|
4
|
|
|
4
|
|
36
|
{ no strict 'refs'; ${__PACKAGE__."::VER"."SION"} = 1999.999; } |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
468
|
|
14
|
|
|
|
|
|
|
our $VERSION = '1000.006'; # VERSION from Dist::Zilla::Plugin::OurPkgVersion |
15
|
|
|
|
|
|
|
our $DATE = '2023-09-06'; # DATE from Dist::Zilla::Plugin::OurDate |
16
|
|
|
|
|
|
|
|
17
|
4
|
|
|
4
|
|
50
|
use Carp; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
300
|
|
18
|
|
|
|
|
|
|
|
19
|
4
|
|
|
4
|
|
27
|
use Exporter 5.57 (); |
|
4
|
|
|
|
|
72
|
|
|
4
|
|
|
|
|
1740
|
|
20
|
|
|
|
|
|
|
our @EXPORT = qw/fmt_call log_call fmt_methcall log_methcall |
21
|
|
|
|
|
|
|
nearest_call abbrev_call_fn_ln_subname/; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub _btwTN($$@) { |
24
|
5
|
|
|
5
|
|
76
|
my $pfx=shift; my $N=shift; local $_ = join("",@_); |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
18
|
|
25
|
5
|
|
|
|
|
13
|
s/\n\z//s; |
26
|
5
|
|
|
|
|
63
|
my ($package, $path, $lno) = caller($N); |
27
|
5
|
|
|
|
|
43
|
(my $fname = $path) =~ s/.*[\\\/]//; |
28
|
5
|
|
|
|
|
12
|
(my $pkg = $package) =~ s/.*:://; |
29
|
5
|
|
|
|
|
328
|
my $s = eval "\"${pfx}\""; |
30
|
5
|
50
|
|
|
|
33
|
confess "ERROR IN btw prefix '$pfx': $@" if $@; |
31
|
5
|
|
|
|
|
42
|
printf "%s %s\n", $s, $_; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub _genbtw($$) { |
35
|
11
|
|
|
11
|
|
65
|
my ($pkg, $pfx) = @_; |
36
|
11
|
|
50
|
2
|
|
57
|
my $btw = eval{ sub(@) { unshift @_,$pfx,0; goto &_btwTN } } // die $@; |
|
11
|
|
|
|
|
88
|
|
|
2
|
|
|
|
|
2114
|
|
|
2
|
|
|
|
|
9
|
|
37
|
4
|
|
|
4
|
|
31
|
no strict 'refs'; |
|
4
|
|
|
|
|
12
|
|
|
4
|
|
|
|
|
756
|
|
38
|
11
|
|
|
|
|
33
|
*{"${pkg}::btw"} = \&$btw; |
|
11
|
|
|
|
|
76
|
|
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
sub _genbtwN($$) { |
41
|
4
|
|
|
4
|
|
16
|
my ($pkg, $pfx) = @_; |
42
|
4
|
|
50
|
3
|
|
8
|
my $btwN = eval{ sub($@) { unshift @_,$pfx; goto &_btwTN } } // die $@; |
|
4
|
|
|
|
|
40
|
|
|
3
|
|
|
|
|
36
|
|
|
3
|
|
|
|
|
11
|
|
43
|
4
|
|
|
4
|
|
31
|
no strict 'refs'; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
383
|
|
44
|
4
|
|
|
|
|
10
|
*{"${pkg}::btwN"} = \&$btwN; |
|
4
|
|
|
|
|
1057
|
|
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
BEGIN { |
47
|
4
|
|
|
4
|
|
40
|
_genbtw(__PACKAGE__,'$lno:'); |
48
|
4
|
|
|
|
|
14
|
_genbtwN(__PACKAGE__,'$lno:'); |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub import { |
52
|
9
|
|
|
9
|
|
2927
|
my $class = shift; |
53
|
9
|
|
|
|
|
23
|
my $pkg = caller; |
54
|
9
|
|
|
|
|
19
|
my @remaining_args; |
55
|
9
|
|
|
|
|
24
|
foreach(@_) { |
56
|
44
|
100
|
|
|
|
156
|
if (/:btw=(.*)/) { _genbtw($pkg,$1) } |
|
7
|
50
|
|
|
|
34
|
|
57
|
0
|
|
|
|
|
0
|
elsif (/:btwN=(.*)/) { _genbtwN($pkg,$1) } |
58
|
|
|
|
|
|
|
else { |
59
|
37
|
|
|
|
|
66
|
push @remaining_args, $_; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
} |
62
|
9
|
|
|
|
|
39
|
@_ = ($class, @remaining_args); |
63
|
9
|
|
|
|
|
165123
|
goto &Exporter::import |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
our @EXPORT_OK = qw/btw btwN oops/; |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
|
69
|
4
|
|
|
4
|
|
35
|
use Scalar::Util qw/reftype refaddr blessed weaken/; |
|
4
|
|
|
|
|
27
|
|
|
4
|
|
|
|
|
305
|
|
70
|
4
|
|
|
4
|
|
27
|
use List::Util qw/first any all/; |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
363
|
|
71
|
4
|
|
|
4
|
|
30
|
use File::Basename qw/dirname basename/; |
|
4
|
|
|
|
|
27
|
|
|
4
|
|
|
|
|
683
|
|
72
|
|
|
|
|
|
|
|
73
|
0
|
|
|
0
|
1
|
0
|
sub oops(@) { @_=("\n".(caller)." oops:\n",@_,"\n"); goto &Carp::confess } |
|
0
|
|
|
|
|
0
|
|
74
|
|
|
|
|
|
|
|
75
|
4
|
|
|
4
|
|
39
|
use Data::Dumper::Interp qw/dvis vis visq avis hvis visnew addrvis u/; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
36
|
|
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
my %backup_defaults = ( |
78
|
|
|
|
|
|
|
logdest => \*STDERR, |
79
|
|
|
|
|
|
|
is_public_api => sub{ $_[1][3] =~ /(?:::|^)[a-z][^:]*$/ }, |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
#fmt_object => sub{ addrvis($_[1]) }, |
82
|
|
|
|
|
|
|
# Just show the address, sans class::name. Note addrvis now wraps it in <...> |
83
|
|
|
|
|
|
|
fmt_object => sub{ addrvis(refaddr($_[1])) }, |
84
|
|
|
|
|
|
|
); |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# Return ref to hash of effective options (READ-ONLY). |
87
|
|
|
|
|
|
|
# If the first argument is a hashref it is shifted off and |
88
|
|
|
|
|
|
|
# used as options which override defaults. |
89
|
|
|
|
|
|
|
sub _getoptions { |
90
|
14
|
|
|
14
|
|
33
|
my $pkg; |
91
|
14
|
|
33
|
|
|
26
|
my $N=1; while (($pkg=caller($N)//oops) eq __PACKAGE__) { ++$N } |
|
14
|
|
|
|
|
82
|
|
|
0
|
|
|
|
|
0
|
|
92
|
4
|
|
|
4
|
|
2334
|
no strict 'refs'; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
2274
|
|
93
|
14
|
|
|
|
|
23
|
my $r = *{$pkg."::SpreadsheetEdit_Log_Options"}{HASH}; |
|
14
|
|
|
|
|
80
|
|
94
|
|
|
|
|
|
|
+{ %backup_defaults, |
95
|
|
|
|
|
|
|
(defined($r) ? %$r : ()), |
96
|
14
|
100
|
100
|
|
|
132
|
((@_ && ref($_[0]) eq 'HASH') ? %{shift(@_)} : ()) |
|
11
|
100
|
|
|
|
60
|
|
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# Format a usually-comma-separated list sans enclosing brackets. |
101
|
|
|
|
|
|
|
# |
102
|
|
|
|
|
|
|
# Items are formatted by vis() and thus strings will be "quoted", except that |
103
|
|
|
|
|
|
|
# \"ref to string" inserts the string value without quotes and suppresses |
104
|
|
|
|
|
|
|
# adjacent commas (for inserting fixed annotations). |
105
|
|
|
|
|
|
|
# Object refs in the top two levels are not visualized. |
106
|
|
|
|
|
|
|
# |
107
|
|
|
|
|
|
|
# If the arguments are recognized as a sequence then they are formatted as |
108
|
|
|
|
|
|
|
# Arg1..ArgN instead of Arg1,Arg2,...,ArgN. |
109
|
|
|
|
|
|
|
# |
110
|
|
|
|
|
|
|
sub _fmt_list($) { |
111
|
11
|
100
|
|
11
|
|
44
|
my @items = ref($_[0]) eq 'ARRAY' ? @{$_[0]} : ($_[0]); |
|
7
|
|
|
|
|
21
|
|
112
|
11
|
50
|
|
|
|
22
|
oops if wantarray; |
113
|
11
|
100
|
|
|
|
35
|
if (my $is_sequential = (@items >= 4)) { |
114
|
1
|
|
|
|
|
3
|
my $seq; |
115
|
1
|
|
|
|
|
3
|
foreach(@items) { |
116
|
1
|
50
|
33
|
|
|
22
|
$is_sequential=0,last |
|
|
|
0
|
|
|
|
|
|
|
|
33
|
|
|
|
|
117
|
|
|
|
|
|
|
unless defined($_) && /^\w+$/ && ($seq//=$items[0])++ eq $_ |
118
|
|
|
|
|
|
|
} |
119
|
1
|
50
|
|
|
|
5
|
if ($is_sequential) { |
120
|
0
|
|
|
|
|
0
|
return visq($items[0])."..".visq($items[-1]) |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
join "", map{ |
124
|
11
|
|
|
|
|
26
|
my $item = $items[$_]; |
|
21
|
|
|
|
|
18801
|
|
125
|
|
|
|
|
|
|
($_ > 0 && (ref($items[$_-1]) ne 'SCALAR' || ${$items[$_-1]} eq "") |
126
|
|
|
|
|
|
|
&& (ref($item) ne 'SCALAR' || ${$item} eq "") |
127
|
|
|
|
|
|
|
? "," : "" |
128
|
|
|
|
|
|
|
) |
129
|
21
|
100
|
100
|
|
|
147
|
.(ref($item) eq 'SCALAR' ? ${$item} : visnew->Pad(" ")->vis($item) |
|
5
|
100
|
|
|
|
15
|
|
130
|
|
|
|
|
|
|
) |
131
|
|
|
|
|
|
|
} 0..$#items; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
## test |
134
|
|
|
|
|
|
|
#foreach ([], [1..5], ['f'..'i'], ['a'], ['a','x']) { |
135
|
|
|
|
|
|
|
# my @items = @$_; |
136
|
|
|
|
|
|
|
# warn avis(@items)," -> ", scalar(_fmt_list(@items)), "\n"; |
137
|
|
|
|
|
|
|
# @items = (\"-FIRST-", @items); |
138
|
|
|
|
|
|
|
# warn avis(@items)," -> ", scalar(_fmt_list(@items)), "\n"; |
139
|
|
|
|
|
|
|
# splice @items, int(scalar(@items)/2),0, \"-ANN-" if @items >= 1; |
140
|
|
|
|
|
|
|
# warn avis(@items)," -> ", scalar(_fmt_list(@items)), "\n"; |
141
|
|
|
|
|
|
|
# push @items, \"-LAST-"; |
142
|
|
|
|
|
|
|
# warn avis(@items)," -> ", scalar(_fmt_list(@items)), "\n"; |
143
|
|
|
|
|
|
|
#} |
144
|
|
|
|
|
|
|
#die "TEX"; |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
##################################################################### |
147
|
|
|
|
|
|
|
# Locate the nearest call to a public sub in the call stack. |
148
|
|
|
|
|
|
|
# |
149
|
|
|
|
|
|
|
# A callback decides what might be a "public" entrypoint (default: |
150
|
|
|
|
|
|
|
# any sub named starting with [a-z]). |
151
|
|
|
|
|
|
|
# |
152
|
|
|
|
|
|
|
# RETURNS |
153
|
|
|
|
|
|
|
# ([frame], [called args]) in array context |
154
|
|
|
|
|
|
|
# [frame] in scalar context |
155
|
|
|
|
|
|
|
# |
156
|
|
|
|
|
|
|
# "frame" means caller(n) results: |
157
|
|
|
|
|
|
|
# 0 1 2 3 |
158
|
|
|
|
|
|
|
# package filename linenum subname ... |
159
|
|
|
|
|
|
|
# |
160
|
4
|
|
33
|
|
|
950
|
use constant _CALLER_OVERRIDE_CHECK_OK => |
161
|
|
|
|
|
|
|
(defined(&Carp::CALLER_OVERRIDE_CHECK_OK) |
162
|
4
|
|
|
4
|
|
38
|
&& &Carp::CALLER_OVERRIDE_CHECK_OK); |
|
4
|
|
|
|
|
9
|
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub _nearest_call($$) { |
165
|
14
|
|
|
14
|
|
30
|
my ($state, $opts) = @_; |
166
|
14
|
|
|
|
|
23
|
my $callback = $opts->{is_public_api}; |
167
|
14
|
|
|
|
|
22
|
for (my $lvl=1 ; ; ++$lvl) { |
168
|
66
|
|
|
|
|
385
|
my @frame = caller($lvl); |
169
|
66
|
50
|
|
|
|
143
|
confess "No public-API sub found" unless defined($frame[0]); |
170
|
66
|
|
|
|
|
80
|
my $calling_pkg = $frame[0]; |
171
|
66
|
50
|
|
|
|
285
|
my ($called_pkg) = ($frame[3] =~ /^(.*)::/) or next; # eval? |
172
|
4
|
|
|
4
|
|
32
|
no strict 'refs'; |
|
4
|
|
|
|
|
12
|
|
|
4
|
|
|
|
|
4941
|
|
173
|
|
|
|
|
|
|
#if ((!any{ $_ eq $called_pkg } (__PACKAGE__,$calling_pkg,@{$calling_pkg."::CARP_NOT"})) |
174
|
66
|
100
|
100
|
|
|
216
|
if ($called_pkg ne __PACKAGE__ && $callback->($state, \@frame)) { |
175
|
14
|
|
|
|
|
67
|
return \@frame; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
sub nearest_call(;$) { |
180
|
1
|
|
|
1
|
1
|
3372
|
my $opts = &_getoptions; |
181
|
1
|
|
|
|
|
4
|
_nearest_call({}, $opts); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub _abbrev_call_fn_ln_subname($$) { |
185
|
13
|
|
|
13
|
|
31
|
my @results = @{ &_nearest_call(@_) }[1,2,3]; # (fn, lno, subname) |
|
13
|
|
|
|
|
35
|
|
186
|
13
|
|
|
|
|
298
|
$results[0] = basename $results[0]; # filename |
187
|
13
|
|
|
|
|
72
|
$results[2] =~ s/.*:://; # subname |
188
|
|
|
|
|
|
|
@results |
189
|
13
|
|
|
|
|
45
|
} |
190
|
|
|
|
|
|
|
sub abbrev_call_fn_ln_subname(;$) { |
191
|
1
|
|
|
1
|
1
|
8
|
my $opts = &_getoptions; |
192
|
1
|
|
|
|
|
5
|
_abbrev_call_fn_ln_subname({},$opts); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub _fmt_call($;$$) { |
196
|
|
|
|
|
|
|
my $opts = shift; |
197
|
|
|
|
|
|
|
confess "Expecting {optOPTIONS} INPUTS optRESULTS" unless @_==1 or @_==2; |
198
|
|
|
|
|
|
|
my ($inputs, $retvals) = @_; |
199
|
|
|
|
|
|
|
#warn dvis '### $opts\n $inputs\n $retvals'; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
my $state = {}; |
202
|
|
|
|
|
|
|
my ($fn, $lno, $subname) = _abbrev_call_fn_ln_subname($state, $opts); |
203
|
|
|
|
|
|
|
my $msg = ">[$fn:$lno] "; |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
my sub myequal($$) { |
206
|
|
|
|
|
|
|
if ((my $r1 = refaddr($_[0])) && (my $r2 = refaddr($_[1]))) { |
207
|
|
|
|
|
|
|
return $r1 == $r2; # same object |
208
|
|
|
|
|
|
|
} else { |
209
|
|
|
|
|
|
|
return u($_[0]) eq u($_[1]); # string reps eq, or both undef |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
state $prev_obj; |
214
|
|
|
|
|
|
|
if (defined(my $obj = $opts->{self})) { |
215
|
|
|
|
|
|
|
# N.B. "self" might not be a ref, or might be unblessed |
216
|
|
|
|
|
|
|
if (! myequal($obj, $prev_obj)) { |
217
|
|
|
|
|
|
|
# Show the obj address in only the first of a sequence of calls |
218
|
|
|
|
|
|
|
# with the same object. |
219
|
|
|
|
|
|
|
my $rep = $opts->{fmt_object}->($state, $obj); |
220
|
|
|
|
|
|
|
if (defined($rep) && refaddr($rep)) { |
221
|
|
|
|
|
|
|
$msg .= _fmt_list($rep); # Data::Dumper::Interp |
222
|
|
|
|
|
|
|
} else { |
223
|
|
|
|
|
|
|
$msg .= $rep; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
$prev_obj = $obj; |
226
|
|
|
|
|
|
|
weaken($prev_obj); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
$msg .= "."; |
229
|
|
|
|
|
|
|
} else { |
230
|
|
|
|
|
|
|
$prev_obj = undef; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
$msg .= $subname; |
234
|
|
|
|
|
|
|
$msg .= " "._fmt_list($inputs) if @$inputs; |
235
|
|
|
|
|
|
|
oops "terminal newline in last input item" if substr($msg,-1) eq "\n"; |
236
|
|
|
|
|
|
|
if (defined $retvals) { |
237
|
|
|
|
|
|
|
$msg .= "()" if @$inputs == 0; |
238
|
|
|
|
|
|
|
$msg .= " ==> "; |
239
|
|
|
|
|
|
|
$msg .= _fmt_list($retvals); |
240
|
|
|
|
|
|
|
oops "terminal newline in last retvals item" if substr($msg,-1) eq "\n"; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
$msg."\n" |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
sub fmt_call { |
245
|
0
|
|
|
0
|
1
|
0
|
my $opts = &_getoptions; |
246
|
0
|
|
|
|
|
0
|
&_fmt_call($opts, @_); |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub log_call { |
250
|
12
|
|
|
12
|
1
|
72892
|
my $opts = &_getoptions; |
251
|
12
|
|
|
|
|
32
|
my $fh = $opts->{logdest}; |
252
|
12
|
|
|
|
|
76
|
print $fh &_fmt_call($opts, @_); |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub fmt_methcall($;@) { |
256
|
0
|
|
|
0
|
1
|
|
my $opts = &_getoptions; |
257
|
0
|
|
0
|
|
|
|
my $obj = shift // croak "Missing 'self' argument\n"; |
258
|
0
|
|
|
|
|
|
$opts->{self} = $obj; |
259
|
0
|
|
|
|
|
|
&_fmt_call($opts, @_); |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub log_methcall { |
263
|
0
|
|
|
0
|
1
|
|
my $opts = &_getoptions; |
264
|
0
|
|
|
|
|
|
my $fh = $opts->{logdest}; |
265
|
0
|
|
|
|
|
|
print $fh &fmt_methcall($opts, @_); |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
1; |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
__END__ |
271
|
|
|
|
|
|
|
=pod |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head1 NAME |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
Spreadsheet::Edit::Log - log method/function calls, args, and return values |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head1 SYNOPSIS |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
use Spreadsheet::Edit::Log qw/:DEFAULT btw oops/; |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub public_method { |
282
|
|
|
|
|
|
|
my $self = shift; |
283
|
|
|
|
|
|
|
$self->_internal_method(@_); |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
sub _internal_method { |
286
|
|
|
|
|
|
|
my $self = shift; |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
oops "zort not set!" unless defined $self->{zort}; |
289
|
|
|
|
|
|
|
btw "By the way, the zort is $self->{zort}" if $self->{debug}; |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
my @result = (42, $_[0]*1000); |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
log_call \@_, [\"Here you go:", @result] if $self->{verbose}; |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
@result; |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
... |
298
|
|
|
|
|
|
|
$obj->public_method(100); |
299
|
|
|
|
|
|
|
# file::lineno public_method 100 ==> Here you go:42,100000 |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=head1 DESCRIPTION |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
(This is generic, no longer specific to Spreadsheet::Edit. Someday it might |
304
|
|
|
|
|
|
|
be published as a stand-alone distribution rather than packaged with |
305
|
|
|
|
|
|
|
Spreadsheet-Edit.) |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
This provides possibly-overkill convenience for "verbose logging" and/or debug |
308
|
|
|
|
|
|
|
tracing of subroutine calls. |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
The resulting message string includes the location of the |
311
|
|
|
|
|
|
|
user's call, the name of the public function or method called, |
312
|
|
|
|
|
|
|
and a representation of the inputs and outputs. |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
The "public" function/method name shown is not necessarily the immediate caller of the logging function. |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head2 log_call {OPTIONS}, [INPUTS], [RESULTS] |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Prints the result of calling C<fmt_call> with the same arguments. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
The message is written to STDERR unless |
321
|
|
|
|
|
|
|
C<< logdest => FILEHANDLE >> is included in I<OPTIONS>. |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=head2 $msgstring = fmt_call {OPTIONS}, [INPUTS], [RESULTS] |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
{OPTIONS} and [RESULTS] are optional, i.e. may be entirely omitted. |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
A message string is composed and returned. The general form is: |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
File:linenum funcname input,items,... ==> output,items,...\n |
330
|
|
|
|
|
|
|
or |
331
|
|
|
|
|
|
|
File:linenum Obj<address>->methname input,items,... ==> output,items,...\n |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
C<[INPUTS]> and C<[RESULTS]> are each a ref to an array of items (or |
334
|
|
|
|
|
|
|
a single non-aref item), used to form comma-separated lists. |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
Each item is formatted similar to I<Data::Dumper>, i.e. strings are "quoted" |
337
|
|
|
|
|
|
|
and complex structures serialized; printable Unicode characters are shown as |
338
|
|
|
|
|
|
|
themselves (rather than hex escapes) |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
... with two exceptions: |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=over |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=item 1. |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
If an item is a reference to a string then the string is inserted |
347
|
|
|
|
|
|
|
as-is (unquoted), |
348
|
|
|
|
|
|
|
and unless the string is empty, adjacent commas are suppressed. |
349
|
|
|
|
|
|
|
This allows pasting arbitrary text between values. |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=item 2. |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
If an item is an object (blessed reference) then only it's type and |
354
|
|
|
|
|
|
|
abbreviated address are shown, unless overridden via |
355
|
|
|
|
|
|
|
the C<fmt_object> option described below. |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=back |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
B<{OPTIONS}> |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
(See "Default OPTIONS" below to specify most of these statically) |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=over |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=item self =E<gt> objref |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
If your sub is a method, your can pass C<self =E<gt> $self> and |
368
|
|
|
|
|
|
|
the the invocant will be displayed separately before the method name. |
369
|
|
|
|
|
|
|
To reduce clutter, the invocant is |
370
|
|
|
|
|
|
|
displayed for only the first of a series of consecutive calls with the |
371
|
|
|
|
|
|
|
same C<self> value. |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=item fmt_object =E<gt> CODE |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
Format a reference to a blessed thing, |
376
|
|
|
|
|
|
|
or the value of the C<self> option (if passed) whether blessed or not. |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
The sub is called with args ($state, $thing). It should return |
379
|
|
|
|
|
|
|
either C<$thing> or an alternative representation string. By default, |
380
|
|
|
|
|
|
|
the type/classname is shown and an abbreviated address (see C<addrvis> |
381
|
|
|
|
|
|
|
in L<Data::Dumper::Interp>). |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
C<$state> is a ref to a hash where you can store anything you want; it persists |
384
|
|
|
|
|
|
|
only during the current C<fmt_call> invocation. |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
=item is_public_api =E<gt> CODE |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
Recognize a public entry-point in the call stack. |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
The sub is called repeatedly with |
391
|
|
|
|
|
|
|
arguments S<< C<($state, [package,file,line,subname,...])>. >> |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
The second argument contains results from C<caller(N)>. |
394
|
|
|
|
|
|
|
Your sub should return True if the frame represents the call to be described |
395
|
|
|
|
|
|
|
in the message. |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
The default callback is S<<< C<sub{ $_[1][3] =~ /(?:::|^)[a-z][^:]*$/ }> >>>, |
398
|
|
|
|
|
|
|
which looks for any sub named with an initial lower-case letter; |
399
|
|
|
|
|
|
|
in other words, it assumes that internal subs start with an underscore |
400
|
|
|
|
|
|
|
or capital letter (such as for constants). |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
=back |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=head2 $string = fmt_methcall {OPTIONS}, $self, [INPUTS], [RESULTS] |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
A short-hand for |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
$string = fmt_call {OPTIONS, self => $self}, [INPUTS], [RESULTS] |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
=head2 log_methcall $self, [INPUTS], [RESULTS] |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=head2 log_methcall {OPTIONS}, $self, [INPUTS], [RESULTS] |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
A short-hand for |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
log_call {OPTIONS, self => $self}, [INPUTS], [RESULTS] |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
Usually {OPTIONS} can be omitted for a more succinct form. |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=head2 $frame = nearest_call {OPTIONS}; |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
Locate the call frame for the "public" interface most recently called. |
423
|
|
|
|
|
|
|
This accesses the internal logic used by C<fmt_call>, and uses the |
424
|
|
|
|
|
|
|
same C<is_public_api> callback. |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
The result is a reference to the items returned by C<caller(N)> which |
427
|
|
|
|
|
|
|
represent the call to be traced. |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
{OPTIONS} may be omitted. |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=head2 ($filename, $linenum, $subname) = abbrev_call_fn_ln_subname {OPTIONS}; |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
Returns abbreviated information from C<nearest_call>, possibly ambiguous |
434
|
|
|
|
|
|
|
but usually more friendly to humans: C<$filename> is the I<basename> only |
435
|
|
|
|
|
|
|
and C<$subname> omits the Package:: prefix. |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=head2 Default OPTIONS |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
B<our %SpreadsheetEdit_Log_Options = (...);> in your package |
440
|
|
|
|
|
|
|
will be used to override the built-in defaults (but are still |
441
|
|
|
|
|
|
|
overridden by C<{OPTIONS}> passed in individual calls). |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
=head1 Debug Utilities |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
Z<> |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=head2 btw string,string,... |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head2 btwN numlevels,string,string,... |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
For internal debug messages (not related to the other functions). |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
C<btw> prints a message to STDERR preceeded by "linenum:" |
454
|
|
|
|
|
|
|
giving the line number I<of the call to btw>. |
455
|
|
|
|
|
|
|
A newline is appended to the message unless the last string |
456
|
|
|
|
|
|
|
string already ends with a newline. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
This is like C<warn 'message'> when the message omits a final newline; |
459
|
|
|
|
|
|
|
but with a different presentation. |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
C<btwN> displays the line number of the call <numlevels> earlier |
462
|
|
|
|
|
|
|
in the call stack. |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
Not exported by default. |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
By default messages show only the caller's line number. |
467
|
|
|
|
|
|
|
The special tags B<:btw=PFX> or B<:btwN=PFX> will import a customized function |
468
|
|
|
|
|
|
|
which prefixes messages with the string B<PFX>. This string |
469
|
|
|
|
|
|
|
may contain |
470
|
|
|
|
|
|
|
I<$lno> I<$path> I<$fname> I<$package> or I<$pkg> |
471
|
|
|
|
|
|
|
to interpolate respectively |
472
|
|
|
|
|
|
|
the calling line number, file path, file basename, |
473
|
|
|
|
|
|
|
package name, or S<abbreviated package name (*:: removed).> |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=head2 oops string,string,... |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
Prepends "\n<your package name> oops:\n" to the message and then |
478
|
|
|
|
|
|
|
chains to Carp::confess for backtrace and death. |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
Not exported by default. |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=head1 SEE ALSO |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
L<Data::Dumper::Interp> |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=head1 AUTHOR |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
Jim Avera (jim.avera gmail) |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=head1 LICENSE |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
Public Domain or CC0 |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=for Pod::Coverage oops |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
=cut |
497
|
|
|
|
|
|
|
|