line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Devel::Optic; |
2
|
|
|
|
|
|
|
$Devel::Optic::VERSION = '0.014'; |
3
|
|
|
|
|
|
|
# ABSTRACT: Production safe data inspector |
4
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
262341
|
use strict; |
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
48
|
|
6
|
2
|
|
|
2
|
|
8
|
use warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
44
|
|
7
|
|
|
|
|
|
|
|
8
|
2
|
|
|
2
|
|
8
|
use Carp qw(croak); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
74
|
|
9
|
2
|
|
|
2
|
|
8
|
use Scalar::Util qw(looks_like_number); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
76
|
|
10
|
2
|
|
|
2
|
|
813
|
use Ref::Util qw(is_ref is_arrayref is_hashref is_scalarref is_coderef is_regexpref); |
|
2
|
|
|
|
|
2705
|
|
|
2
|
|
|
|
|
183
|
|
11
|
|
|
|
|
|
|
|
12
|
2
|
|
|
2
|
|
646
|
use Sub::Info qw(sub_info); |
|
2
|
|
|
|
|
5965
|
|
|
2
|
|
|
|
|
12
|
|
13
|
|
|
|
|
|
|
|
14
|
2
|
|
|
2
|
|
771
|
use PadWalker qw(peek_my); |
|
2
|
|
|
|
|
1006
|
|
|
2
|
|
|
|
|
94
|
|
15
|
|
|
|
|
|
|
|
16
|
2
|
|
|
2
|
|
707
|
use Devel::Optic::Lens::Perlish; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
69
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use constant { |
19
|
2
|
|
|
|
|
1254
|
DEFAULT_SCALAR_TRUNCATION_SIZE => 256, |
20
|
|
|
|
|
|
|
DEFAULT_SCALAR_SAMPLE_SIZE => 64, |
21
|
|
|
|
|
|
|
DEFAULT_SAMPLE_COUNT => 4, |
22
|
2
|
|
|
2
|
|
10
|
}; |
|
2
|
|
|
|
|
4
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub new { |
25
|
9
|
|
|
9
|
1
|
20130
|
my ($class, %params) = @_; |
26
|
9
|
|
100
|
|
|
34
|
my $uplevel = $params{uplevel} // 1; |
27
|
|
|
|
|
|
|
|
28
|
9
|
100
|
100
|
|
|
48
|
if (!$uplevel || !looks_like_number($uplevel) || $uplevel < 1) { |
|
|
|
100
|
|
|
|
|
29
|
3
|
|
|
|
|
311
|
croak "uplevel should be integer >= 1, not '$uplevel'"; |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
my $self = { |
33
|
|
|
|
|
|
|
uplevel => $uplevel, |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# substr size for scalar subjects |
36
|
|
|
|
|
|
|
scalar_truncation_size => $params{scalar_truncation_size} // DEFAULT_SCALAR_TRUNCATION_SIZE, |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# when building a sample, how much of each scalar child to substr |
39
|
|
|
|
|
|
|
scalar_sample_size => $params{scalar_sample_size} // DEFAULT_SCALAR_SAMPLE_SIZE, |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# how many keys or indicies to display in a sample from a hashref/arrayref |
42
|
|
|
|
|
|
|
sample_count => $params{sample_count} // DEFAULT_SAMPLE_COUNT, |
43
|
|
|
|
|
|
|
|
44
|
6
|
|
100
|
|
|
49
|
lens => $params{lens} // Devel::Optic::Lens::Perlish->new, |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
33
|
|
|
|
|
45
|
|
|
|
|
|
|
}; |
46
|
|
|
|
|
|
|
|
47
|
6
|
|
|
|
|
14
|
bless $self, $class; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub inspect { |
51
|
0
|
|
|
0
|
1
|
0
|
my ($self, $query) = @_; |
52
|
0
|
|
|
|
|
0
|
my $scope = peek_my($self->{uplevel}); |
53
|
0
|
|
|
|
|
0
|
my $full_picture = $self->{lens}->inspect($scope, $query); |
54
|
0
|
|
|
|
|
0
|
return $self->fit_to_view($full_picture); |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# This sub is effectively a very basic serializer. It could probably be made |
58
|
|
|
|
|
|
|
# much more information-dense by adopting strategies from real serializers, or |
59
|
|
|
|
|
|
|
# by incorporating hints from the user on their desired space<->thoroughness |
60
|
|
|
|
|
|
|
# tradeoff. |
61
|
|
|
|
|
|
|
sub fit_to_view { |
62
|
28
|
|
|
28
|
1
|
70
|
my ($self, $subject) = @_; |
63
|
|
|
|
|
|
|
|
64
|
28
|
|
|
|
|
52
|
my $ref = ref $subject; |
65
|
28
|
|
100
|
|
|
161
|
my $reasonably_summarized_with_substr = !is_ref($subject) || is_regexpref($subject) || is_scalarref($subject); |
66
|
|
|
|
|
|
|
|
67
|
28
|
100
|
|
|
|
53
|
if ($reasonably_summarized_with_substr) { |
68
|
9
|
100
|
|
|
|
16
|
if (!defined $subject) { |
69
|
1
|
|
|
|
|
5
|
return "(undef)"; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
8
|
100
|
|
|
|
17
|
if ($subject eq "") { |
73
|
1
|
|
|
|
|
40
|
return '"" (len 0)'; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
7
|
100
|
|
|
|
12
|
$subject = $$subject if is_scalarref($subject); |
77
|
7
|
|
|
|
|
12
|
my $scalar_truncation_size = $self->{scalar_truncation_size}; |
78
|
7
|
|
|
|
|
10
|
my $len = length $subject; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# simple scalars we can truncate (PadWalker always returns refs, so |
81
|
|
|
|
|
|
|
# this is pretty safe from accidentally substr-ing an array or hash). |
82
|
|
|
|
|
|
|
# Also, once we know we're dealing with a gigantic string (or |
83
|
|
|
|
|
|
|
# number...), we can trim much more aggressively without hurting user |
84
|
|
|
|
|
|
|
# understanding too much. |
85
|
|
|
|
|
|
|
|
86
|
7
|
100
|
|
|
|
11
|
if ($len <= $scalar_truncation_size) { |
87
|
5
|
100
|
|
|
|
61
|
return sprintf( |
88
|
|
|
|
|
|
|
"%s%s (len %d)", |
89
|
|
|
|
|
|
|
$ref ? "$ref " : "", |
90
|
|
|
|
|
|
|
$subject, |
91
|
|
|
|
|
|
|
$len, |
92
|
|
|
|
|
|
|
); |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
2
|
50
|
|
|
|
45
|
return sprintf( |
96
|
|
|
|
|
|
|
"%s%s (truncated to len %d; len %d)", |
97
|
|
|
|
|
|
|
$ref ? "$ref " : "", |
98
|
|
|
|
|
|
|
substr($subject, 0, $scalar_truncation_size) . "...", |
99
|
|
|
|
|
|
|
$scalar_truncation_size, |
100
|
|
|
|
|
|
|
$len, |
101
|
|
|
|
|
|
|
); |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
19
|
|
|
|
|
26
|
my $sample_count = $self->{sample_count}; |
105
|
19
|
|
|
|
|
24
|
my $scalar_sample_size = $self->{scalar_sample_size}; |
106
|
19
|
|
|
|
|
24
|
my $sample_text = "(no sample)"; |
107
|
19
|
100
|
|
|
|
38
|
if (is_hashref($subject)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
108
|
9
|
|
|
|
|
10
|
my @sample; |
109
|
9
|
|
|
|
|
58
|
my @keys = keys %$subject; |
110
|
9
|
|
|
|
|
14
|
my $key_count = scalar @keys; |
111
|
9
|
100
|
|
|
|
28
|
$sample_count = $key_count > $sample_count ? $sample_count : $key_count; |
112
|
9
|
|
|
|
|
23
|
my @sample_keys = @keys[0 .. $sample_count - 1]; |
113
|
9
|
|
|
|
|
16
|
for my $key (@sample_keys) { |
114
|
16
|
|
|
|
|
23
|
my $val = $subject->{$key}; |
115
|
16
|
|
|
|
|
17
|
my $val_chunk; |
116
|
16
|
100
|
|
|
|
19
|
if (ref $val) { |
117
|
4
|
|
|
|
|
7
|
$val_chunk = ref $val; |
118
|
|
|
|
|
|
|
} else { |
119
|
12
|
|
|
|
|
19
|
$val_chunk = substr($val, 0, $scalar_sample_size); |
120
|
12
|
100
|
|
|
|
22
|
$val_chunk .= '...' if length($val_chunk) < length($val); |
121
|
|
|
|
|
|
|
} |
122
|
16
|
|
|
|
|
20
|
my $key_chunk = substr($key, 0, $scalar_sample_size); |
123
|
16
|
100
|
|
|
|
67
|
$key_chunk .= '...' if length($key_chunk) < length($key); |
124
|
16
|
|
|
|
|
80
|
push @sample, sprintf("%s => %s", $key_chunk, $val_chunk); |
125
|
|
|
|
|
|
|
} |
126
|
9
|
100
|
|
|
|
46
|
$sample_text = sprintf("{%s%s} (%d keys)", |
127
|
|
|
|
|
|
|
join(', ', @sample), |
128
|
|
|
|
|
|
|
$key_count > $sample_count ? ' ...' : '', |
129
|
|
|
|
|
|
|
$key_count, |
130
|
|
|
|
|
|
|
); |
131
|
|
|
|
|
|
|
} elsif (is_arrayref($subject)) { |
132
|
8
|
|
|
|
|
9
|
my @sample; |
133
|
8
|
|
|
|
|
10
|
my $total_len = scalar @$subject; |
134
|
8
|
100
|
|
|
|
15
|
$sample_count = $total_len > $sample_count ? $sample_count : $total_len; |
135
|
8
|
|
|
|
|
17
|
for (my $i = 0; $i < $sample_count; $i++) { |
136
|
16
|
|
|
|
|
17
|
my $val = $subject->[$i]; |
137
|
16
|
|
|
|
|
22
|
my $val_chunk; |
138
|
16
|
100
|
|
|
|
24
|
if (ref $val) { |
139
|
4
|
|
|
|
|
4
|
$val_chunk = ref $val; |
140
|
|
|
|
|
|
|
} else { |
141
|
12
|
|
|
|
|
17
|
$val_chunk = substr($val, 0, $scalar_sample_size); |
142
|
12
|
100
|
|
|
|
17
|
$val_chunk .= '...' if length($val_chunk) < length($val); |
143
|
|
|
|
|
|
|
} |
144
|
16
|
|
|
|
|
32
|
push @sample, $val_chunk; |
145
|
|
|
|
|
|
|
} |
146
|
8
|
100
|
|
|
|
38
|
$sample_text = sprintf("[%s%s] (len %d)", |
147
|
|
|
|
|
|
|
join(', ', @sample), |
148
|
|
|
|
|
|
|
$total_len > $sample_count ? ' ...' : '', |
149
|
|
|
|
|
|
|
$total_len, |
150
|
|
|
|
|
|
|
); |
151
|
|
|
|
|
|
|
} elsif (is_coderef($subject)) { |
152
|
1
|
|
|
|
|
6
|
my $info = sub_info($subject); |
153
|
|
|
|
|
|
|
$sample_text = sprintf("sub %s { ... } (L%d-%d in %s (%s))", |
154
|
|
|
|
|
|
|
$info->{name}, |
155
|
|
|
|
|
|
|
$info->{start_line}, |
156
|
|
|
|
|
|
|
$info->{end_line}, |
157
|
|
|
|
|
|
|
$info->{package}, |
158
|
|
|
|
|
|
|
$info->{file}, |
159
|
1
|
|
|
|
|
355
|
); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
19
|
|
|
|
|
180
|
return "$ref: $sample_text"; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
1; |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
__END__ |