line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package RapidApp::Util; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ABSTRACT: Misc util and sugar functions for RapidApp |
4
|
|
|
|
|
|
|
|
5
|
6
|
|
|
6
|
|
137000
|
use strict; |
|
6
|
|
|
|
|
30
|
|
|
6
|
|
|
|
|
172
|
|
6
|
6
|
|
|
6
|
|
32
|
use warnings; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
170
|
|
7
|
|
|
|
|
|
|
|
8
|
6
|
|
|
6
|
|
33
|
use Scalar::Util qw(blessed weaken reftype); |
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
363
|
|
9
|
6
|
|
|
6
|
|
2544
|
use Clone qw(clone); |
|
6
|
|
|
|
|
15183
|
|
|
6
|
|
|
|
|
626
|
|
10
|
6
|
|
|
6
|
|
43
|
use Carp qw(carp croak confess cluck longmess shortmess); |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
389
|
|
11
|
6
|
|
|
6
|
|
1414
|
use Try::Tiny; |
|
6
|
|
|
|
|
5073
|
|
|
6
|
|
|
|
|
326
|
|
12
|
6
|
|
|
6
|
|
2081
|
use Time::HiRes qw(gettimeofday tv_interval); |
|
6
|
|
|
|
|
4977
|
|
|
6
|
|
|
|
|
34
|
|
13
|
6
|
|
|
6
|
|
3743
|
use Data::Dumper::Concise qw(Dumper); |
|
6
|
|
|
|
|
29906
|
|
|
6
|
|
|
|
|
421
|
|
14
|
6
|
|
|
6
|
|
3622
|
use Term::ANSIColor qw(:constants); |
|
6
|
|
|
|
|
50462
|
|
|
6
|
|
|
|
|
7518
|
|
15
|
6
|
|
|
|
|
569
|
use RapidApp::JSON::MixedEncoder qw( |
16
|
|
|
|
|
|
|
encode_json decode_json encode_json_utf8 decode_json_utf8 encode_json_ascii decode_json_ascii |
17
|
6
|
|
|
6
|
|
3195
|
); |
|
6
|
|
|
|
|
14
|
|
18
|
|
|
|
|
|
|
|
19
|
6
|
|
|
6
|
|
3248
|
use RapidApp::Util::Hash::Merge qw( merge ); |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
412
|
|
20
|
|
|
|
|
|
|
RapidApp::Util::Hash::Merge::set_behavior( 'RIGHT_PRECEDENT' ); |
21
|
|
|
|
|
|
|
|
22
|
6
|
|
|
6
|
|
4635
|
use Data::Printer; |
|
6
|
|
|
|
|
141348
|
|
|
6
|
|
|
|
|
97
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our $DEBUG_AROUND_COUNT = 0; |
25
|
|
|
|
|
|
|
our $DEBUG_AROUND_CALL_NO = 0; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
BEGIN { |
28
|
6
|
|
|
6
|
|
982
|
use Exporter; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
252
|
|
29
|
6
|
|
|
6
|
|
495
|
use parent 'Exporter'; |
|
6
|
|
|
|
|
296
|
|
|
6
|
|
|
|
|
49
|
|
30
|
|
|
|
|
|
|
|
31
|
6
|
|
|
6
|
|
353
|
use vars qw (@EXPORT_OK %EXPORT_TAGS); |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
611
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# These are *extra* exports which came to us via other packages. Note that |
34
|
|
|
|
|
|
|
# all functions defined directly in the class will also be added to the |
35
|
|
|
|
|
|
|
# @EXPORT_OK and setup with the :all tag (see the end of the file) |
36
|
6
|
|
|
6
|
|
37
|
@EXPORT_OK = qw( |
37
|
|
|
|
|
|
|
blessed weaken reftype |
38
|
|
|
|
|
|
|
clone |
39
|
|
|
|
|
|
|
carp croak confess cluck longmess shortmess |
40
|
|
|
|
|
|
|
try catch finally |
41
|
|
|
|
|
|
|
gettimeofday tv_interval |
42
|
|
|
|
|
|
|
Dumper |
43
|
|
|
|
|
|
|
encode_json decode_json encode_json_utf8 decode_json_utf8 encode_json_ascii decode_json_ascii |
44
|
|
|
|
|
|
|
merge |
45
|
|
|
|
|
|
|
); |
46
|
|
|
|
|
|
|
|
47
|
6
|
|
|
|
|
13
|
push @EXPORT_OK, @{$Term::ANSIColor::EXPORT_TAGS{constants}}; |
|
6
|
|
|
|
|
96
|
|
48
|
|
|
|
|
|
|
|
49
|
6
|
|
|
|
|
155
|
%EXPORT_TAGS = ( |
50
|
|
|
|
|
|
|
all => \@EXPORT_OK |
51
|
|
|
|
|
|
|
); |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
6
|
|
|
6
|
|
2882
|
use RapidApp::Responder::UserError; |
|
6
|
|
|
|
|
24
|
|
|
6
|
|
|
|
|
284
|
|
55
|
6
|
|
|
6
|
|
3652
|
use RapidApp::Responder::CustomPrompt; |
|
6
|
|
|
|
|
25
|
|
|
6
|
|
|
|
|
282
|
|
56
|
6
|
|
|
6
|
|
3601
|
use RapidApp::Responder::InfoStatus; |
|
6
|
|
|
|
|
26
|
|
|
6
|
|
|
|
|
238
|
|
57
|
6
|
|
|
6
|
|
3066
|
use RapidApp::JSONFunc; |
|
6
|
|
|
|
|
27
|
|
|
6
|
|
|
|
|
253
|
|
58
|
6
|
|
|
6
|
|
53
|
use RapidApp::JSON::MixedEncoder; |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
412
|
|
59
|
6
|
|
|
6
|
|
3476
|
use RapidApp::JSON::RawJavascript; |
|
6
|
|
|
|
|
24
|
|
|
6
|
|
|
|
|
238
|
|
60
|
6
|
|
|
6
|
|
3269
|
use RapidApp::JSON::ScriptWithData; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
197
|
|
61
|
|
|
|
|
|
|
|
62
|
6
|
|
|
6
|
|
2454
|
use RapidApp::HTML::RawHtml; |
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
171
|
|
63
|
6
|
|
|
6
|
|
2372
|
use RapidApp::Handler; |
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
244
|
|
64
|
6
|
|
|
6
|
|
56
|
use HTML::Entities; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
409
|
|
65
|
6
|
|
|
6
|
|
3325
|
use RapidApp::RootModule; |
|
6
|
|
|
|
|
27
|
|
|
6
|
|
|
|
|
648
|
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
######################################################################## |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub scream { |
71
|
0
|
|
|
0
|
0
|
0
|
local $_ = caller_data(3); |
72
|
0
|
|
|
|
|
0
|
scream_color(YELLOW . BOLD,@_); |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub scream_color { |
76
|
0
|
|
|
0
|
0
|
0
|
my $color = shift; |
77
|
6
|
|
|
6
|
|
59
|
no warnings 'uninitialized'; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
20930
|
|
78
|
|
|
|
|
|
|
|
79
|
0
|
|
0
|
|
|
0
|
my $maxdepth = $Data::Dumper::Maxdepth || 4; |
80
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Maxdepth = $maxdepth; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
local $_ = caller_data(3) unless ( |
83
|
|
|
|
|
|
|
$_ eq 'no_caller_data' or ( |
84
|
|
|
|
|
|
|
ref($_) eq 'ARRAY' and |
85
|
|
|
|
|
|
|
scalar(@$_) == 3 and |
86
|
|
|
|
|
|
|
ref($_->[0]) eq 'HASH' and |
87
|
|
|
|
|
|
|
defined $_->[0]->{package} |
88
|
|
|
|
|
|
|
) |
89
|
0
|
0
|
0
|
|
|
0
|
); |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
90
|
|
|
|
|
|
|
|
91
|
0
|
|
|
|
|
0
|
my $data = $_[0]; |
92
|
0
|
0
|
|
|
|
0
|
$data = \@_ if (scalar(@_) > 1); |
93
|
0
|
0
|
|
|
|
0
|
$data = Dumper($data) if (ref $data); |
94
|
0
|
0
|
|
|
|
0
|
$data = ' ' . UNDERLINE . 'undef' unless (defined $data); |
95
|
|
|
|
|
|
|
|
96
|
0
|
|
|
|
|
0
|
my $pre = ''; |
97
|
|
|
|
|
|
|
$pre = BOLD . ($_->[2]->{subroutine} ? $_->[2]->{subroutine} . ' ' : '') . |
98
|
0
|
0
|
|
|
|
0
|
'[line ' . $_->[1]->{line} . ']: ' . CLEAR . "\n" unless ($_ eq 'no_caller_data'); |
|
|
0
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
100
|
0
|
|
|
|
|
0
|
print STDERR $pre . $color . $data . CLEAR . "\n"; |
101
|
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
0
|
return @_; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# Takes a list and returns a HashRef. List can be a mixed Hash/List: |
107
|
|
|
|
|
|
|
#( |
108
|
|
|
|
|
|
|
# item1 => { opt1 => 'foo' }, |
109
|
|
|
|
|
|
|
# item2 => { key => 'data', foo => 'blah' }, |
110
|
|
|
|
|
|
|
# 'item3', |
111
|
|
|
|
|
|
|
# 'item4', |
112
|
|
|
|
|
|
|
# item1 => { opt2 => 'foobar', opt3 => 'zippy do da' } |
113
|
|
|
|
|
|
|
#) |
114
|
|
|
|
|
|
|
# Bare items like item3 and item4 become {} in the returned hashref. |
115
|
|
|
|
|
|
|
# Repeated items like item1 and merged |
116
|
|
|
|
|
|
|
# also handles the first arg as a hashref or arrayref |
117
|
|
|
|
|
|
|
sub get_mixed_hash_args { |
118
|
0
|
|
|
0
|
0
|
0
|
my @args = @_; |
119
|
0
|
0
|
|
|
|
0
|
return $args[0] if (ref($args[0]) eq 'HASH'); |
120
|
0
|
0
|
|
|
|
0
|
@args = @{ $args[0] } if (ref($args[0]) eq 'ARRAY'); |
|
0
|
|
|
|
|
0
|
|
121
|
|
|
|
|
|
|
|
122
|
0
|
|
|
|
|
0
|
my $hashref = {}; |
123
|
0
|
|
|
|
|
0
|
my $last; |
124
|
0
|
|
|
|
|
0
|
foreach my $item (@args) { |
125
|
0
|
0
|
|
|
|
0
|
if (ref($item)) { |
126
|
0
|
0
|
0
|
|
|
0
|
die "Error in arguments" unless (ref($item) eq 'HASH' and defined $last and not ref($last)); |
|
|
|
0
|
|
|
|
|
127
|
0
|
|
|
|
|
0
|
$hashref->{$last} = { %{$hashref->{$last}}, %$item }; |
|
0
|
|
|
|
|
0
|
|
128
|
0
|
|
|
|
|
0
|
next; |
129
|
|
|
|
|
|
|
} |
130
|
0
|
|
|
|
|
0
|
$last = $item; |
131
|
0
|
0
|
|
|
|
0
|
$hashref->{$item} = {} unless (defined $hashref->{$item}); |
132
|
|
|
|
|
|
|
} |
133
|
0
|
|
|
|
|
0
|
return $hashref; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# Takes a list and returns a Hash. Like get_mixed_hash_args, but |
138
|
|
|
|
|
|
|
# list order is preserved |
139
|
|
|
|
|
|
|
sub get_mixed_hash_args_ordered { |
140
|
0
|
|
|
0
|
0
|
0
|
my @args = @_; |
141
|
0
|
0
|
|
|
|
0
|
return $args[0] if (ref($args[0]) eq 'HASH'); |
142
|
0
|
0
|
|
|
|
0
|
@args = @{ $args[0] } if (ref($args[0]) eq 'ARRAY'); |
|
0
|
|
|
|
|
0
|
|
143
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
0
|
my $hashref = {}; |
145
|
0
|
|
|
|
|
0
|
my @list = (); |
146
|
0
|
|
|
|
|
0
|
my $last; |
147
|
0
|
|
|
|
|
0
|
foreach my $item (@args) { |
148
|
0
|
0
|
|
|
|
0
|
if (ref($item)) { |
149
|
0
|
0
|
0
|
|
|
0
|
die "Error in arguments" unless (ref($item) eq 'HASH' and defined $last and not ref($last)); |
|
|
|
0
|
|
|
|
|
150
|
0
|
|
|
|
|
0
|
$hashref->{$last} = { %{$hashref->{$last}}, %$item }; |
|
0
|
|
|
|
|
0
|
|
151
|
0
|
|
|
|
|
0
|
push @list, $last, $hashref->{$last}; |
152
|
0
|
|
|
|
|
0
|
next; |
153
|
|
|
|
|
|
|
} |
154
|
0
|
0
|
|
|
|
0
|
$hashref->{$item} = {} unless (defined $hashref->{$item}); |
155
|
0
|
0
|
|
|
|
0
|
push @list,$item,$hashref->{$item} unless (ref $last); |
156
|
0
|
|
|
|
|
0
|
$last = $item; |
157
|
|
|
|
|
|
|
} |
158
|
0
|
|
|
|
|
0
|
return @list; # <-- preserve order |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# returns \0 and \1 as 0 and 1, and returns 0 and 1 as 0 and 1 |
163
|
|
|
|
|
|
|
sub jstrue { |
164
|
2970
|
|
|
2970
|
0
|
5847
|
my $v = shift; |
165
|
2970
|
100
|
66
|
|
|
19025
|
ref($v) && ref($v) eq 'SCALAR' ? $$v : $v; |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# The coderefs supplied here get called immediately after the |
170
|
|
|
|
|
|
|
# _load_root_module method in RapidApp/RapidApp.pm |
171
|
|
|
|
|
|
|
sub rapidapp_add_global_init_coderef { |
172
|
0
|
|
|
0
|
0
|
0
|
foreach my $ref (@_) { |
173
|
0
|
0
|
|
|
|
0
|
ref($ref) eq 'CODE' or die "rapidapp_add_global_init_coderef: argument is not a CodeRef: " . Dumper($ref); |
174
|
0
|
|
|
|
|
0
|
push @RapidApp::RootModule::GLOBAL_INIT_CODEREFS, $ref; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Returns an arrayref of hashes containing standard 'caller' function data |
179
|
|
|
|
|
|
|
# with named properties: |
180
|
|
|
|
|
|
|
sub caller_data { |
181
|
0
|
|
0
|
0
|
0
|
0
|
my $depth = shift || 1; |
182
|
|
|
|
|
|
|
|
183
|
0
|
|
|
|
|
0
|
my @list = (); |
184
|
0
|
|
|
|
|
0
|
for(my $i = 0; $i < $depth; $i++) { |
185
|
0
|
|
|
|
|
0
|
my $h = {}; |
186
|
|
|
|
|
|
|
($h->{package}, $h->{filename}, $h->{line}, $h->{subroutine}, $h->{hasargs}, |
187
|
0
|
|
|
|
|
0
|
$h->{wantarray}, $h->{evaltext}, $h->{is_require}, $h->{hints}, $h->{bitmask}) = caller($i); |
188
|
0
|
0
|
|
|
|
0
|
push @list,$h if($h->{package}); |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
0
|
|
|
|
|
0
|
return \@list; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub caller_data_brief { |
195
|
0
|
|
0
|
0
|
0
|
0
|
my $depth = shift || 1; |
196
|
0
|
|
|
|
|
0
|
my $list = caller_data($depth + 1); |
197
|
0
|
|
|
|
|
0
|
my $regex = shift; |
198
|
|
|
|
|
|
|
|
199
|
0
|
|
|
|
|
0
|
shift @$list; |
200
|
0
|
|
|
|
|
0
|
shift @$list; |
201
|
|
|
|
|
|
|
|
202
|
0
|
|
|
|
|
0
|
my @inc_parms = qw(subroutine line filename); |
203
|
|
|
|
|
|
|
|
204
|
0
|
|
|
|
|
0
|
my %inc = map { $_ => 1 } @inc_parms; |
|
0
|
|
|
|
|
0
|
|
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
0
|
my @new = (); |
207
|
0
|
|
|
|
|
0
|
my $seq = 0; |
208
|
0
|
|
|
|
|
0
|
foreach my $item (@$list) { |
209
|
0
|
0
|
0
|
|
|
0
|
if($regex and ! eval('$item->{subroutine} =~ /' . $regex . '/')) { |
210
|
0
|
|
|
|
|
0
|
$seq++; |
211
|
0
|
|
|
|
|
0
|
next; |
212
|
|
|
|
|
|
|
} |
213
|
0
|
0
|
|
|
|
0
|
push @new, ' . ' x $seq if ($seq); |
214
|
0
|
|
|
|
|
0
|
$seq = 0; |
215
|
0
|
|
|
|
|
0
|
push @new, { map { $_ => $item->{$_} } grep { $inc{$_} } keys %$item }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
0
|
|
|
|
|
0
|
return \@new; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# TODO: replace this with uniq from List::Utils |
223
|
|
|
|
|
|
|
# Returns a list with duplicates removed. If passed a single arrayref, duplicates are |
224
|
|
|
|
|
|
|
# removed from the arrayref in place, and the new list (contents) are returned. |
225
|
|
|
|
|
|
|
sub uniq { |
226
|
10027
|
|
|
10027
|
0
|
18288
|
my %seen = (); |
227
|
10027
|
50
|
100
|
|
|
37359
|
return grep { !$seen{ defined $_ ? $_ : '___!undef!___'}++ } @_ unless (@_ == 1 and ref($_[0]) eq 'ARRAY'); |
|
22305
|
100
|
|
|
|
140927
|
|
228
|
184
|
50
|
|
|
|
376
|
return () unless (@{$_[0]} > 0); |
|
184
|
|
|
|
|
589
|
|
229
|
|
|
|
|
|
|
# we add the first element to the end of the arg list to prevetn deep recursion in the |
230
|
|
|
|
|
|
|
# case of nested single element arrayrefs |
231
|
184
|
|
|
|
|
376
|
@{$_[0]} = uniq(@{$_[0]},$_[0]->[0]); |
|
184
|
|
|
|
|
645
|
|
|
184
|
|
|
|
|
773
|
|
232
|
184
|
|
|
|
|
373
|
return @{$_[0]}; |
|
184
|
|
|
|
|
462
|
|
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub deref { |
236
|
0
|
|
|
0
|
0
|
0
|
my $ref = shift; |
237
|
0
|
|
0
|
|
|
0
|
my $type = ref $ref || return $ref,@_; |
238
|
0
|
0
|
|
|
|
0
|
die 'deref(): more than 1 argument not supported' if (@_ > 0); |
239
|
0
|
0
|
|
|
|
0
|
return $$ref if ($type eq 'SCALAR'); |
240
|
0
|
0
|
|
|
|
0
|
return @$ref if ($type eq 'ARRAY'); |
241
|
0
|
0
|
|
|
|
0
|
return %$ref if ($type eq 'HASH'); |
242
|
0
|
|
|
|
|
0
|
die "deref(): invalid ref type '$type' - supported types: SCALAR, ARRAY and HASH"; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# Generic function returns a short display string of a supplied value/values |
246
|
|
|
|
|
|
|
# This is like a lite version of Dumper meant more for single values |
247
|
|
|
|
|
|
|
# Accepts optional CodeRef as first argument for custom handling, for example, |
248
|
|
|
|
|
|
|
# this would allow you to use Dumper instead for all ref values: |
249
|
|
|
|
|
|
|
# print disp(sub{ ref $_ ? Dumper($_) : undef },$_) for (@vals); |
250
|
|
|
|
|
|
|
sub disp { |
251
|
0
|
0
|
|
0
|
0
|
0
|
my $recurse = (caller(1))[3] eq __PACKAGE__ . '::disp' ? 1 : 0; #<-- true if called by ourself |
252
|
|
|
|
|
|
|
|
253
|
0
|
0
|
|
|
|
0
|
local $_{code} = $recurse ? $_{code} : undef; |
254
|
0
|
0
|
0
|
|
|
0
|
$_{code} = shift if(ref($_[0]) eq 'CODE' && @_>1 && $recurse == 0); |
|
|
|
0
|
|
|
|
|
255
|
0
|
0
|
|
|
|
0
|
if($_{code}) { |
256
|
0
|
|
|
|
|
0
|
local $_ = $_[0]; |
257
|
0
|
|
|
|
|
0
|
my $cust = $_{code}->(@_); |
258
|
0
|
0
|
|
|
|
0
|
return $cust if (defined $cust); |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
0
|
0
|
|
|
|
0
|
return join(',',map {disp($_)} @_) if(@_>1); |
|
0
|
|
|
|
|
0
|
|
262
|
0
|
|
|
|
|
0
|
my $val = shift; |
263
|
0
|
0
|
|
|
|
0
|
return 'undef' unless (defined $val); |
264
|
0
|
0
|
|
|
|
0
|
if(ref $val) { |
265
|
0
|
0
|
|
|
|
0
|
return '[' . disp(@$val) . ']' if (ref($val) eq 'ARRAY'); |
266
|
0
|
0
|
|
|
|
0
|
return '\\' . disp($$val) if (ref($val) eq 'SCALAR'); |
267
|
0
|
0
|
|
|
|
0
|
return '{ ' . join(',',map { $_ . ' => ' . disp($val->{$_}) } keys %$val) . ' }' if (ref($val) eq 'HASH'); |
|
0
|
|
|
|
|
0
|
|
268
|
0
|
|
|
|
|
0
|
return "$val" #<-- generic fall-back for other references |
269
|
|
|
|
|
|
|
} |
270
|
0
|
|
|
|
|
0
|
return "'" . $val . "'"; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub print_trunc($$) { |
275
|
6
|
|
|
6
|
0
|
14
|
my $max_length = shift; |
276
|
6
|
|
|
|
|
11
|
my $str = shift; |
277
|
|
|
|
|
|
|
|
278
|
6
|
50
|
33
|
|
|
55
|
die "Invalid max length '$max_length'" unless ( |
|
|
|
33
|
|
|
|
|
279
|
|
|
|
|
|
|
defined $max_length && |
280
|
|
|
|
|
|
|
$max_length =~ /^\d+$/ && |
281
|
|
|
|
|
|
|
$max_length > 0 |
282
|
|
|
|
|
|
|
); |
283
|
|
|
|
|
|
|
|
284
|
6
|
100
|
|
|
|
26
|
return 'undef' unless (defined $str); |
285
|
3
|
50
|
|
|
|
14
|
if (ref $str) { |
286
|
0
|
|
|
|
|
0
|
$str = disp($str); |
287
|
0
|
|
|
|
|
0
|
$str =~ s/^\'//; |
288
|
0
|
|
|
|
|
0
|
$str =~ s/\'$//; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# escape single quotes: |
292
|
3
|
|
|
|
|
10
|
$str =~ s/'/\\'/g; |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# convert tabs: |
295
|
3
|
|
|
|
|
10
|
$str =~ s/\t/ /g; |
296
|
|
|
|
|
|
|
|
297
|
3
|
|
|
|
|
8
|
my $length = length $str; |
298
|
3
|
50
|
|
|
|
28
|
return "'" . $str . "'" if ($length <= $max_length); |
299
|
0
|
|
|
|
|
0
|
return "'" . substr($str,0,$max_length) . "'...<$length" . " bytes> "; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
our $debug_arounds_set = {}; |
303
|
|
|
|
|
|
|
our $debug_around_nest_level = 0; |
304
|
|
|
|
|
|
|
our $debug_around_last_nest_level = 0; |
305
|
|
|
|
|
|
|
our $debug_around_stats = {}; |
306
|
|
|
|
|
|
|
our $debug_around_nest_elapse = 0; |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub debug_around($@) { |
309
|
0
|
|
|
0
|
0
|
0
|
my ($pkg,$filename,$line) = caller; |
310
|
0
|
|
|
|
|
0
|
my $method = shift; |
311
|
0
|
|
|
|
|
0
|
my @methods = ( $method ); |
312
|
0
|
0
|
|
|
|
0
|
@methods = @$method if (ref($method) eq 'ARRAY'); |
313
|
|
|
|
|
|
|
|
314
|
0
|
0
|
|
|
|
0
|
my %opt = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
|
0
|
|
|
|
|
0
|
|
315
|
|
|
|
|
|
|
|
316
|
0
|
|
|
|
|
0
|
%opt = ( |
317
|
|
|
|
|
|
|
pkg => $pkg, |
318
|
|
|
|
|
|
|
filename => $filename, |
319
|
|
|
|
|
|
|
line => $line, |
320
|
|
|
|
|
|
|
%opt |
321
|
|
|
|
|
|
|
); |
322
|
|
|
|
|
|
|
|
323
|
0
|
|
|
|
|
0
|
$pkg = $opt{pkg}; |
324
|
|
|
|
|
|
|
|
325
|
0
|
|
|
|
|
0
|
foreach my $method (@methods) { |
326
|
|
|
|
|
|
|
|
327
|
0
|
|
|
|
|
0
|
my $package = $pkg; |
328
|
0
|
|
|
|
|
0
|
my @namespace = split(/::/,$method); |
329
|
0
|
0
|
|
|
|
0
|
if(scalar @namespace > 1) { |
330
|
0
|
|
|
|
|
0
|
$method = pop @namespace; |
331
|
0
|
|
|
|
|
0
|
$package = join('::',@namespace); |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
0
|
0
|
|
|
|
0
|
next if ($debug_arounds_set->{$package . '->' . $method}++); #<-- if its already set |
335
|
|
|
|
|
|
|
|
336
|
0
|
|
|
|
|
0
|
eval "require $package;"; |
337
|
0
|
|
|
|
|
0
|
my $around = func_debug_around($method, %opt, pkg => $package); |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
# It's a Moose class or otherwise already has an 'around' class method: |
340
|
0
|
0
|
|
|
|
0
|
if($package->can('around')) { |
341
|
0
|
|
|
|
|
0
|
$package->can('around')->($method => $around); |
342
|
0
|
|
|
|
|
0
|
next; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
# The class doesn't have an around method, so we'll setup manually with Class::MOP: |
346
|
0
|
|
|
|
|
0
|
my $meta = Class::MOP::Class->initialize($package); |
347
|
0
|
|
|
|
|
0
|
$meta->add_around_method_modifier($method => $around) |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
# Returns a coderef - designed to be a Moose around modifier - that will |
352
|
|
|
|
|
|
|
# print useful debug info about the given function to which it is attached |
353
|
|
|
|
|
|
|
sub func_debug_around { |
354
|
0
|
|
|
0
|
0
|
0
|
my $name = shift; |
355
|
0
|
0
|
|
|
|
0
|
my %opt = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
|
0
|
|
|
|
|
0
|
|
356
|
|
|
|
|
|
|
|
357
|
0
|
|
|
|
|
0
|
my $Id = $DEBUG_AROUND_COUNT++; |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
%opt = ( |
361
|
|
|
|
|
|
|
track_stats => 1, |
362
|
|
|
|
|
|
|
time => 1, |
363
|
|
|
|
|
|
|
verbose => 0, |
364
|
|
|
|
|
|
|
verbose_in => undef, |
365
|
|
|
|
|
|
|
verbose_out => undef, |
366
|
|
|
|
|
|
|
newline => 0, |
367
|
|
|
|
|
|
|
list_args => 0, |
368
|
|
|
|
|
|
|
list_out => 0, |
369
|
|
|
|
|
|
|
dump_maxdepth => 3, |
370
|
|
|
|
|
|
|
use_json => 0, |
371
|
|
|
|
|
|
|
stack => 0, |
372
|
|
|
|
|
|
|
instance => 0, |
373
|
|
|
|
|
|
|
color => GREEN, |
374
|
|
|
|
|
|
|
ret_color => RED.BOLD, |
375
|
0
|
|
|
0
|
|
0
|
arg_ignore => sub { 0 }, # <-- no debug output prited when this returns true |
376
|
0
|
|
|
0
|
|
0
|
return_ignore => sub { 0 },# <-- no debug output prited when this returns true |
377
|
0
|
|
|
|
|
0
|
%opt |
378
|
|
|
|
|
|
|
); |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
# around wrapper in %opt to allow the user to pass a different one to use: |
381
|
|
|
|
|
|
|
$opt{around} ||= sub { |
382
|
0
|
|
|
0
|
|
0
|
my $orig = shift; |
383
|
0
|
|
|
|
|
0
|
my $self = shift; |
384
|
0
|
0
|
|
|
|
0
|
print STDERR "\n" if ($opt{newline}); |
385
|
0
|
|
|
|
|
0
|
return $self->$orig(@_); |
386
|
0
|
|
0
|
|
|
0
|
}; |
387
|
|
|
|
|
|
|
|
388
|
0
|
0
|
0
|
|
|
0
|
$opt{verbose_in} = 1 if ($opt{verbose} and not defined $opt{verbose_in}); |
389
|
0
|
0
|
0
|
|
|
0
|
$opt{verbose_out} = 1 if ($opt{verbose} and not defined $opt{verbose_out}); |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
$opt{dump_func} = sub { |
392
|
0
|
|
|
0
|
|
0
|
my $verbose = shift; |
393
|
0
|
0
|
0
|
|
|
0
|
return UNDERLINE . 'undef' . CLEAR unless (@_ > 0 and defined $_[0]); |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
# if list_out is false, return the number of items in the return, underlined |
396
|
0
|
0
|
|
|
|
0
|
return $opt{list_out} ? join(',',map { ref $_ ? "$_" : "'$_'" } @_) : UNDERLINE . @_ . CLEAR |
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
|
397
|
|
|
|
|
|
|
unless ($verbose); |
398
|
|
|
|
|
|
|
|
399
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Maxdepth = $opt{dump_maxdepth}; |
400
|
0
|
0
|
|
|
|
0
|
return Dumper(@_) unless ($opt{use_json}); |
401
|
|
|
|
|
|
|
#return RapidApp::JSON::MixedEncoder->new->allow_blessed->convert_blessed->allow_nonref->encode(\@_); |
402
|
0
|
|
|
|
|
0
|
return encode_json(\@_); |
403
|
0
|
0
|
|
|
|
0
|
} unless ($opt{dump_func}); |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
return sub { |
406
|
0
|
|
|
0
|
|
0
|
my $orig = shift; |
407
|
0
|
|
|
|
|
0
|
my $self = shift; |
408
|
0
|
|
|
|
|
0
|
my @args = @_; |
409
|
|
|
|
|
|
|
|
410
|
0
|
|
|
|
|
0
|
my $printed_newlines = 0; |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
my $_PRINTER = sub { |
413
|
0
|
|
|
|
|
0
|
for my $text (@_) { |
414
|
0
|
|
|
|
|
0
|
my $char = "\n"; |
415
|
0
|
|
|
|
|
0
|
my $newlines = () = $text =~ /\Q$char/g; |
416
|
0
|
|
|
|
|
0
|
$printed_newlines = $printed_newlines + $newlines; |
417
|
0
|
|
|
|
|
0
|
print STDERR $text |
418
|
|
|
|
|
|
|
} |
419
|
0
|
|
|
|
|
0
|
}; |
420
|
|
|
|
|
|
|
|
421
|
0
|
|
|
|
|
0
|
my $Count = $DEBUG_AROUND_CALL_NO++; |
422
|
0
|
|
|
|
|
0
|
my $is_odd = $Count % 2 == 1; |
423
|
|
|
|
|
|
|
|
424
|
0
|
0
|
|
|
|
0
|
my $label_color = $is_odd ? CLEAR.CYAN.BOLD : CLEAR.MAGENTA.BOLD; |
425
|
|
|
|
|
|
|
|
426
|
0
|
|
|
|
|
0
|
my $nest_level = $debug_around_nest_level; |
427
|
0
|
|
|
|
|
0
|
local $debug_around_nest_level = $debug_around_nest_level + 1; |
428
|
|
|
|
|
|
|
|
429
|
0
|
0
|
|
|
|
0
|
my $new_nest = $debug_around_last_nest_level < $nest_level ? 1 : 0; |
430
|
0
|
0
|
|
|
|
0
|
my $leave_nest = $debug_around_last_nest_level > $nest_level ? 1 : 0; |
431
|
0
|
|
|
|
|
0
|
$debug_around_last_nest_level = $nest_level; |
432
|
|
|
|
|
|
|
|
433
|
0
|
0
|
|
|
|
0
|
$debug_around_nest_elapse = 0 if ($nest_level == 0); |
434
|
|
|
|
|
|
|
|
435
|
0
|
0
|
|
|
|
0
|
my $indent = $nest_level > 0 ? (' ' x $nest_level) : ''; |
436
|
0
|
|
|
|
|
0
|
my $newline = "\n$indent"; |
437
|
|
|
|
|
|
|
|
438
|
0
|
|
|
|
|
0
|
my $has_refs = 0; |
439
|
|
|
|
|
|
|
|
440
|
0
|
|
|
|
|
0
|
my $class = $opt{pkg}; |
441
|
|
|
|
|
|
|
|
442
|
0
|
|
0
|
|
|
0
|
my $oneline = ! $leave_nest || ! $nest_level; |
443
|
|
|
|
|
|
|
|
444
|
0
|
0
|
|
|
|
0
|
$_PRINTER->($newline) if ($new_nest); |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
$_PRINTER->(join('', |
447
|
|
|
|
|
|
|
$label_color,"[$Id/$Count]",'==> ',CLEAR,$opt{color},$class,CLEAR,'->', |
448
|
0
|
|
|
|
|
0
|
$opt{color},BOLD,$name,CLEAR, |
449
|
|
|
|
|
|
|
'( ' . MAGENTA . 'args in: ' . BOLD . scalar(@args) . CLEAR . ' ) ' |
450
|
|
|
|
|
|
|
)); |
451
|
|
|
|
|
|
|
|
452
|
0
|
0
|
|
|
|
0
|
if($opt{list_args}) { |
453
|
0
|
|
|
|
|
0
|
$oneline = 0; |
454
|
0
|
|
|
|
|
0
|
my @plines = split(/\r?\n/,np(@args, colored => 0)); |
455
|
0
|
|
|
|
|
0
|
$plines[0] = "Supplied arguments: $plines[0]"; |
456
|
0
|
|
|
|
|
0
|
my $max = 0; |
457
|
0
|
|
0
|
|
|
0
|
$max < $_ and $max = $_ for (map { length($_) } @plines); |
|
0
|
|
|
|
|
0
|
|
458
|
|
|
|
|
|
|
|
459
|
0
|
|
|
|
|
0
|
for my $line (@plines) { |
460
|
0
|
|
|
|
|
0
|
my $pad = $max - length($line); |
461
|
0
|
|
|
|
|
0
|
$_PRINTER->(join('',$newline,(' ' x ($nest_level+6)), ON_CYAN,' ', $line,ON_CYAN, (' ' x ($pad+3)),' ',CLEAR)); |
462
|
|
|
|
|
|
|
} |
463
|
0
|
|
|
|
|
0
|
$_PRINTER->($newline); |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
#my $in = '( ' . MAGENTA . 'args in: ' . BOLD . scalar(@args) . CLEAR . ' ): '; |
473
|
|
|
|
|
|
|
#if($opt{list_args}) { |
474
|
|
|
|
|
|
|
# my @print_args = map { (ref($_) and ++$has_refs) ? "$_" : MAGENTA . "'$_'" . CLEAR } @args; |
475
|
|
|
|
|
|
|
# $in = '(' . join(',',@print_args) . '): '; |
476
|
|
|
|
|
|
|
#} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
|
479
|
0
|
0
|
|
|
|
0
|
if($opt{stack}) { |
480
|
0
|
|
|
|
|
0
|
$oneline = 0; |
481
|
0
|
|
|
|
|
0
|
my $stack = caller_data_brief($opt{stack} + 3); |
482
|
0
|
|
|
|
|
0
|
shift @$stack; |
483
|
0
|
|
|
|
|
0
|
shift @$stack; |
484
|
0
|
|
|
|
|
0
|
shift @$stack; |
485
|
0
|
|
|
|
|
0
|
@$stack = reverse @$stack; |
486
|
0
|
|
|
|
|
0
|
my $i = scalar @$stack; |
487
|
|
|
|
|
|
|
#my $i = $opt{stack}; |
488
|
0
|
|
|
|
|
0
|
$_PRINTER->($newline); |
489
|
|
|
|
|
|
|
|
490
|
0
|
|
|
|
|
0
|
my $max_fn = 0; |
491
|
0
|
|
|
|
|
0
|
foreach my $data (@$stack) { |
492
|
0
|
|
|
|
|
0
|
my ($fn) = split(/\s+/,(reverse split(/\//,$data->{filename}))[0]); |
493
|
0
|
0
|
|
|
|
0
|
$max_fn = length($fn) if (length($fn) > $max_fn); |
494
|
0
|
|
|
|
|
0
|
$data->{fn} = $fn; |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
|
497
|
0
|
|
|
|
|
0
|
my $pfx = ' '; |
498
|
0
|
|
|
|
|
0
|
foreach my $data (@$stack) { |
499
|
|
|
|
|
|
|
$_PRINTER->($label_color,'|'.$pfx . CLEAR . sprintf("%3s",$i--) . ' | ' . CYAN . sprintf("%".$max_fn."s",$data->{fn}) . ' ' . |
500
|
|
|
|
|
|
|
BOLD . sprintf("%-5s",$data->{line}) . CLEAR . CYAN . '-> ' . CLEAR . |
501
|
0
|
|
|
|
|
0
|
GREEN . $data->{subroutine} . CLEAR . $newline); |
502
|
0
|
|
|
|
|
0
|
$pfx = '^'; |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
#print STDERR '((stack 0)) ' . sprintf("%7s",'[' . $opt{line} . ']') . ' ' . |
507
|
|
|
|
|
|
|
# GREEN . $class . '::' . $name . $newline . CLEAR; |
508
|
|
|
|
|
|
|
#$class = "$self"; |
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
#else { |
511
|
|
|
|
|
|
|
# print STDERR $newline and $oneline = 0 if ($new_nest); |
512
|
|
|
|
|
|
|
#} |
513
|
|
|
|
|
|
|
|
514
|
0
|
0
|
|
|
|
0
|
if($opt{stack}) { |
515
|
0
|
|
|
|
|
0
|
$_PRINTER->(CLEAR . $label_color . "|^" .CLEAR . BOLD " -->" . CLEAR); |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
0
|
0
|
|
|
|
0
|
unless($oneline) { |
519
|
0
|
0
|
|
|
|
0
|
$_PRINTER->($label_color . "[$Id/$Count]",'^^ ' . CLEAR) unless ($opt{stack}); |
520
|
0
|
|
|
|
|
0
|
$_PRINTER->(' ',$opt{color} . $class . CLEAR . '->' . $opt{color} . BOLD . $name . ' ' . CLEAR); |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
|
534
|
0
|
|
|
|
|
0
|
my $spaces = ' ' x (2 + length($opt{line})); |
535
|
|
|
|
|
|
|
my $in_func = sub { |
536
|
|
|
|
|
|
|
$_PRINTER->($newline . ON_WHITE.BOLD . BLUE . "$spaces Supplied arguments dump: " . |
537
|
|
|
|
|
|
|
$opt{dump_func}->($opt{verbose_in},\@args) . CLEAR . $newline . ": ") |
538
|
0
|
0
|
0
|
|
|
0
|
if($has_refs && $opt{verbose_in}); |
539
|
0
|
|
|
|
|
0
|
}; |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
|
547
|
0
|
|
|
|
|
0
|
my $res; |
548
|
|
|
|
|
|
|
my @res; |
549
|
0
|
|
|
|
|
0
|
my @res_copy = (); |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
# before timestamp: |
552
|
0
|
|
|
|
|
0
|
my $t0 = [gettimeofday]; |
553
|
0
|
|
|
|
|
0
|
my $current_nest_elapse; |
554
|
|
|
|
|
|
|
{ |
555
|
0
|
|
|
|
|
0
|
local $debug_around_nest_elapse = 0; |
|
0
|
|
|
|
|
0
|
|
556
|
0
|
0
|
|
|
|
0
|
if(wantarray) { |
557
|
|
|
|
|
|
|
try { |
558
|
0
|
|
|
|
|
0
|
@res = $opt{around}->($orig,$self,@args); |
559
|
0
|
|
|
|
|
0
|
} catch { $in_func->(); die (shift);}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
560
|
0
|
|
|
|
|
0
|
push @res_copy, @res; |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
else { |
563
|
|
|
|
|
|
|
try { |
564
|
0
|
|
|
|
|
0
|
$res = $opt{around}->($orig,$self,@args); |
565
|
0
|
|
|
|
|
0
|
} catch { $in_func->(); die (shift);}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
566
|
0
|
|
|
|
|
0
|
push @res_copy,$res; |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
# How much of the elapsed time was in nested funcs below us: |
569
|
0
|
|
|
|
|
0
|
$current_nest_elapse = $debug_around_nest_elapse; |
570
|
|
|
|
|
|
|
} |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
|
574
|
0
|
0
|
|
|
|
0
|
if($opt{list_out}) { |
575
|
0
|
|
|
|
|
0
|
$oneline = 0; |
576
|
0
|
|
|
|
|
0
|
my @plines = split(/\r?\n/,np(@res_copy, colored => 0)); |
577
|
0
|
|
|
|
|
0
|
$plines[0] = "Returned values: $plines[0]"; |
578
|
0
|
|
|
|
|
0
|
my $max = 0; |
579
|
0
|
|
0
|
|
|
0
|
$max < $_ and $max = $_ for (map { length($_) } @plines); |
|
0
|
|
|
|
|
0
|
|
580
|
|
|
|
|
|
|
|
581
|
0
|
|
|
|
|
0
|
for my $line (@plines) { |
582
|
0
|
|
|
|
|
0
|
my $pad = $max - length($line); |
583
|
0
|
|
|
|
|
0
|
$_PRINTER->(join('',$newline,(' ' x ($nest_level+6)), ON_GREEN,' ', $line,ON_GREEN, (' ' x ($pad+3)),' ',CLEAR)); |
584
|
|
|
|
|
|
|
} |
585
|
0
|
|
|
|
|
0
|
$_PRINTER->($newline); |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
# after timestamp, calculate elapsed (to the millisecond): |
593
|
0
|
|
|
|
|
0
|
my $elapsed_raw = tv_interval($t0); |
594
|
0
|
|
|
|
|
0
|
my $adj_elapsed = $elapsed_raw - $current_nest_elapse; |
595
|
0
|
|
|
|
|
0
|
$debug_around_nest_elapse += $elapsed_raw; #<-- send our elapsed time up the chain |
596
|
|
|
|
|
|
|
|
597
|
0
|
0
|
|
|
|
0
|
if($opt{list_out}) { |
598
|
|
|
|
|
|
|
$_PRINTER->($label_color . $label_color . "[$Id/$Count]", '^^^ ' . CLEAR . $opt{color} . $class . CLEAR . '->' . |
599
|
0
|
|
|
|
|
0
|
$opt{color} . BOLD . $name . ' '); |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
|
602
|
0
|
|
|
|
|
0
|
$_PRINTER->($opt{ret_color} . 'Ret itms: ' . scalar(@res_copy) . CLEAR); |
603
|
0
|
|
|
|
|
0
|
$_PRINTER->(CLEAR . ' in ' . ON_WHITE.RED . sprintf('%.5fs',$elapsed_raw) . ' (' . sprintf('%.5fs',$adj_elapsed) . ' exclusive)' . CLEAR); |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
# -- Track stats in global %$RapidApp::Util::debug_around_stats: |
607
|
0
|
0
|
|
|
|
0
|
if($opt{track_stats}) { |
608
|
6
|
|
|
6
|
|
51
|
no warnings 'uninitialized'; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
11758
|
|
609
|
0
|
|
|
|
|
0
|
my $k = $class . '->' . $name; |
610
|
0
|
|
0
|
|
|
0
|
$debug_around_stats->{$k} = $debug_around_stats->{$k} || {}; |
611
|
0
|
|
|
|
|
0
|
my $stats = $debug_around_stats->{$k}; |
612
|
|
|
|
|
|
|
%$stats = ( |
613
|
|
|
|
|
|
|
class => $class, |
614
|
|
|
|
|
|
|
sub => $name, |
615
|
|
|
|
|
|
|
line => $opt{line}, |
616
|
|
|
|
|
|
|
calls => $stats->{calls} + 1, |
617
|
|
|
|
|
|
|
real_total => $stats->{real_total} + $elapsed_raw, |
618
|
|
|
|
|
|
|
total => $stats->{total} + $adj_elapsed, |
619
|
|
|
|
|
|
|
min => exists $stats->{min} ? $stats->{min} : $adj_elapsed, |
620
|
0
|
0
|
|
|
|
0
|
max => exists $stats->{max} ? $stats->{max} : $adj_elapsed, |
|
|
0
|
|
|
|
|
|
621
|
|
|
|
|
|
|
); |
622
|
0
|
|
|
|
|
0
|
$stats->{avg} = $stats->{total}/$stats->{calls}; |
623
|
0
|
0
|
|
|
|
0
|
$stats->{min} = $adj_elapsed if ($adj_elapsed < $stats->{min}); |
624
|
0
|
0
|
|
|
|
0
|
$stats->{max} = $adj_elapsed if ($adj_elapsed > $stats->{max}); |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
# -- |
627
|
|
|
|
|
|
|
|
628
|
0
|
|
|
|
|
0
|
local $_ = $self; |
629
|
0
|
0
|
0
|
|
|
0
|
if(!$opt{arg_ignore}->(@args) && !$opt{return_ignore}->(@res_copy)) { |
630
|
|
|
|
|
|
|
|
631
|
0
|
|
|
|
|
0
|
$in_func->(); |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
#my $elapsed_short = '[' . sprintf("%.3f", $elapsed_raw ) . 's]'; |
634
|
|
|
|
|
|
|
|
635
|
0
|
|
|
|
|
0
|
my @a = map { sprintf('%.3f',$_) } ($elapsed_raw,$adj_elapsed); |
|
0
|
|
|
|
|
0
|
|
636
|
0
|
|
|
|
|
0
|
my $elapsed_long = '[' . join('|',@a) . ']'; |
637
|
|
|
|
|
|
|
|
638
|
0
|
|
|
|
|
0
|
my $result = $opt{ret_color} . $opt{dump_func}->($opt{verbose_out},@res_copy) . CLEAR; |
639
|
0
|
0
|
|
|
|
0
|
$result = "\n" . ON_WHITE.BOLD . "$spaces Returned: " . $result . "\n" if ($opt{verbose_out}); |
640
|
0
|
0
|
|
|
|
0
|
$result .= ' ' . ON_WHITE.RED . $elapsed_long . CLEAR if ($opt{time}); |
641
|
|
|
|
|
|
|
|
642
|
0
|
|
|
|
|
0
|
$result =~ s/\n/${newline}/gm; |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
# Reset cursor position if nesting happened: |
645
|
0
|
0
|
|
|
|
0
|
$_PRINTER->("\r$indent") unless ($RapidApp::Util::debug_around_last_nest_level == $nest_level); |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
#print STDERR $result . $newline; |
648
|
0
|
|
|
|
|
0
|
$_PRINTER->($newline); |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
else { |
652
|
|
|
|
|
|
|
# 'arg_ignore' and/or 'return_ignore' returned true, so we're not |
653
|
|
|
|
|
|
|
# supposed to print anything... but since we already have, in case |
654
|
|
|
|
|
|
|
# the function would have barfed, we'll print a \r to move the cursor |
655
|
|
|
|
|
|
|
# to the begining of the line so it will get overwritten, which is |
656
|
|
|
|
|
|
|
# almost as good as if we had not printed anything in the first place... |
657
|
|
|
|
|
|
|
# (note if the function printed something too we're screwed) |
658
|
0
|
|
|
|
|
0
|
$_PRINTER->("\r"); |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
0
|
0
|
|
|
|
0
|
if($printed_newlines > 5) { |
662
|
0
|
|
|
|
|
0
|
$_PRINTER->($label_color,"[$Id/$Count]", ('-' x 80), '^^^^', "\n\n",CLEAR); |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
} |
665
|
|
|
|
|
|
|
|
666
|
0
|
0
|
|
|
|
0
|
return wantarray ? @res : $res; |
667
|
0
|
|
|
|
|
0
|
}; |
668
|
|
|
|
|
|
|
} |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
# Lets you create a sub and set debug_around on it at the same time |
671
|
|
|
|
|
|
|
sub debug_sub($&) { |
672
|
0
|
|
|
0
|
0
|
0
|
my ($pkg,$filename,$line) = caller; |
673
|
0
|
|
|
|
|
0
|
my ($name,$code) = @_; |
674
|
|
|
|
|
|
|
|
675
|
0
|
|
|
|
|
0
|
my $meta = Class::MOP::Class->initialize($pkg); |
676
|
0
|
|
|
|
|
0
|
$meta->add_method($name,$code); |
677
|
|
|
|
|
|
|
|
678
|
0
|
|
|
|
|
0
|
return debug_around $name, pkg => $pkg, filename => $filename, line => $line; |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
sub debug_around_all { |
682
|
0
|
|
0
|
0
|
0
|
0
|
my $pkg = shift || caller; |
683
|
0
|
|
|
|
|
0
|
my $meta = Class::MOP::Class->initialize($pkg); |
684
|
0
|
|
|
|
|
0
|
debug_around($_, pkg => $pkg) for ($meta->get_method_list); |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
# Returns a stat in a hash with named keys |
688
|
|
|
|
|
|
|
sub xstat { |
689
|
0
|
|
|
0
|
0
|
0
|
my $file = shift; |
690
|
0
|
0
|
|
|
|
0
|
return undef unless (-e $file); |
691
|
0
|
|
|
|
|
0
|
my $h = {}; |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
($h->{dev},$h->{ino},$h->{mode},$h->{nlink},$h->{uid},$h->{gid},$h->{rdev}, |
694
|
|
|
|
|
|
|
$h->{size},$h->{atime},$h->{mtime},$h->{ctime},$h->{blksize},$h->{blocks}) |
695
|
0
|
|
|
|
|
0
|
= stat($file); |
696
|
|
|
|
|
|
|
|
697
|
0
|
|
|
|
|
0
|
return $h; |
698
|
|
|
|
|
|
|
} |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
##### From RapidApp::Sugar ##### |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
sub asjson { |
704
|
0
|
0
|
|
0
|
0
|
0
|
scalar(@_) == 1 or die "Expected single argument"; |
705
|
0
|
|
|
|
|
0
|
return RapidApp::JSON::MixedEncoder::encode_json($_[0]); |
706
|
|
|
|
|
|
|
} |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
# Bless a string as RawJavascript so that it doesn't get encoded as JSON data during asjson |
709
|
|
|
|
|
|
|
sub rawjs { |
710
|
0
|
0
|
0
|
0
|
0
|
0
|
scalar(@_) == 1 && ref $_[0] eq '' or die "Expected single string argument"; |
711
|
0
|
|
|
|
|
0
|
return RapidApp::JSON::RawJavascript->new(js=>$_[0]); |
712
|
|
|
|
|
|
|
} |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
# Works like rawjs but accepts a list of arguments. Each argument should be a function defintion, |
715
|
|
|
|
|
|
|
# and will be stacked together, passing each function in the chain through the first argument |
716
|
|
|
|
|
|
|
sub jsfunc { |
717
|
2093
|
50
|
|
2093
|
0
|
4871
|
my $js = shift or die "jsfunc(): At least one argument is required"; |
718
|
|
|
|
|
|
|
|
719
|
2093
|
100
|
|
|
|
5007
|
return jsfunc(@$js) if (ref($js) eq 'ARRAY'); |
720
|
|
|
|
|
|
|
|
721
|
1509
|
50
|
66
|
|
|
4017
|
blessed $js and not $js->can('TO_JSON_RAW') and |
722
|
|
|
|
|
|
|
die "jsfunc: arguments must be JavaScript function definition strings or objects with TO_JSON_RAW methods"; |
723
|
|
|
|
|
|
|
|
724
|
1509
|
100
|
|
|
|
3287
|
$js = $js->TO_JSON_RAW if (blessed $js); |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
# Remove undef arguments: |
727
|
1509
|
|
|
|
|
2483
|
@_ = grep { defined $_ } @_; |
|
918
|
|
|
|
|
3053
|
|
728
|
|
|
|
|
|
|
|
729
|
1509
|
100
|
|
|
|
4787
|
$js = 'function(){ ' . |
730
|
|
|
|
|
|
|
'var args = arguments; ' . |
731
|
|
|
|
|
|
|
'args[0] = (' . $js . ').apply(this,arguments); ' . |
732
|
|
|
|
|
|
|
'return (' . jsfunc(@_) . ').apply(this,args); ' . |
733
|
|
|
|
|
|
|
'}' if (scalar @_ > 0); |
734
|
|
|
|
|
|
|
|
735
|
1509
|
|
|
|
|
46379
|
return RapidApp::JSON::RawJavascript->new(js=>$js) |
736
|
|
|
|
|
|
|
} |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
# Encode a mix of javascript and data into appropriate objects that will get converted |
739
|
|
|
|
|
|
|
# to JSON properly during "asjson". |
740
|
|
|
|
|
|
|
# |
741
|
|
|
|
|
|
|
# Example: mixedjs "function() { var data=", { a => $foo, b => $bar }, "; Ext.msg.alert(data); }"; |
742
|
|
|
|
|
|
|
# See ScriptWithData for more details. |
743
|
|
|
|
|
|
|
# |
744
|
|
|
|
|
|
|
sub mixedjs { |
745
|
0
|
|
|
0
|
0
|
|
return RapidApp::JSON::ScriptWithData->new(@_); |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
# Take a string of text/plain and convert it to text/html. This handles "RawHtml" objects. |
749
|
|
|
|
|
|
|
sub ashtml { |
750
|
0
|
|
|
0
|
0
|
|
my $text= shift; |
751
|
0
|
0
|
0
|
|
|
|
return "$text" if ref($text) && ref($text)->isa('RapidApp::HTML::RawHtml'); |
752
|
0
|
0
|
|
|
|
|
return undef unless defined $text; |
753
|
0
|
|
|
|
|
|
return join('<br />', map { encode_entities($_) } split("\n", "$text")); |
|
0
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
# Bless a scalar to indicate the scalar is already html, and doesn't need converted. |
757
|
|
|
|
|
|
|
sub rawhtml { |
758
|
0
|
|
|
0
|
0
|
|
my $html= shift; |
759
|
|
|
|
|
|
|
# any other arguments we were given, we pass back in hopes that we're part of a function call that needed them. |
760
|
0
|
|
|
|
|
|
return RapidApp::HTML::RawHtml->new($html), @_; |
761
|
|
|
|
|
|
|
} |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
=head2 usererr $message, key => $value, key => $value |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
Shorthand notation to create a UserError, to inform the user they did something wrong. |
766
|
|
|
|
|
|
|
First argument is a scalar of text (or a RawHtml scalar of html) |
767
|
|
|
|
|
|
|
Second through N arguments are hash keys to apply to the UserError constructor. |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
Examples: |
770
|
|
|
|
|
|
|
# To throw a message to the user with no data and no error report: |
771
|
|
|
|
|
|
|
die usererr "Hey you moron, don't do that"; |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
# To specify that your message is html already: |
774
|
|
|
|
|
|
|
die usererr rawhtml "<h2>Hell Yeah</h2>"; |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
=cut |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
my %keyAliases = ( |
779
|
|
|
|
|
|
|
msg => 'message', |
780
|
|
|
|
|
|
|
umsg => 'userMessage', |
781
|
|
|
|
|
|
|
title => 'userMessageTitle', |
782
|
|
|
|
|
|
|
); |
783
|
|
|
|
|
|
|
sub usererr { |
784
|
0
|
|
|
0
|
1
|
|
my %args= (); |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
# First arg is always the message. We stringify it, so it doesn't matter if it was an object. |
787
|
0
|
|
|
|
|
|
my $msg= shift; |
788
|
0
|
0
|
|
|
|
|
defined $msg or die "userexception requires at least a first message argument"; |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
# If the passed arg is already a UserError object, return it as-is: |
791
|
0
|
0
|
0
|
|
|
|
return $msg if ref($msg) && ref($msg)->isa('RapidApp::Responder::UserError'); |
792
|
|
|
|
|
|
|
|
793
|
0
|
0
|
0
|
|
|
|
$args{userMessage}= ref($msg) && ref($msg)->isa('RapidApp::HTML::RawHtml')? $msg : "$msg"; |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
# pull in any other args |
796
|
0
|
|
|
|
|
|
while (scalar(@_) > 1) { |
797
|
0
|
|
|
|
|
|
my ($key, $val)= (shift, shift); |
798
|
0
|
|
0
|
|
|
|
$key = $keyAliases{$key} || $key; |
799
|
0
|
0
|
|
|
|
|
RapidApp::Responder::UserError->can($key) |
800
|
|
|
|
|
|
|
or warn "Invalid attribute for UserError: $key"; |
801
|
0
|
|
|
|
|
|
$args{$key}= $val; |
802
|
|
|
|
|
|
|
} |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
# userexception is allowed to have a payload at the end, but this would be meaningless for usererr, |
805
|
|
|
|
|
|
|
# since usererr is not saved. |
806
|
0
|
0
|
|
|
|
|
if (scalar(@_)) { |
807
|
0
|
|
|
|
|
|
my ($pkg, $file, $line)= caller; |
808
|
0
|
|
|
|
|
|
warn "Odd number of arguments to usererr at $file:$line"; |
809
|
|
|
|
|
|
|
} |
810
|
|
|
|
|
|
|
|
811
|
0
|
|
|
|
|
|
return RapidApp::Responder::UserError->new(\%args); |
812
|
|
|
|
|
|
|
} |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
=head2 userexception $message, key => $value, key => $value, \%data |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
Shorthand notation for creating a RapidApp::Error which also informs the user about why the error occured. |
817
|
|
|
|
|
|
|
First argument is the message displayed to the user (can be a RawHtml object). |
818
|
|
|
|
|
|
|
Last argument is a hash of data that should be saved for the error report. |
819
|
|
|
|
|
|
|
( the last argument is equivalent to a value for an implied hash key of "data" ) |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
Examples: |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
# Die with a custom user-facing message (in plain text), and a title made of html. |
824
|
|
|
|
|
|
|
die userexception "Description of what shouldn't have happened", title => rawhtml "<h1>ERROR</h1>"; |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
# Capture some data for the error report, as we show this message to the user. |
827
|
|
|
|
|
|
|
die userexception "Description of what shouldn't have happened", $some_debug_info; |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
=cut |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
sub userexception { |
832
|
0
|
|
|
0
|
1
|
|
my %args= (); |
833
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
# First arg is always the message. We stringify it, so it doesn't matter if it was an object. |
835
|
0
|
|
|
|
|
|
my $msg= shift; |
836
|
0
|
0
|
|
|
|
|
defined $msg or die "userexception requires at least a first message argument"; |
837
|
0
|
0
|
0
|
|
|
|
$args{userMessage}= ref($msg) && ref($msg)->isa('RapidApp::HTML::RawHtml')? $msg : "$msg"; |
838
|
0
|
|
|
|
|
|
$args{message}= $args{userMessage}; |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
# pull in any other args |
841
|
0
|
|
|
|
|
|
while (scalar(@_) > 1) { |
842
|
0
|
|
|
|
|
|
my ($key, $val)= (shift, shift); |
843
|
0
|
|
0
|
|
|
|
$key = $keyAliases{$key} || $key; |
844
|
0
|
0
|
|
|
|
|
RapidApp::Error->can($key) |
845
|
|
|
|
|
|
|
or warn "Invalid attribute for RapidApp::Error: $key"; |
846
|
0
|
|
|
|
|
|
$args{$key}= $val; |
847
|
|
|
|
|
|
|
} |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
# userexception is allowed to have a payload as the last argument |
850
|
0
|
0
|
|
|
|
|
if (scalar(@_)) { |
851
|
0
|
|
|
|
|
|
$args{data}= shift; |
852
|
|
|
|
|
|
|
} |
853
|
|
|
|
|
|
|
|
854
|
0
|
|
|
|
|
|
return RapidApp::Error->new(\%args); |
855
|
|
|
|
|
|
|
} |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
# Suger function sets up a Native Trait ArrayRef attribute with useful |
860
|
|
|
|
|
|
|
# default accessor methods |
861
|
|
|
|
|
|
|
#sub hasarray { |
862
|
|
|
|
|
|
|
# my $name = shift; |
863
|
|
|
|
|
|
|
# my %opt = @_; |
864
|
|
|
|
|
|
|
# |
865
|
|
|
|
|
|
|
# my %defaults = ( |
866
|
|
|
|
|
|
|
# is => 'ro', |
867
|
|
|
|
|
|
|
# isa => 'ArrayRef', |
868
|
|
|
|
|
|
|
# traits => [ 'Array' ], |
869
|
|
|
|
|
|
|
# default => sub {[]}, |
870
|
|
|
|
|
|
|
# handles => { |
871
|
|
|
|
|
|
|
# 'all_' . $name => 'uniq', |
872
|
|
|
|
|
|
|
# 'add_' . $name => 'push', |
873
|
|
|
|
|
|
|
# 'insert_' . $name => 'unshift', |
874
|
|
|
|
|
|
|
# 'has_no_' . $name => 'is_empty', |
875
|
|
|
|
|
|
|
# 'count_' . $name => 'count' |
876
|
|
|
|
|
|
|
# } |
877
|
|
|
|
|
|
|
# ); |
878
|
|
|
|
|
|
|
# |
879
|
|
|
|
|
|
|
# my $conf = merge(\%defaults,\%opt); |
880
|
|
|
|
|
|
|
# return caller->can('has')->($name,%$conf); |
881
|
|
|
|
|
|
|
#} |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
# Suger function sets up a Native Trait HashRef attribute with useful |
884
|
|
|
|
|
|
|
# default accessor methods |
885
|
|
|
|
|
|
|
#sub hashash { |
886
|
|
|
|
|
|
|
# my $name = shift; |
887
|
|
|
|
|
|
|
# my %opt = @_; |
888
|
|
|
|
|
|
|
# |
889
|
|
|
|
|
|
|
# my %defaults = ( |
890
|
|
|
|
|
|
|
# is => 'ro', |
891
|
|
|
|
|
|
|
# isa => 'HashRef', |
892
|
|
|
|
|
|
|
# traits => [ 'Hash' ], |
893
|
|
|
|
|
|
|
# default => sub {{}}, |
894
|
|
|
|
|
|
|
# handles => { |
895
|
|
|
|
|
|
|
# 'apply_' . $name => 'set', |
896
|
|
|
|
|
|
|
# 'get_' . $name => 'get', |
897
|
|
|
|
|
|
|
# 'has_' . $name => 'exists', |
898
|
|
|
|
|
|
|
# 'all_' . $name => 'values', |
899
|
|
|
|
|
|
|
# $name . '_names' => 'keys', |
900
|
|
|
|
|
|
|
# } |
901
|
|
|
|
|
|
|
# ); |
902
|
|
|
|
|
|
|
# |
903
|
|
|
|
|
|
|
# my $conf = merge(\%defaults,\%opt); |
904
|
|
|
|
|
|
|
# return caller->can('has')->($name,%$conf); |
905
|
|
|
|
|
|
|
#} |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
sub infostatus { |
909
|
0
|
|
|
0
|
0
|
|
my %opt = @_; |
910
|
0
|
0
|
|
|
|
|
%opt = ( msg => $_[0] ) if (@_ == 1); |
911
|
0
|
|
|
|
|
|
return RapidApp::Responder::InfoStatus->new(%opt); |
912
|
|
|
|
|
|
|
} |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
# ----- |
916
|
|
|
|
|
|
|
# New sugar automates usage of CustomPrompt for the purposes of a simple |
917
|
|
|
|
|
|
|
# message with Ok/Cancel buttons. Returns the string name of the button |
918
|
|
|
|
|
|
|
# after the prompt round-trip. Example usage: |
919
|
|
|
|
|
|
|
# |
920
|
|
|
|
|
|
|
# if(throw_prompt_ok("really blah?") eq 'Ok') { |
921
|
|
|
|
|
|
|
# # do blah ... |
922
|
|
|
|
|
|
|
# } |
923
|
|
|
|
|
|
|
# |
924
|
|
|
|
|
|
|
sub throw_prompt_ok { |
925
|
0
|
|
|
0
|
0
|
|
my $msg; |
926
|
0
|
0
|
0
|
|
|
|
$msg = shift if (scalar(@_) % 2 && ! (ref $_[0])); # argument list is odd, and first arg not a ref |
927
|
|
|
|
|
|
|
|
928
|
0
|
0
|
0
|
|
|
|
my %opt = (ref($_[0]) && ref($_[0]) eq 'HASH') ? %{$_[0]} : @_; |
|
0
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
|
930
|
0
|
|
0
|
|
|
|
$msg ||= $opt{msg}; |
931
|
0
|
0
|
|
|
|
|
$msg or die 'throw_prompt_ok(): must supply a "msg" as either first arg or named in hash key'; |
932
|
|
|
|
|
|
|
|
933
|
0
|
0
|
|
|
|
|
my $c = RapidApp->active_request_context or die join(' ', |
934
|
|
|
|
|
|
|
'throw_prompt_ok(): this sugar function can only be called from', |
935
|
|
|
|
|
|
|
'within the context of an active request' |
936
|
|
|
|
|
|
|
); |
937
|
|
|
|
|
|
|
|
938
|
0
|
0
|
|
|
|
|
$c->is_ra_ajax_req or die die join(' ', |
939
|
|
|
|
|
|
|
'throw_prompt_ok(): this sugar function can only be called from', |
940
|
|
|
|
|
|
|
'within the context of a RapidApp-generated Ajax request' |
941
|
|
|
|
|
|
|
); |
942
|
|
|
|
|
|
|
|
943
|
0
|
|
|
|
|
|
my %cust_prompt = ( |
944
|
|
|
|
|
|
|
title => 'Confirm', |
945
|
|
|
|
|
|
|
items => { |
946
|
|
|
|
|
|
|
html => $msg |
947
|
|
|
|
|
|
|
}, |
948
|
|
|
|
|
|
|
formpanel_cnf => { |
949
|
|
|
|
|
|
|
defaults => {} |
950
|
|
|
|
|
|
|
}, |
951
|
|
|
|
|
|
|
validate => \1, |
952
|
|
|
|
|
|
|
noCancel => \1, |
953
|
|
|
|
|
|
|
buttons => [ 'Ok', 'Cancel' ], |
954
|
|
|
|
|
|
|
EnterButton => 'Ok', |
955
|
|
|
|
|
|
|
EscButton => 'Cancel', |
956
|
|
|
|
|
|
|
height => 175, |
957
|
|
|
|
|
|
|
width => 350, |
958
|
|
|
|
|
|
|
%opt |
959
|
|
|
|
|
|
|
); |
960
|
|
|
|
|
|
|
|
961
|
0
|
0
|
|
|
|
|
if (my $button = $c->req->header('X-RapidApp-CustomPrompt-Button')){ |
962
|
|
|
|
|
|
|
# $button should contain 'Ok' or 'Cancel' (or whatever values were set in 'buttons') |
963
|
0
|
|
|
|
|
|
return $button; |
964
|
|
|
|
|
|
|
} |
965
|
|
|
|
|
|
|
|
966
|
0
|
|
|
|
|
|
die RapidApp::Responder::CustomPrompt->new(\%cust_prompt); |
967
|
|
|
|
|
|
|
} |
968
|
|
|
|
|
|
|
# ----- |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
########################################################################################## |
974
|
|
|
|
|
|
|
########################################################################################## |
975
|
|
|
|
|
|
|
# |
976
|
|
|
|
|
|
|
# Automatically export all functions defined above: |
977
|
|
|
|
|
|
|
|
978
|
6
|
|
|
6
|
|
60
|
use Class::MOP::Class; |
|
6
|
|
|
|
|
19
|
|
|
6
|
|
|
|
|
1788
|
|
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
my @pkg_methods = grep { ! ($_ =~ /^_/) } ( # Do not export funcs that start with '_' |
981
|
|
|
|
|
|
|
Class::MOP::Class |
982
|
|
|
|
|
|
|
->initialize(__PACKAGE__) |
983
|
|
|
|
|
|
|
->get_method_list |
984
|
|
|
|
|
|
|
); |
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
push @EXPORT_OK, @pkg_methods; |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
# |
989
|
|
|
|
|
|
|
########################################################################################## |
990
|
|
|
|
|
|
|
########################################################################################## |
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
# The same as Catalyst::Utils::home but just a little bit more clever: |
993
|
|
|
|
|
|
|
sub find_app_home { |
994
|
0
|
0
|
0
|
0
|
0
|
|
$_[0] && $_[0] eq __PACKAGE__ and shift; |
995
|
|
|
|
|
|
|
|
996
|
0
|
|
|
|
|
|
require Catalyst::Utils; |
997
|
0
|
|
|
|
|
|
require Module::Locate; |
998
|
|
|
|
|
|
|
|
999
|
0
|
0
|
|
|
|
|
my $class = shift or die "find_app_home(): expected app class name argument"; |
1000
|
|
|
|
|
|
|
|
1001
|
0
|
|
|
|
|
|
my $path = Catalyst::Utils::home($class); |
1002
|
|
|
|
|
|
|
|
1003
|
0
|
0
|
|
|
|
|
unless($path) { |
1004
|
|
|
|
|
|
|
# make an $INC{ $key } style string from the class name |
1005
|
0
|
|
|
|
|
|
(my $file = "$class.pm") =~ s{::}{/}g; |
1006
|
0
|
0
|
|
|
|
|
unless ($INC{$file}) { |
1007
|
0
|
0
|
|
|
|
|
if(my $pm_path = Module::Locate::locate($class)) { |
1008
|
0
|
|
|
|
|
|
local $INC{$file} = $pm_path; |
1009
|
0
|
|
|
|
|
|
$path = Catalyst::Utils::home($class); |
1010
|
|
|
|
|
|
|
} |
1011
|
|
|
|
|
|
|
} |
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
|
1014
|
0
|
|
|
|
|
|
return $path; |
1015
|
|
|
|
|
|
|
} |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
1; |