line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Variable::Watcher; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
require v5.6.0; |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
59725
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
54
|
|
6
|
1
|
|
|
1
|
|
6
|
use vars qw[$VERSION $AUTOLOAD $REPORT_FH $TRACE $VERBOSE]; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
96
|
|
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
2711
|
use Attribute::Handlers; |
|
1
|
|
|
|
|
13146
|
|
|
1
|
|
|
|
|
7
|
|
9
|
1
|
|
|
1
|
|
40
|
use Carp; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
72
|
|
10
|
1
|
|
|
1
|
|
5
|
use Data::Dumper; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
44
|
|
11
|
1
|
|
|
1
|
|
946
|
use Log::Message private => 1; |
|
1
|
|
|
|
|
24253
|
|
|
1
|
|
|
|
|
9
|
|
12
|
1
|
|
|
1
|
|
259
|
use Params::Check qw[check allow]; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
55
|
|
13
|
|
|
|
|
|
|
|
14
|
1
|
|
|
1
|
|
1056
|
use Tie::Scalar; |
|
1
|
|
|
|
|
661
|
|
|
1
|
|
|
|
|
25
|
|
15
|
1
|
|
|
1
|
|
781
|
use Tie::Array; |
|
1
|
|
|
|
|
1288
|
|
|
1
|
|
|
|
|
36
|
|
16
|
1
|
|
|
1
|
|
1104
|
use Tie::Hash; |
|
1
|
|
|
|
|
1096
|
|
|
1
|
|
|
|
|
144
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
$VERSION = '0.01'; |
19
|
|
|
|
|
|
|
$VERBOSE = 1; |
20
|
|
|
|
|
|
|
$TRACE = 1; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
### file handles to print to |
23
|
|
|
|
|
|
|
local $| = 1; |
24
|
|
|
|
|
|
|
$REPORT_FH = \*STDERR; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
### list of names to use for the variables we're watching |
27
|
|
|
|
|
|
|
my %Names = (); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
### log::message object to store actions in |
30
|
|
|
|
|
|
|
my $Log = new Log::Message; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
### list of mappings of bless classes to tie classes |
33
|
|
|
|
|
|
|
my %Map = ( |
34
|
|
|
|
|
|
|
SCALAR => 'Tie::StdScalar', |
35
|
|
|
|
|
|
|
ARRAY => 'Tie::StdArray', |
36
|
|
|
|
|
|
|
HASH => 'Tie::StdHash', |
37
|
|
|
|
|
|
|
); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
### add ourselves to the callers @INC, so we can use attributes that |
41
|
|
|
|
|
|
|
### that are inherited. |
42
|
|
|
|
|
|
|
sub import { |
43
|
1
|
|
|
1
|
|
8
|
my $self = shift; |
44
|
1
|
|
|
|
|
5
|
my $class = [caller]->[0]; |
45
|
|
|
|
|
|
|
|
46
|
1
|
|
|
1
|
|
8
|
{ no strict 'refs'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
362
|
|
|
1
|
|
|
|
|
2
|
|
47
|
1
|
|
|
|
|
2
|
push @{"${class}::ISA"}, __PACKAGE__; |
|
1
|
|
|
|
|
2544
|
|
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head1 NAME |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
Variable::Watcher -- Keep track of changes on C variables |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=head1 SYNOPSIS |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
### keep track of scalar changes |
58
|
|
|
|
|
|
|
my $scalar : Watch(s) = 1; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
### keep track of array changes |
61
|
|
|
|
|
|
|
my @list : Watch(l) = (1); |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
### keep track of hash changes |
64
|
|
|
|
|
|
|
my %hash : Watch(h) = (1 => 2); |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
### retrieve individual mutations: |
68
|
|
|
|
|
|
|
my @stack = Variable::Watcher->stack; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
### retrieve the mutation as a printable string |
71
|
|
|
|
|
|
|
my $string = Variable::Watcher->stack_as_string; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
### flush the logs of all the mutations so far |
74
|
|
|
|
|
|
|
Variable::Watcher->flush; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
### Set the default reporting filehandle (defaults to STDERR |
77
|
|
|
|
|
|
|
### -- see the C section |
78
|
|
|
|
|
|
|
$Variable::Watcher::REPORT_FH = \*MY_FH; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
### Make Variable::Watcher not print to REPORT_FH when running |
81
|
|
|
|
|
|
|
### You will have to use the stack/stack_as_string method to |
82
|
|
|
|
|
|
|
### retrieve the logs. See the C section |
83
|
|
|
|
|
|
|
$Variable::Watcher::VERBOSE = 0; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=head1 DESCRIPTION |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
C allows you to keep track of mutations on C |
89
|
|
|
|
|
|
|
variables. It will record every mutation you do to a variable that |
90
|
|
|
|
|
|
|
is being Ced. You can retrieve these mutations as a list or |
91
|
|
|
|
|
|
|
as a big printable string, filtered by a regex if you like. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
This is a useful debugging tool when you find your C |
94
|
|
|
|
|
|
|
variables in a state you did not expect. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
See the C section for the limitations of this approach. |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=head1 Attributes |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=head2 my $var : Watch([NAME]) |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
In order to start Cing a variable, you must tag it as being |
103
|
|
|
|
|
|
|
Ced at declaration time. You can optionally give it a name |
104
|
|
|
|
|
|
|
to be used in the logs, rather than it's memory address (this is much |
105
|
|
|
|
|
|
|
recommended). |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
You can do this for perls three basic variable types; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=over 4 |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=item SCALAR |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
To keep track of a scalar, and it's mutations, you could for example, |
114
|
|
|
|
|
|
|
do somethign like this: |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
my $scalar : Watch(s) = 1; |
117
|
|
|
|
|
|
|
$scalar++; |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
The resulting output would be much like this: |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
[Variable::Watcher s -> STORE] Performing 'STORE' on s passing |
123
|
|
|
|
|
|
|
'1' at z.pl line 6 |
124
|
|
|
|
|
|
|
[Variable::Watcher s -> FETCH] Performing 'FETCH' on s at z.pl |
125
|
|
|
|
|
|
|
line 7 |
126
|
|
|
|
|
|
|
[Variable::Watcher s -> STORE] Performing 'STORE' on s passing |
127
|
|
|
|
|
|
|
'2' at z.pl line 7 |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
Showing you when you did the first C, when you retrieved the |
130
|
|
|
|
|
|
|
value (C) and when you stored the increment (C). |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=item ARRAY |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
To keep track of an array, and it's mutation, you could for example, |
135
|
|
|
|
|
|
|
do something like this: |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
my @list : Watch(l) = (1); |
138
|
|
|
|
|
|
|
push @list, 2; |
139
|
|
|
|
|
|
|
pop @list; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
The resulting output would be much like this: |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
[Variable::Watcher l -> CLEAR] Performing 'CLEAR' on l at z2.pl |
144
|
|
|
|
|
|
|
line 6 |
145
|
|
|
|
|
|
|
[Variable::Watcher l -> EXTEND] Performing 'EXTEND' on l |
146
|
|
|
|
|
|
|
passing '1' at z2.pl line 6 |
147
|
|
|
|
|
|
|
[Variable::Watcher l -> STORE] Performing 'STORE' on l passing |
148
|
|
|
|
|
|
|
'0 1' at z2.pl line 6 |
149
|
|
|
|
|
|
|
[Variable::Watcher l -> PUSH] Performing 'PUSH' on l passing |
150
|
|
|
|
|
|
|
'2' at z2.pl line 7 |
151
|
|
|
|
|
|
|
[Variable::Watcher l -> FETCHSIZE] Performing 'FETCHSIZE' on l |
152
|
|
|
|
|
|
|
at z2.pl line 7 |
153
|
|
|
|
|
|
|
[Variable::Watcher l -> POP] Performing 'POP' on l at z2.pl |
154
|
|
|
|
|
|
|
line 8 |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
Showing you that you initialized an empty array (C), and |
157
|
|
|
|
|
|
|
extended it's size (C) to fit your first assignment (C), |
158
|
|
|
|
|
|
|
followed by the C which adds another value to your list. |
159
|
|
|
|
|
|
|
Then we attempt to remove the last value, showing us how perl fetches |
160
|
|
|
|
|
|
|
its size (C) and Cs the last value off. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=item HASH |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
To keep track of a hash, and it's mutation, you could for example, |
165
|
|
|
|
|
|
|
do something like this: |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
my %hash : Watch(h) = (1 => 2); |
168
|
|
|
|
|
|
|
$hash{3} = 4; |
169
|
|
|
|
|
|
|
delete $hash{3}; |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
The resulting output would be much like this: |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
[Variable::Watcher h -> CLEAR] Performing 'CLEAR' on h at z3.pl |
174
|
|
|
|
|
|
|
line 6 |
175
|
|
|
|
|
|
|
[Variable::Watcher h -> STORE] Performing 'STORE' on h passing |
176
|
|
|
|
|
|
|
'1 2' at z3.pl line 6 |
177
|
|
|
|
|
|
|
[Variable::Watcher h -> STORE] Performing 'STORE' on h passing |
178
|
|
|
|
|
|
|
'3 4' at z3.pl line 7 |
179
|
|
|
|
|
|
|
[Variable::Watcher h -> DELETE] Performing 'DELETE' on h |
180
|
|
|
|
|
|
|
passing '3' at z3.pl line 8 |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
Showing you that you initialized an empty hash (C), and |
183
|
|
|
|
|
|
|
Cd it's first key/value pair. Then we C the second |
184
|
|
|
|
|
|
|
key/value pair, followed by a C of the key C<3>. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=cut |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub Watch : ATTR { |
189
|
7
|
|
|
7
|
1
|
19182
|
my ($package, $symbol, $ref, $attr, $data, $phase) = @_; |
190
|
7
|
|
|
|
|
21
|
my $reftype = ref $ref; |
191
|
|
|
|
|
|
|
|
192
|
7
|
|
|
|
|
16
|
my $obj; |
193
|
|
|
|
|
|
|
### do we support this type of ref? |
194
|
7
|
100
|
|
|
|
57
|
unless( $Map{ $reftype } ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
### report from the callers perspective, not from attribute.pm |
197
|
|
|
|
|
|
|
### or attribute::handlers perspective |
198
|
1
|
|
|
|
|
4
|
local $Carp::CarpLevel += 2; |
199
|
|
|
|
|
|
|
|
200
|
1
|
|
|
|
|
278
|
carp("Cannot watch variable of type: '$reftype'" ); |
201
|
1
|
|
|
|
|
55
|
return; |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
### if so, tie it to the appropriate class |
204
|
|
|
|
|
|
|
### note that '$ref' is not the same as '$obj'! |
205
|
|
|
|
|
|
|
} elsif ( $reftype eq 'SCALAR' ) { |
206
|
4
|
|
|
|
|
49
|
tie $$ref, __PACKAGE__ .'::'. $reftype; |
207
|
4
|
|
|
|
|
39
|
$obj = tied $$ref; |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
} elsif ( $reftype eq 'ARRAY' ) { |
210
|
1
|
|
|
|
|
20
|
tie @$ref, __PACKAGE__ .'::'. $reftype; |
211
|
1
|
|
|
|
|
10
|
$obj = tied @$ref; |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
} elsif ( $reftype eq 'HASH' ) { |
214
|
1
|
|
|
|
|
18
|
tie %$ref, __PACKAGE__ .'::'. $reftype; |
215
|
1
|
|
|
|
|
7
|
$obj = tied %$ref; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
### store the name which we will call this variable in the |
219
|
|
|
|
|
|
|
### pretty print output |
220
|
6
|
|
33
|
|
|
50
|
$Names{ $obj } = ($data || "$obj"); |
221
|
|
|
|
|
|
|
|
222
|
6
|
|
|
|
|
19
|
return 1; |
223
|
1
|
|
|
1
|
|
7
|
} |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
12
|
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub AUTOLOAD { |
226
|
455
|
|
|
455
|
|
21498
|
my $self = shift; |
227
|
455
|
|
|
|
|
633
|
my $ref = tied $self; |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
### figure out the method called, and the class we're |
230
|
|
|
|
|
|
|
### blessed into |
231
|
455
|
|
|
|
|
4343
|
my ($class,$method) = $AUTOLOAD =~ /::([^:]+)::([^:]+)$/; |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
### XXX we won't have a name yet at TIEFOO stage, but don't |
234
|
|
|
|
|
|
|
### bother reporting that either |
235
|
455
|
100
|
|
|
|
2149
|
if( my $name = $Names{ $self } ) { |
236
|
449
|
|
|
|
|
1624
|
my $msg = "Performing '$method' on $name"; |
237
|
449
|
100
|
|
|
|
3559
|
$msg .= " passing '@_'" if @_; |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
### skip the call frames that are private to this module |
240
|
449
|
|
|
|
|
609
|
local $Carp::CarpLevel += 1; |
241
|
|
|
|
|
|
|
|
242
|
449
|
|
|
|
|
154597
|
$Log->store( |
243
|
|
|
|
|
|
|
message => Carp::shortmess($msg), |
244
|
|
|
|
|
|
|
tag => __PACKAGE__ . " $name -> $method", |
245
|
|
|
|
|
|
|
level => 'report', |
246
|
|
|
|
|
|
|
extra => [@_] |
247
|
|
|
|
|
|
|
); |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
### get the coderef to the correpsonding function in |
251
|
|
|
|
|
|
|
### the tie class |
252
|
455
|
|
|
|
|
7646
|
my $func = $Map{$class}->can( $method ); |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
### called the tie function, with ourselves as primary |
255
|
|
|
|
|
|
|
### argument, and the rest of the args after that |
256
|
455
|
|
|
|
|
1791
|
$func->($self, @_); |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
### tie packages, which inherit straight from base |
261
|
|
|
|
|
|
|
{ package Variable::Watcher::SCALAR; |
262
|
1
|
|
|
1
|
|
681
|
use base 'Variable::Watcher'; |
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
176
|
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
package Variable::Watcher::ARRAY; |
265
|
1
|
|
|
1
|
|
27
|
use base 'Variable::Watcher'; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
79
|
|
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
package Variable::Watcher::HASH; |
268
|
1
|
|
|
1
|
|
5
|
use base 'Variable::Watcher'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
442
|
|
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=pod |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head1 CLASS METHODS |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=head2 @stack = Variable::Watcher->stack( [name => $name, action => $action] ); |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
Retrieves a list of C objects describing the |
278
|
|
|
|
|
|
|
mutations of the Ced variables. |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
The optional C argument lets you filter based on the name you |
281
|
|
|
|
|
|
|
have given the variables to be Ced. |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
The optional C argument lets you filter on the type of action |
284
|
|
|
|
|
|
|
you want to retrieve (C or C, etc). |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
Refer to the C manpage for details on how to work with |
287
|
|
|
|
|
|
|
C objects. |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=cut |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
### report stack retrieval and manipulation |
292
|
|
|
|
|
|
|
sub stack { |
293
|
8
|
|
|
8
|
1
|
16
|
my $self = shift; |
294
|
8
|
|
|
|
|
23
|
my %hash = @_; |
295
|
|
|
|
|
|
|
|
296
|
8
|
|
|
|
|
15
|
my($name,$action); |
297
|
8
|
|
|
|
|
69
|
my $tmpl = { |
298
|
|
|
|
|
|
|
name => { default => '', store => \$name }, |
299
|
|
|
|
|
|
|
action => { default => '', store => \$action }, |
300
|
|
|
|
|
|
|
}; |
301
|
|
|
|
|
|
|
|
302
|
8
|
50
|
|
|
|
51
|
check( $tmpl, \%hash ) or return; |
303
|
|
|
|
|
|
|
|
304
|
8
|
|
|
|
|
648
|
my @rv; |
305
|
8
|
|
|
|
|
19
|
my $re = __PACKAGE__ . '\s(.+?)\s->\s(.+?)$'; |
306
|
|
|
|
|
|
|
|
307
|
8
|
|
|
|
|
58
|
for my $item ( $Log->retrieve( chrono => 1 ) ) { |
308
|
459
|
|
|
|
|
27146
|
my ($tagname,$tagaction) = $item->tag =~ /$re/; |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
### you want to do name based retrieving? |
311
|
459
|
100
|
|
|
|
6075
|
if( $name ) { |
312
|
8
|
50
|
|
|
|
23
|
next unless allow( $tagname, $name ); |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
### you want to do action based retrieving? |
316
|
451
|
100
|
|
|
|
864
|
if( $action ) { |
317
|
4
|
100
|
|
|
|
13
|
next unless allow( $tagaction, $action); |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
449
|
|
|
|
|
755
|
push @rv, $item; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
8
|
|
|
|
|
446
|
return @rv; |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=head2 $string = Variable::Watcher->stack_as_string( [name => $name, action => $action] ); |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
Returns the mutation log as a printable string, optionally filterd on |
329
|
|
|
|
|
|
|
the criteria as described in the C method. |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=cut |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub stack_as_string { |
334
|
8
|
|
|
8
|
1
|
36669
|
my $class = shift; |
335
|
8
|
|
|
|
|
43
|
my @stack = $class->stack( @_ ); |
336
|
|
|
|
|
|
|
|
337
|
449
|
|
|
|
|
8385
|
return join '', map { |
338
|
8
|
|
|
|
|
46
|
'[' . $_->tag . '] ' . $_->message; |
339
|
|
|
|
|
|
|
} @stack |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=head2 @stack = Variable::Watcher->flush; |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
Flushes the logs of all mutations that have occurred so far. Returns |
345
|
|
|
|
|
|
|
the stack, like the C method would, without filtering. |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=cut |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub flush { |
351
|
5
|
|
|
5
|
1
|
33702
|
return reverse $Log->flush; |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
### the function that pretty prints the actions performed on variables |
355
|
|
|
|
|
|
|
{ package Log::Message::Handlers; |
356
|
1
|
|
|
1
|
|
6
|
use Carp (); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
111
|
|
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub report { |
359
|
449
|
|
|
449
|
0
|
788410
|
my $self = shift; |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
### so you don't want us to print the msg? ### |
362
|
449
|
100
|
|
|
|
2713
|
return unless $Variable::Watcher::VERBOSE; |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
### store the old filehandle, select the one the user wants us |
365
|
|
|
|
|
|
|
### to print to |
366
|
2
|
|
|
|
|
9
|
my $old_fh = select $Variable::Watcher::REPORT_FH; |
367
|
2
|
|
|
|
|
16
|
print '['. $self->tag (). '] ' . $self->message; |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
### restore the old filehandle |
370
|
2
|
|
|
|
|
53
|
select $old_fh; |
371
|
|
|
|
|
|
|
|
372
|
2
|
|
|
|
|
10
|
return; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
1; |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
__END__ |