| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Devel::Optic; |
|
2
|
|
|
|
|
|
|
$Devel::Optic::VERSION = '0.013'; |
|
3
|
|
|
|
|
|
|
# ABSTRACT: Production safe data inspector |
|
4
|
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
269002
|
use strict; |
|
|
2
|
|
|
|
|
8
|
|
|
|
2
|
|
|
|
|
46
|
|
|
6
|
2
|
|
|
2
|
|
9
|
use warnings; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
43
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
2
|
|
|
2
|
|
9
|
use Carp qw(croak); |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
71
|
|
|
9
|
2
|
|
|
2
|
|
9
|
use Scalar::Util qw(looks_like_number); |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
66
|
|
|
10
|
2
|
|
|
2
|
|
822
|
use Ref::Util qw(is_ref is_arrayref is_hashref is_scalarref is_coderef is_regexpref); |
|
|
2
|
|
|
|
|
2652
|
|
|
|
2
|
|
|
|
|
143
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
2
|
|
|
2
|
|
406
|
use Sub::Info qw(sub_info); |
|
|
2
|
|
|
|
|
5645
|
|
|
|
2
|
|
|
|
|
13
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
2
|
|
|
2
|
|
775
|
use PadWalker qw(peek_my); |
|
|
2
|
|
|
|
|
974
|
|
|
|
2
|
|
|
|
|
91
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
2
|
|
|
2
|
|
693
|
use Devel::Optic::Lens::Perlish; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
72
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use constant { |
|
19
|
2
|
|
|
|
|
1315
|
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
|
16492
|
my ($class, %params) = @_; |
|
26
|
9
|
|
100
|
|
|
29
|
my $uplevel = $params{uplevel} // 1; |
|
27
|
|
|
|
|
|
|
|
|
28
|
9
|
100
|
100
|
|
|
51
|
if (!$uplevel || !looks_like_number($uplevel) || $uplevel < 1) { |
|
|
|
|
100
|
|
|
|
|
|
29
|
3
|
|
|
|
|
306
|
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
|
|
|
50
|
lens => $params{lens} // Devel::Optic::Lens::Perlish->new, |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
45
|
|
|
|
|
|
|
}; |
|
46
|
|
|
|
|
|
|
|
|
47
|
6
|
|
|
|
|
15
|
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
|
72
|
my ($self, $subject) = @_; |
|
63
|
|
|
|
|
|
|
|
|
64
|
28
|
|
|
|
|
43
|
my $ref = ref $subject; |
|
65
|
28
|
|
100
|
|
|
121
|
my $reasonably_summarized_with_substr = !is_ref($subject) || is_regexpref($subject) || is_scalarref($subject); |
|
66
|
|
|
|
|
|
|
|
|
67
|
28
|
100
|
|
|
|
47
|
if ($reasonably_summarized_with_substr) { |
|
68
|
9
|
100
|
|
|
|
12
|
if (!defined $subject) { |
|
69
|
1
|
|
|
|
|
4
|
return "(undef)"; |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
|
|
72
|
8
|
100
|
|
|
|
18
|
if ($subject eq "") { |
|
73
|
1
|
|
|
|
|
4
|
return '"" (len 0)'; |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
7
|
100
|
|
|
|
11
|
$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
|
|
|
|
13
|
if ($len <= $scalar_truncation_size) { |
|
87
|
5
|
100
|
|
|
|
46
|
return sprintf( |
|
88
|
|
|
|
|
|
|
"%s%s (len %d)", |
|
89
|
|
|
|
|
|
|
$ref ? "$ref " : "", |
|
90
|
|
|
|
|
|
|
$subject, |
|
91
|
|
|
|
|
|
|
$len, |
|
92
|
|
|
|
|
|
|
); |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
2
|
50
|
|
|
|
49
|
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
|
|
|
|
|
28
|
my $sample_count = $self->{sample_count}; |
|
105
|
19
|
|
|
|
|
22
|
my $scalar_sample_size = $self->{scalar_sample_size}; |
|
106
|
19
|
|
|
|
|
26
|
my $sample_text = "(no sample)"; |
|
107
|
19
|
100
|
|
|
|
37
|
if (is_hashref($subject)) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
108
|
9
|
|
|
|
|
10
|
my @sample; |
|
109
|
9
|
|
|
|
|
56
|
my @keys = keys %$subject; |
|
110
|
9
|
|
|
|
|
12
|
my $key_count = scalar @keys; |
|
111
|
9
|
100
|
|
|
|
29
|
$sample_count = $key_count > $sample_count ? $sample_count : $key_count; |
|
112
|
9
|
|
|
|
|
24
|
my @sample_keys = @keys[0 .. $sample_count - 1]; |
|
113
|
9
|
|
|
|
|
15
|
for my $key (@sample_keys) { |
|
114
|
16
|
|
|
|
|
22
|
my $val = $subject->{$key}; |
|
115
|
16
|
|
|
|
|
16
|
my $val_chunk; |
|
116
|
16
|
100
|
|
|
|
23
|
if (ref $val) { |
|
117
|
4
|
|
|
|
|
5
|
$val_chunk = ref $val; |
|
118
|
|
|
|
|
|
|
} else { |
|
119
|
12
|
|
|
|
|
17
|
$val_chunk = substr($val, 0, $scalar_sample_size); |
|
120
|
12
|
100
|
|
|
|
23
|
$val_chunk .= '...' if length($val_chunk) < length($val); |
|
121
|
|
|
|
|
|
|
} |
|
122
|
16
|
|
|
|
|
20
|
my $key_chunk = substr($key, 0, $scalar_sample_size); |
|
123
|
16
|
100
|
|
|
|
23
|
$key_chunk .= '...' if length($key_chunk) < length($key); |
|
124
|
16
|
|
|
|
|
44
|
push @sample, sprintf("%s => %s", $key_chunk, $val_chunk); |
|
125
|
|
|
|
|
|
|
} |
|
126
|
9
|
100
|
|
|
|
41
|
$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
|
|
|
|
|
9
|
my $total_len = scalar @$subject; |
|
134
|
8
|
100
|
|
|
|
14
|
$sample_count = $total_len > $sample_count ? $sample_count : $total_len; |
|
135
|
8
|
|
|
|
|
15
|
for (my $i = 0; $i < $sample_count; $i++) { |
|
136
|
16
|
|
|
|
|
23
|
my $val = $subject->[$i]; |
|
137
|
16
|
|
|
|
|
19
|
my $val_chunk; |
|
138
|
16
|
100
|
|
|
|
27
|
if (ref $val) { |
|
139
|
4
|
|
|
|
|
5
|
$val_chunk = ref $val; |
|
140
|
|
|
|
|
|
|
} else { |
|
141
|
12
|
|
|
|
|
19
|
$val_chunk = substr($val, 0, $scalar_sample_size); |
|
142
|
12
|
100
|
|
|
|
19
|
$val_chunk .= '...' if length($val_chunk) < length($val); |
|
143
|
|
|
|
|
|
|
} |
|
144
|
16
|
|
|
|
|
33
|
push @sample, $val_chunk; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
8
|
100
|
|
|
|
55
|
$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
|
|
|
|
|
5
|
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
|
|
|
|
|
372
|
); |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
|
|
162
|
19
|
|
|
|
|
169
|
return "$ref: $sample_text"; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
1; |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
__END__ |