| 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
|
|
|
|
|
|
|
|