Filename | /home/hejohns/perl5/lib/perl5/Data/Printer/Object.pm |
Statements | Executed 82 statements in 4.22ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 1.73ms | 1.81ms | BEGIN@3.28 | Data::Printer::
1 | 1 | 1 | 1.42ms | 1.50ms | BEGIN@61 | Data::Printer::Object::
1 | 1 | 1 | 885µs | 930µs | BEGIN@51 | Data::Printer::Object::
1 | 1 | 1 | 538µs | 619µs | BEGIN@54 | Data::Printer::Object::
1 | 1 | 1 | 538µs | 913µs | BEGIN@52 | Data::Printer::Object::
1 | 1 | 1 | 400µs | 459µs | BEGIN@53 | Data::Printer::Object::
1 | 1 | 1 | 358µs | 588µs | BEGIN@57 | Data::Printer::Object::
1 | 1 | 1 | 337µs | 525µs | BEGIN@60 | Data::Printer::Object::
1 | 1 | 1 | 227µs | 296µs | BEGIN@56 | Data::Printer::Object::
1 | 1 | 1 | 224µs | 279µs | BEGIN@59 | Data::Printer::Object::
1 | 1 | 1 | 197µs | 251µs | BEGIN@55 | Data::Printer::Object::
1 | 1 | 1 | 125µs | 180µs | BEGIN@58 | Data::Printer::Object::
1 | 1 | 1 | 9µs | 14µs | BEGIN@76 | Data::Printer::Object::
1 | 1 | 1 | 6µs | 7µs | BEGIN@1 | Data::Printer::
11 | 11 | 1 | 4µs | 4µs | __ANON__ (xsub) | Data::Printer::Object::
1 | 1 | 1 | 3µs | 12µs | BEGIN@2.27 | Data::Printer::
1 | 1 | 1 | 2µs | 2µs | BEGIN@50 | Data::Printer::Object::
4 | 4 | 2 | 2µs | 2µs | __ANON__ (xsub) | Data::Printer::
0 | 0 | 0 | 0s | 0s | expand | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | format_inheritance | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | inherited | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | internals | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | linear_isa | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | new | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | parent_filters | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | parents | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | show_methods | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | show_overloads | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | show_reftype | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | show_wrapped | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | sort_methods | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | stringify | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | universal | Data::Printer::Object::ClassOptions::
0 | 0 | 0 | 0s | 0s | __ANON__[:728] | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | __ANON__[:80] | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _check_memsize | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _check_readonly | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _check_weak | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _detect_color_level | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _filters_for_class | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _filters_for_data | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _filters_for_type | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _init | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _load_colors | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _load_external_filter | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _load_filters | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _load_output_handle | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _refcount | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _see | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | _write_label | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | current_depth | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | current_name | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | extra_config | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | fulldump | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | indent | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | maybe_colorize | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | multiline | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | new | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | newline | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | outdent | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | output | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | parse | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | parse_as | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | seen | Data::Printer::Object::
0 | 0 | 0 | 0s | 0s | unsee | Data::Printer::Object::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | 2 | 14µs | 2 | 8µs | # spent 7µs (6+1000ns) within Data::Printer::BEGIN@1 which was called:
# once (6µs+1000ns) by Data::Printer::BEGIN@4 at line 1 # spent 7µs making 1 call to Data::Printer::BEGIN@1
# spent 1µs making 1 call to strict::import |
2 | 2 | 16µs | 2 | 21µs | # spent 12µs (3+9) within Data::Printer::BEGIN@2.27 which was called:
# once (3µs+9µs) by Data::Printer::BEGIN@4 at line 2 # spent 12µs making 1 call to Data::Printer::BEGIN@2.27
# spent 9µs making 1 call to warnings::import |
3 | 2 | 295µs | 2 | 1.81ms | # spent 1.81ms (1.73+75µs) within Data::Printer::BEGIN@3.28 which was called:
# once (1.73ms+75µs) by Data::Printer::BEGIN@4 at line 3 # spent 1.81ms making 1 call to Data::Printer::BEGIN@3.28
# spent 500ns making 1 call to Data::Printer::__ANON__ |
4 | |||||
5 | package # hide from pause | ||||
6 | Data::Printer::Object::ClassOptions; | ||||
7 | sub parents { $_[0]->{'parents'} } | ||||
8 | sub linear_isa { $_[0]->{'linear_isa'} } | ||||
9 | sub universal { $_[0]->{'universal'} } | ||||
10 | sub expand { $_[0]->{'expand'} } | ||||
11 | sub stringify { $_[0]->{'stringify'} } | ||||
12 | sub show_reftype { $_[0]->{'show_reftype'} } | ||||
13 | sub show_overloads { $_[0]->{'show_overloads'} } | ||||
14 | sub show_methods { $_[0]->{'show_methods'} } | ||||
15 | sub sort_methods { $_[0]->{'sort_methods'} } | ||||
16 | sub show_wrapped { $_[0]->{'show_wrapped'} } | ||||
17 | sub inherited { $_[0]->{'inherited'} } | ||||
18 | sub format_inheritance { $_[0]->{'format_inheritance'} } | ||||
19 | sub parent_filters { $_[0]->{'parent_filters'} } | ||||
20 | sub internals { $_[0]->{'internals'} } | ||||
21 | sub new { | ||||
22 | my ($class, $params) = @_; | ||||
23 | my $self = { | ||||
24 | 'linear_isa' => Data::Printer::Common::_fetch_scalar_or_default($params, 'linear_isa', 'auto'), | ||||
25 | 'show_reftype' => Data::Printer::Common::_fetch_scalar_or_default($params, 'show_reftype', 0), | ||||
26 | 'show_overloads' => Data::Printer::Common::_fetch_scalar_or_default($params, 'show_overloads', 1), | ||||
27 | 'stringify' => Data::Printer::Common::_fetch_scalar_or_default($params, 'stringify', 1), | ||||
28 | 'expand' => Data::Printer::Common::_fetch_scalar_or_default($params, 'expand', 1), | ||||
29 | 'show_methods' => Data::Printer::Common::_fetch_anyof( | ||||
30 | $params, 'show_methods', 'all', [qw(none all private public)] | ||||
31 | ), | ||||
32 | 'inherited' => Data::Printer::Common::_fetch_anyof( | ||||
33 | $params, 'inherited', 'public', [qw(none all private public)] | ||||
34 | ), | ||||
35 | 'format_inheritance' => Data::Printer::Common::_fetch_anyof( | ||||
36 | $params, 'format_inheritance', 'lines', [qw(string lines)] | ||||
37 | ), | ||||
38 | 'parent_filters' => Data::Printer::Common::_fetch_scalar_or_default($params, 'parent_filters', 1), | ||||
39 | 'universal' => Data::Printer::Common::_fetch_scalar_or_default($params, 'universal', 0), | ||||
40 | 'sort_methods' => Data::Printer::Common::_fetch_scalar_or_default($params, 'sort_methods', 1), | ||||
41 | 'show_wrapped' => Data::Printer::Common::_fetch_scalar_or_default($params, 'show_wrapped', 1), | ||||
42 | 'internals' => Data::Printer::Common::_fetch_scalar_or_default($params, 'internals', 1), | ||||
43 | 'parents' => Data::Printer::Common::_fetch_scalar_or_default($params, 'parents', 1), | ||||
44 | }; | ||||
45 | return bless $self, $class; | ||||
46 | } | ||||
47 | 1; | ||||
48 | |||||
49 | package Data::Printer::Object; | ||||
50 | 2 | 15µs | 1 | 2µs | # spent 2µs within Data::Printer::Object::BEGIN@50 which was called:
# once (2µs+0s) by Data::Printer::BEGIN@4 at line 50 # spent 2µs making 1 call to Data::Printer::Object::BEGIN@50 |
51 | 2 | 88µs | 2 | 931µs | # spent 930µs (885+45) within Data::Printer::Object::BEGIN@51 which was called:
# once (885µs+45µs) by Data::Printer::BEGIN@4 at line 51 # spent 930µs making 1 call to Data::Printer::Object::BEGIN@51
# spent 700ns making 1 call to Data::Printer::Object::__ANON__ |
52 | 2 | 83µs | 2 | 913µs | # spent 913µs (538+376) within Data::Printer::Object::BEGIN@52 which was called:
# once (538µs+376µs) by Data::Printer::BEGIN@4 at line 52 # spent 913µs making 1 call to Data::Printer::Object::BEGIN@52
# spent 300ns making 1 call to Data::Printer::Object::__ANON__ |
53 | 2 | 75µs | 2 | 459µs | # spent 459µs (400+59) within Data::Printer::Object::BEGIN@53 which was called:
# once (400µs+59µs) by Data::Printer::BEGIN@4 at line 53 # spent 459µs making 1 call to Data::Printer::Object::BEGIN@53
# spent 300ns making 1 call to Data::Printer::Object::__ANON__ |
54 | 2 | 88µs | 2 | 619µs | # spent 619µs (538+81) within Data::Printer::Object::BEGIN@54 which was called:
# once (538µs+81µs) by Data::Printer::BEGIN@4 at line 54 # spent 619µs making 1 call to Data::Printer::Object::BEGIN@54
# spent 300ns making 1 call to Data::Printer::Object::__ANON__ |
55 | 2 | 97µs | 2 | 252µs | # spent 251µs (197+54) within Data::Printer::Object::BEGIN@55 which was called:
# once (197µs+54µs) by Data::Printer::BEGIN@4 at line 55 # spent 251µs making 1 call to Data::Printer::Object::BEGIN@55
# spent 300ns making 1 call to Data::Printer::Object::__ANON__ |
56 | 2 | 87µs | 2 | 297µs | # spent 296µs (227+69) within Data::Printer::Object::BEGIN@56 which was called:
# once (227µs+69µs) by Data::Printer::BEGIN@4 at line 56 # spent 296µs making 1 call to Data::Printer::Object::BEGIN@56
# spent 700ns making 1 call to Data::Printer::Object::__ANON__ |
57 | 2 | 85µs | 2 | 588µs | # spent 588µs (358+230) within Data::Printer::Object::BEGIN@57 which was called:
# once (358µs+230µs) by Data::Printer::BEGIN@4 at line 57 # spent 588µs making 1 call to Data::Printer::Object::BEGIN@57
# spent 300ns making 1 call to Data::Printer::Object::__ANON__ |
58 | 2 | 74µs | 2 | 180µs | # spent 180µs (125+55) within Data::Printer::Object::BEGIN@58 which was called:
# once (125µs+55µs) by Data::Printer::BEGIN@4 at line 58 # spent 180µs making 1 call to Data::Printer::Object::BEGIN@58
# spent 300ns making 1 call to Data::Printer::Object::__ANON__ |
59 | 2 | 69µs | 2 | 279µs | # spent 279µs (224+55) within Data::Printer::Object::BEGIN@59 which was called:
# once (224µs+55µs) by Data::Printer::BEGIN@4 at line 59 # spent 279µs making 1 call to Data::Printer::Object::BEGIN@59
# spent 300ns making 1 call to Data::Printer::Object::__ANON__ |
60 | 2 | 74µs | 2 | 526µs | # spent 525µs (337+189) within Data::Printer::Object::BEGIN@60 which was called:
# once (337µs+189µs) by Data::Printer::BEGIN@4 at line 60 # spent 525µs making 1 call to Data::Printer::Object::BEGIN@60
# spent 300ns making 1 call to Data::Printer::Object::__ANON__ |
61 | 2 | 124µs | 2 | 1.50ms | # spent 1.50ms (1.42+72µs) within Data::Printer::Object::BEGIN@61 which was called:
# once (1.42ms+72µs) by Data::Printer::BEGIN@4 at line 61 # spent 1.50ms making 1 call to Data::Printer::Object::BEGIN@61
# spent 400ns making 1 call to Data::Printer::Object::__ANON__ |
62 | |||||
63 | # create our basic accessors: | ||||
64 | 1 | 4µs | my @method_names =qw( | ||
65 | name show_tainted show_unicode show_readonly show_lvalue show_refcount | ||||
66 | show_memsize memsize_unit print_escapes scalar_quotes escape_chars | ||||
67 | caller_info caller_message caller_message_newline caller_message_position | ||||
68 | string_max string_overflow string_preserve resolve_scalar_refs | ||||
69 | array_max array_overflow array_preserve hash_max hash_overflow | ||||
70 | hash_preserve unicode_charnames colored theme show_weak | ||||
71 | max_depth index separator end_separator class_method class hash_separator | ||||
72 | align_hash sort_keys quote_keys deparse return_value show_dualvar show_tied | ||||
73 | warnings arrows coderef_stub coderef_undefined | ||||
74 | ); | ||||
75 | 1 | 300ns | foreach my $method_name (@method_names) { | ||
76 | 2 | 2.86ms | 2 | 19µs | # spent 14µs (9+5) within Data::Printer::Object::BEGIN@76 which was called:
# once (9µs+5µs) by Data::Printer::BEGIN@4 at line 76 # spent 14µs making 1 call to Data::Printer::Object::BEGIN@76
# spent 5µs making 1 call to strict::unimport |
77 | *{__PACKAGE__ . "::$method_name"} = sub { | ||||
78 | $_[0]->{$method_name} = $_[1] if @_ > 1; | ||||
79 | return $_[0]->{$method_name}; | ||||
80 | } | ||||
81 | 47 | 69µs | } | ||
82 | sub extra_config { $_[0]->{extra_config} } | ||||
83 | |||||
84 | sub current_depth { $_[0]->{_depth} } | ||||
85 | sub indent { $_[0]->{_depth}++ } | ||||
86 | sub outdent { $_[0]->{_depth}-- } | ||||
87 | |||||
88 | sub newline { | ||||
89 | my ($self) = @_; | ||||
90 | return $self->{_linebreak} | ||||
91 | . (' ' x ($self->{_depth} * $self->{_current_indent})) | ||||
92 | . (' ' x $self->{_array_padding}) | ||||
93 | ; | ||||
94 | } | ||||
95 | |||||
96 | sub current_name { | ||||
97 | my ($self, $new_value) = @_; | ||||
98 | if (defined $new_value) { | ||||
99 | $self->{_current_name} = $new_value; | ||||
100 | } | ||||
101 | else { | ||||
102 | $self->{_current_name} = $self->name unless defined $self->{_current_name}; | ||||
103 | } | ||||
104 | return $self->{_current_name}; | ||||
105 | } | ||||
106 | |||||
107 | sub _init { | ||||
108 | my $self = shift; | ||||
109 | my $props = { @_ == 1 ? %{$_[0]} : @_ }; | ||||
110 | |||||
111 | $self->{'_linebreak'} = "\n"; | ||||
112 | $self->{'_depth'} = 0; | ||||
113 | $self->{'_position'} = 0; # depth is for indentation only! | ||||
114 | $self->{'_array_padding'} = 0; | ||||
115 | $self->{'_seen'} = {}; | ||||
116 | $self->{_refcount_base} = 3; | ||||
117 | $self->{'warnings'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'warning', 1); | ||||
118 | $self->{'indent'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'indent', 4); | ||||
119 | $self->{'index'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'index', 1); | ||||
120 | $self->{'name'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'name', 'var'); | ||||
121 | $self->{'arrows'} = Data::Printer::Common::_fetch_anyof( | ||||
122 | $props, | ||||
123 | 'arrows', | ||||
124 | 'none', | ||||
125 | [qw(none first all)] | ||||
126 | ); | ||||
127 | |||||
128 | $self->{'show_tainted'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'show_tainted', 1); | ||||
129 | $self->{'show_tied'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'show_tied', 1); | ||||
130 | $self->{'show_weak'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'show_weak', 1); | ||||
131 | $self->{'show_unicode'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'show_unicode', 0); | ||||
132 | $self->{'show_readonly'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'show_readonly', 1); | ||||
133 | $self->{'show_lvalue'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'show_lvalue', 1); | ||||
134 | $self->{'show_refcount'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'show_refcount', 0); | ||||
135 | $self->{'show_memsize'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'show_memsize', 0); | ||||
136 | $self->{'memsize_unit'} = Data::Printer::Common::_fetch_anyof( | ||||
137 | $props, | ||||
138 | 'memsize_unit', | ||||
139 | 'auto', | ||||
140 | [qw(auto b k m)] | ||||
141 | ); | ||||
142 | $self->{'print_escapes'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'print_escapes', 0); | ||||
143 | $self->{'scalar_quotes'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'scalar_quotes', q(")); | ||||
144 | $self->{'escape_chars'} = Data::Printer::Common::_fetch_anyof( | ||||
145 | $props, | ||||
146 | 'escape_chars', | ||||
147 | 'none', | ||||
148 | [qw(none nonascii nonlatin1 all)] | ||||
149 | ); | ||||
150 | $self->{'caller_info'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'caller_info', 0); | ||||
151 | $self->{'caller_message'} = Data::Printer::Common::_fetch_scalar_or_default( | ||||
152 | $props, | ||||
153 | 'caller_message', | ||||
154 | 'Printing in line __LINE__ of __FILENAME__:' | ||||
155 | ); | ||||
156 | $self->{'caller_message_newline'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'caller_message_newline', 1); | ||||
157 | $self->{'caller_message_position'} = Data::Printer::Common::_fetch_anyof($props, 'caller_message_position', 'before', [qw(before after)]); | ||||
158 | $self->{'resolve_scalar_refs'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'resolve_scalar_refs', 0); | ||||
159 | $self->{'string_max'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'string_max', 4096); | ||||
160 | $self->{'string_preserve'} = Data::Printer::Common::_fetch_anyof( | ||||
161 | $props, | ||||
162 | 'string_preserve', | ||||
163 | 'begin', | ||||
164 | [qw(begin end middle extremes none)] | ||||
165 | ); | ||||
166 | $self->{'string_overflow'} = Data::Printer::Common::_fetch_scalar_or_default( | ||||
167 | $props, | ||||
168 | 'string_overflow', | ||||
169 | '(...skipping __SKIPPED__ chars...)' | ||||
170 | ); | ||||
171 | $self->{'array_max'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'array_max', 100); | ||||
172 | $self->{'array_preserve'} = Data::Printer::Common::_fetch_anyof( | ||||
173 | $props, | ||||
174 | 'array_preserve', | ||||
175 | 'begin', | ||||
176 | [qw(begin end middle extremes none)] | ||||
177 | ); | ||||
178 | $self->{'array_overflow'} = Data::Printer::Common::_fetch_scalar_or_default( | ||||
179 | $props, | ||||
180 | 'array_overflow', | ||||
181 | '(...skipping __SKIPPED__ items...)' | ||||
182 | ); | ||||
183 | $self->{'hash_max'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'hash_max', 100); | ||||
184 | $self->{'hash_preserve'} = Data::Printer::Common::_fetch_anyof( | ||||
185 | $props, | ||||
186 | 'hash_preserve', | ||||
187 | 'begin', | ||||
188 | [qw(begin end middle extremes none)] | ||||
189 | ); | ||||
190 | $self->{'hash_overflow'} = Data::Printer::Common::_fetch_scalar_or_default( | ||||
191 | $props, | ||||
192 | 'hash_overflow', | ||||
193 | '(...skipping __SKIPPED__ keys...)' | ||||
194 | ); | ||||
195 | $self->{'unicode_charnames'} = Data::Printer::Common::_fetch_scalar_or_default( | ||||
196 | $props, | ||||
197 | 'unicode_charnames', | ||||
198 | 0 | ||||
199 | ); | ||||
200 | $self->{'colored'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'colored', 'auto'); | ||||
201 | $self->{'max_depth'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'max_depth', 0); | ||||
202 | $self->{'separator'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'separator', ','); | ||||
203 | $self->{'end_separator'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'end_separator', 0); | ||||
204 | $self->{'class_method'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'class_method', '_data_printer'); | ||||
205 | $self->{'class'} = Data::Printer::Object::ClassOptions->new($props->{'class'}); | ||||
206 | $self->{'hash_separator'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'hash_separator', ' '); | ||||
207 | $self->{'align_hash'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'align_hash', 1); | ||||
208 | $self->{'sort_keys'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'sort_keys', 1); | ||||
209 | $self->{'quote_keys'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'quote_keys', 'auto'); | ||||
210 | $self->{'deparse'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'deparse', 0); | ||||
211 | $self->{'coderef_stub'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'coderef_stub', 'sub { ... }'); | ||||
212 | $self->{'coderef_undefined'} = Data::Printer::Common::_fetch_scalar_or_default($props, 'coderef_undefined', '<undefined coderef>'); | ||||
213 | $self->{'return_value'} = Data::Printer::Common::_fetch_anyof( | ||||
214 | $props, | ||||
215 | 'return_value', | ||||
216 | 'pass', | ||||
217 | [qw(pass dump void)] | ||||
218 | ); | ||||
219 | $self->{'show_dualvar'} = Data::Printer::Common::_fetch_anyof( | ||||
220 | $props, | ||||
221 | 'show_dualvar', | ||||
222 | 'lax', | ||||
223 | [qw(lax strict off)] | ||||
224 | ); | ||||
225 | |||||
226 | if (exists $props->{as}) { | ||||
227 | my $msg = Data::Printer::Common::_fetch_scalar_or_default($props, 'as', ''); | ||||
228 | $self->{caller_info} = 1; | ||||
229 | $self->{caller_message} = $msg; | ||||
230 | } | ||||
231 | |||||
232 | $self->multiline( | ||||
233 | Data::Printer::Common::_fetch_scalar_or_default($props, 'multiline', 1) | ||||
234 | ); | ||||
235 | |||||
236 | $self->fulldump( | ||||
237 | Data::Printer::Common::_fetch_scalar_or_default($props, 'fulldump', 0) | ||||
238 | ); | ||||
239 | |||||
240 | $self->output(defined $props->{output} ? $props->{output} : 'stderr'); | ||||
241 | $self->_load_colors($props); | ||||
242 | $self->_load_filters($props); | ||||
243 | |||||
244 | my %extra_config; | ||||
245 | my %core_options = map { $_ => 1 } | ||||
246 | (@method_names, qw(as multiline output colors filters)); | ||||
247 | foreach my $key (keys %$props) { | ||||
248 | $extra_config{$key} = $props->{$key} unless exists $core_options{$key}; | ||||
249 | } | ||||
250 | $self->{extra_config} = \%extra_config; | ||||
251 | |||||
252 | return $self; | ||||
253 | } | ||||
254 | |||||
255 | sub output { | ||||
256 | my ($self, $new_output) = @_; | ||||
257 | if (@_ > 1) { | ||||
258 | $self->_load_output_handle($new_output); | ||||
259 | } | ||||
260 | return $self->{output}; | ||||
261 | } | ||||
262 | |||||
263 | sub _load_output_handle { | ||||
264 | my ($self, $output) = @_; | ||||
265 | my %targets = ( stdout => *STDOUT, stderr => *STDERR ); | ||||
266 | my $error; | ||||
267 | my $ref = ref $output; | ||||
268 | if (!$ref and exists $targets{ lc $output }) { | ||||
269 | $self->{output} = lc $output; | ||||
270 | $self->{output_handle} = $targets{ $self->{output} }; | ||||
271 | } | ||||
272 | elsif ( ( $ref and $ref eq 'GLOB') | ||||
273 | or (!$ref and \$output =~ /GLOB\([^()]+\)$/) | ||||
274 | ) { | ||||
275 | $self->{output} = 'handle'; | ||||
276 | $self->{output_handle} = $output; | ||||
277 | } | ||||
278 | elsif (!$ref or $ref eq 'SCALAR') { | ||||
279 | if (open my $fh, '>>', $output) { | ||||
280 | $self->{output} = 'file'; | ||||
281 | $self->{output_handle} = $fh; | ||||
282 | } | ||||
283 | else { | ||||
284 | $error = "file '$output': $!"; | ||||
285 | } | ||||
286 | } | ||||
287 | else { | ||||
288 | $error = 'unknown output data'; | ||||
289 | } | ||||
290 | if ($error) { | ||||
291 | Data::Printer::Common::_warn($self, "error opening custom output handle: $error"); | ||||
292 | $self->{output_handle} = $targets{'stderr'} | ||||
293 | } | ||||
294 | return; | ||||
295 | } | ||||
296 | |||||
297 | sub new { | ||||
298 | my $class = shift; | ||||
299 | my $self = bless {}, $class; | ||||
300 | return $self->_init(@_); | ||||
301 | } | ||||
302 | |||||
303 | sub multiline { | ||||
304 | my ($self, $value) = @_; | ||||
305 | if (defined $value) { | ||||
306 | $self->{multiline} = !!$value; | ||||
307 | if ($value) { | ||||
308 | $self->{_linebreak} = "\n"; | ||||
309 | $self->{_current_indent} = $self->{indent}; | ||||
310 | $self->index( $self->{_original_index} ) | ||||
311 | if exists $self->{_original_index}; | ||||
312 | $self->hash_separator( $self->{_original_separator} ) | ||||
313 | if exists $self->{_original_separator}; | ||||
314 | $self->array_overflow( $self->{_original_array_overflow} ) | ||||
315 | if exists $self->{_original_array_overflow}; | ||||
316 | $self->hash_overflow( $self->{_original_hash_overflow} ) | ||||
317 | if exists $self->{_original_hash_overflow}; | ||||
318 | $self->string_overflow( $self->{_original_string_overflow} ) | ||||
319 | if exists $self->{_original_string_overflow}; | ||||
320 | } | ||||
321 | else { | ||||
322 | $self->{_original_index} = $self->index; | ||||
323 | $self->index(0); | ||||
324 | $self->{_original_separator} = $self->hash_separator; | ||||
325 | $self->hash_separator(':'); | ||||
326 | $self->{_original_array_overflow} = $self->array_overflow; | ||||
327 | $self->array_overflow('(...)'); | ||||
328 | $self->{_original_hash_overflow} = $self->hash_overflow; | ||||
329 | $self->hash_overflow('(...)'); | ||||
330 | $self->{_original_string_overflow} = $self->string_overflow; | ||||
331 | $self->string_overflow('(...)'); | ||||
332 | $self->{_linebreak} = ' '; | ||||
333 | $self->{_current_indent} = 0; | ||||
334 | } | ||||
335 | } | ||||
336 | return $self->{multiline}; | ||||
337 | } | ||||
338 | |||||
339 | sub fulldump { | ||||
340 | my ($self, $value) = @_; | ||||
341 | if (defined $value) { | ||||
342 | $self->{fulldump} = !!$value; | ||||
343 | if ($value) { | ||||
344 | $self->{_original_string_max} = $self->string_max; | ||||
345 | $self->string_max(0); | ||||
346 | $self->{_original_array_max} = $self->array_max; | ||||
347 | $self->array_max(0); | ||||
348 | $self->{_original_hash_max} = $self->hash_max; | ||||
349 | $self->hash_max(0); | ||||
350 | } | ||||
351 | else { | ||||
352 | $self->string_max($self->{_original_string_max}) | ||||
353 | if exists $self->{_original_string_max}; | ||||
354 | $self->array_max($self->{_original_array_max}) | ||||
355 | if exists $self->{_original_array_max}; | ||||
356 | $self->hash_max($self->{_original_hash_max}) | ||||
357 | if exists $self->{_original_hash_max}; | ||||
358 | } | ||||
359 | } | ||||
360 | } | ||||
361 | |||||
362 | sub _load_filters { | ||||
363 | my ($self, $props) = @_; | ||||
364 | |||||
365 | # load our core filters (LVALUE is under the 'SCALAR' filter module) | ||||
366 | my @core_filters = qw(SCALAR ARRAY HASH REF VSTRING GLOB FORMAT Regexp CODE GenericClass); | ||||
367 | foreach my $class (@core_filters) { | ||||
368 | $self->_load_external_filter($class); | ||||
369 | } | ||||
370 | my @filters; | ||||
371 | # load any custom filters provided by the user | ||||
372 | if (exists $props->{filters}) { | ||||
373 | if (ref $props->{filters} eq 'HASH') { | ||||
374 | Data::Printer::Common::_warn( | ||||
375 | $self, | ||||
376 | 'please update your code: filters => { ... } is now filters => [{ ... }]' | ||||
377 | ); | ||||
378 | push @filters, $props->{filters}; | ||||
379 | } | ||||
380 | elsif (ref $props->{filters} eq 'ARRAY') { | ||||
381 | @filters = @{ $props->{filters} }; | ||||
382 | } | ||||
383 | else { | ||||
384 | Data::Printer::Common::_warn($self, 'filters must be an ARRAY reference'); | ||||
385 | } | ||||
386 | } | ||||
387 | foreach my $filter (@filters) { | ||||
388 | my $filter_reftype = Scalar::Util::reftype($filter); | ||||
389 | if (!defined $filter_reftype) { | ||||
390 | $self->_load_external_filter($filter); | ||||
391 | } | ||||
392 | elsif ($filter_reftype eq 'HASH') { | ||||
393 | foreach my $k (keys %$filter) { | ||||
394 | if ($k eq '-external') { | ||||
395 | Data::Printer::Common::_warn( | ||||
396 | $self, | ||||
397 | 'please update your code: ' | ||||
398 | . 'filters => { -external => [qw(Foo Bar)}' | ||||
399 | . ' is now filters => [qw(Foo Bar)]' | ||||
400 | ); | ||||
401 | next; | ||||
402 | } | ||||
403 | if (Scalar::Util::reftype($filter->{$k}) eq 'CODE') { | ||||
404 | my $type = Data::Printer::Common::_filter_category_for($k); | ||||
405 | unshift @{ $self->{$type}{$k} }, $filter->{$k}; | ||||
406 | } | ||||
407 | else { | ||||
408 | Data::Printer::Common::_warn( | ||||
409 | $self, | ||||
410 | 'hash filters must point to a CODE reference' | ||||
411 | ); | ||||
412 | } | ||||
413 | } | ||||
414 | } | ||||
415 | else { | ||||
416 | Data::Printer::Common::_warn($self, 'filters must be a name or { type => sub {...} }'); | ||||
417 | } | ||||
418 | } | ||||
419 | return; | ||||
420 | } | ||||
421 | |||||
422 | sub _load_external_filter { | ||||
423 | my ($self, $class) = @_; | ||||
424 | my $module = "Data::Printer::Filter::$class"; | ||||
425 | my $error = Data::Printer::Common::_tryme("use $module; 1;"); | ||||
426 | if ($error) { | ||||
427 | Data::Printer::Common::_warn($self, "error loading filter '$class': $error"); | ||||
428 | return; | ||||
429 | } | ||||
430 | my $from_module = $module->_filter_list; | ||||
431 | foreach my $kind (keys %$from_module) { | ||||
432 | foreach my $name (keys %{$from_module->{$kind}}) { | ||||
433 | unshift @{ $self->{$kind}{$name} }, @{ $from_module->{$kind}{$name} }; | ||||
434 | } | ||||
435 | } | ||||
436 | return; | ||||
437 | } | ||||
438 | |||||
439 | sub _detect_color_level { | ||||
440 | my ($self) = @_; | ||||
441 | my $colored = $self->colored; | ||||
442 | my $color_level; | ||||
443 | |||||
444 | # first we honour ANSI_COLORS_DISABLED, colored and writing to files | ||||
445 | if ( !$colored | ||||
446 | || ($colored eq 'auto' | ||||
447 | && (exists $ENV{ANSI_COLORS_DISABLED} | ||||
448 | || $self->output eq 'handle' | ||||
449 | || $self->output eq 'file' | ||||
450 | ) | ||||
451 | ) | ||||
452 | ) { | ||||
453 | $color_level = 0; | ||||
454 | } | ||||
455 | else { | ||||
456 | # NOTE: we could try `tput colors` but it may not give | ||||
457 | # the proper result, so instead we do what most terminals | ||||
458 | # currently do and rely on environment variables. | ||||
459 | if ($ENV{COLORTERM} && $ENV{COLORTERM} eq 'truecolor') { | ||||
460 | $color_level = 3; | ||||
461 | } | ||||
462 | elsif ($ENV{TERM_PROGRAM} && $ENV{TERM_PROGRAM} eq 'iTerm.app') { | ||||
463 | my $major_version = substr($ENV{TERM_PROGRAM_VERSION} || '0', 0, 1); | ||||
464 | $color_level = $major_version >= 3 ? 3 : 2; | ||||
465 | } | ||||
466 | elsif ($ENV{TERM_PROGRAM} && $ENV{TERM_PROGRAM} eq 'Apple_Terminal') { | ||||
467 | $color_level= 2; | ||||
468 | } | ||||
469 | elsif ($ENV{TERM} && $ENV{TERM} =~ /\-256(?:color)?\z/i) { | ||||
470 | $color_level = 2; | ||||
471 | } | ||||
472 | elsif ($ENV{TERM} | ||||
473 | && ($ENV{TERM} =~ /\A(?:screen|xterm|vt100|rxvt)/i | ||||
474 | || $ENV{TERM} =~ /color|ansi|cygwin|linux/i) | ||||
475 | ) { | ||||
476 | $color_level = 1; | ||||
477 | } | ||||
478 | elsif ($ENV{COLORTERM}) { | ||||
479 | $color_level = 1; | ||||
480 | } | ||||
481 | else { | ||||
482 | $color_level = $colored eq 'auto' ? 0 : 1; | ||||
483 | } | ||||
484 | } | ||||
485 | return $color_level; | ||||
486 | } | ||||
487 | |||||
488 | sub _load_colors { | ||||
489 | my ($self, $props) = @_; | ||||
490 | |||||
491 | $self->{_output_color_level} = $self->_detect_color_level; | ||||
492 | |||||
493 | my $theme_object; | ||||
494 | my $default_theme = 'Material'; | ||||
495 | my $theme_name = Data::Printer::Common::_fetch_scalar_or_default($props, 'theme', $default_theme); | ||||
496 | $theme_object = Data::Printer::Theme->new( | ||||
497 | name => $theme_name, | ||||
498 | color_overrides => $props->{colors}, | ||||
499 | color_level => $self->{_output_color_level}, | ||||
500 | ddp => $self, | ||||
501 | ); | ||||
502 | if (!$theme_object) { | ||||
503 | if ($theme_name ne $default_theme) { | ||||
504 | $theme_object = Data::Printer::Theme->new( | ||||
505 | name => $default_theme, | ||||
506 | color_overrides => $props->{colors}, | ||||
507 | color_level => $self->{_output_color_level}, | ||||
508 | ddp => $self, | ||||
509 | ); | ||||
510 | } | ||||
511 | Data::Printer::Common::_die("Unable to load default theme. This should never happen - please contact the author") unless $theme_object; | ||||
512 | } | ||||
513 | $self->{theme} = $theme_object; | ||||
514 | } | ||||
515 | |||||
516 | sub _filters_for_type { | ||||
517 | my ($self, $type) = @_; | ||||
518 | return exists $self->{type_filters}{$type} ? @{ $self->{type_filters}{$type} } : (); | ||||
519 | } | ||||
520 | |||||
521 | sub _filters_for_class { | ||||
522 | my ($self, $type) = @_; | ||||
523 | return exists $self->{class_filters}{$type} ? @{ $self->{class_filters}{$type} } : (); | ||||
524 | } | ||||
525 | |||||
526 | sub _filters_for_data { | ||||
527 | my ($self, $data) = @_; | ||||
528 | |||||
529 | # we favour reftype() over ref() because you could have | ||||
530 | # a HASH.pm (or ARRAY.pm or whatever) blessing any variable. | ||||
531 | my $ref_kind = Scalar::Util::reftype($data); | ||||
532 | $ref_kind = 'SCALAR' unless $ref_kind; | ||||
533 | |||||
534 | # ref() returns 'Regexp' but reftype() returns 'REGEXP', so we picked one: | ||||
535 | $ref_kind = 'Regexp' if $ref_kind eq 'REGEXP'; | ||||
536 | |||||
537 | my @potential_filters; | ||||
538 | |||||
539 | # first, try class name + full inheritance for a specific name. | ||||
540 | my $class = Scalar::Util::blessed($data); | ||||
541 | |||||
542 | # a regular regexp is blessed, but in that case we want a | ||||
543 | # regexp filter, not a class filter. | ||||
544 | if (defined $class && $class eq 'Regexp') { | ||||
545 | if ($ref_kind eq 'Regexp' || ($] < 5.011 && $ref_kind eq 'SCALAR')) { | ||||
546 | $ref_kind = 'Regexp'; | ||||
547 | undef $class; | ||||
548 | } | ||||
549 | } | ||||
550 | if (defined $class) { | ||||
551 | if ($self->class->parent_filters) { | ||||
552 | my $linear_ISA = Data::Printer::Common::_linear_ISA_for($class, $self); | ||||
553 | foreach my $candidate_class (@$linear_ISA) { | ||||
554 | push @potential_filters, $self->_filters_for_class($candidate_class); | ||||
555 | } | ||||
556 | } | ||||
557 | else { | ||||
558 | push @potential_filters, $self->_filters_for_class($class); | ||||
559 | } | ||||
560 | # next, let any '-class' filters have a go: | ||||
561 | push @potential_filters, $self->_filters_for_class('-class'); | ||||
562 | } | ||||
563 | |||||
564 | # then, try regular data filters | ||||
565 | push @potential_filters, $self->_filters_for_type($ref_kind); | ||||
566 | |||||
567 | # finally, if it's neither a class nor a known core type, | ||||
568 | # we must be in a future perl with some type we're unaware of: | ||||
569 | push @potential_filters, $self->_filters_for_class('-unknown'); | ||||
570 | |||||
571 | return @potential_filters; | ||||
572 | } | ||||
573 | |||||
574 | # _see($data): marks data as seen if it was never seen it before. | ||||
575 | # if we are showing refcounts, we return those. Initially we had | ||||
576 | # this funcionallity separated, but refcounts increase as we find | ||||
577 | # them again and because of that we were seeing weird refcounting. | ||||
578 | # So now instead we store the refcount of the variable when we | ||||
579 | # first see it. | ||||
580 | # Finally, if we have already seen the data, we return its stringified | ||||
581 | # position, like "var", "var{foo}[7]", etc. UNLESS $options{seen_override} | ||||
582 | # is set. Why seen_override? Sometimes we want to print the same data | ||||
583 | # twice, like the GenericClass filter, which prints the object's metadata | ||||
584 | # via parse() and then the internal structure via parse_as(). But if we | ||||
585 | # simply do that, we'd get the "seen" version (because we have already | ||||
586 | # visited it!) The refcount is still calculated only once though :) | ||||
587 | sub _see { | ||||
588 | my ($self, $data, %options) = @_; | ||||
589 | return {} unless ref $data; | ||||
590 | my $id = pack 'J', Scalar::Util::refaddr($data); | ||||
591 | if (!exists $self->{_seen}{$id}) { | ||||
592 | $self->{_seen}{$id} = { | ||||
593 | name => $self->current_name, | ||||
594 | refcount => ($self->show_refcount ? $self->_refcount($data) : 0), | ||||
595 | }; | ||||
596 | return { refcount => $self->{_seen}{$id}->{refcount} }; | ||||
597 | } | ||||
598 | return { refcount => $self->{_seen}{$id}->{refcount} } if $options{seen_override}; | ||||
599 | return $self->{_seen}{$id}; | ||||
600 | } | ||||
601 | |||||
602 | sub seen { | ||||
603 | my ($self, $data) = @_; | ||||
604 | my $id = pack 'J', Scalar::Util::refaddr($data); | ||||
605 | return exists $self->{_seen}{$id}; | ||||
606 | } | ||||
607 | |||||
608 | sub unsee { | ||||
609 | my ($self, $data) = @_; | ||||
610 | return unless ref $data && keys %{$self->{_seen}}; | ||||
611 | |||||
612 | my $id = pack 'J', Scalar::Util::refaddr($data); | ||||
613 | delete $self->{_seen}{$id}; | ||||
614 | return; | ||||
615 | } | ||||
616 | |||||
617 | sub _refcount { | ||||
618 | my ($self, $data) = @_; | ||||
619 | |||||
620 | require B; | ||||
621 | my $count; | ||||
622 | my $rv = B::svref_2object(\$data)->RV; | ||||
623 | if (ref($data) eq 'REF' && ref($$data)) { | ||||
624 | $rv = B::svref_2object($data)->RV; | ||||
625 | } | ||||
626 | |||||
627 | # some SV's are special (represented by B::SPECIAL) | ||||
628 | # and don't have a ->REFCNT (e.g. \undef) | ||||
629 | return 0 unless $rv->can( 'REFCNT' ); | ||||
630 | |||||
631 | # 3 is our magical number: so we return the actual reference count | ||||
632 | # minus the references we added as we were traversing: | ||||
633 | return $rv->REFCNT - $self->{_refcount_base}; | ||||
634 | } | ||||
635 | |||||
636 | sub parse_as { | ||||
637 | my ($self, $type, $data) = @_; | ||||
638 | return $self->parse($data, force_type => $type, seen_override => 1); | ||||
639 | } | ||||
640 | |||||
641 | # parse() must always receive a reference, never a regular copy, because | ||||
642 | # that's the only way we are able to figure whether the source data | ||||
643 | # is a weak ref or not. | ||||
644 | sub parse { | ||||
645 | my $self = shift; | ||||
646 | my $str_weak = $self->_check_weak( $_[0] ); | ||||
647 | |||||
648 | my ($data, %options) = @_; | ||||
649 | my $parsed_string = ''; | ||||
650 | |||||
651 | # if we've seen this structure before, we return its location | ||||
652 | # instead of going through it again. This avoids infinite loops | ||||
653 | # when parsing circular references: | ||||
654 | my $seen = $self->_see($data, %options); | ||||
655 | if (my $name = $seen->{name}) { | ||||
656 | $parsed_string .= $self->maybe_colorize( | ||||
657 | ((ref $data eq 'SCALAR' && $self->resolve_scalar_refs) | ||||
658 | ? $$data | ||||
659 | : $name | ||||
660 | ), | ||||
661 | 'repeated' | ||||
662 | ); | ||||
663 | # on repeated references, the only extra data we put | ||||
664 | # is whether this reference is weak or not. | ||||
665 | $parsed_string .= $str_weak; | ||||
666 | return $parsed_string; | ||||
667 | } | ||||
668 | $self->{_position}++; | ||||
669 | |||||
670 | # Each filter type provides an array of potential parsers. | ||||
671 | # Once we find the right kind, we go through all of them, | ||||
672 | # from most precise match to most generic. | ||||
673 | # The first filter that returns a defined value "wins" | ||||
674 | # (even if it's an empty string) | ||||
675 | foreach my $filter ( | ||||
676 | exists $options{force_type} | ||||
677 | ? $self->_filters_for_type($options{force_type}) | ||||
678 | : $self->_filters_for_data($data) | ||||
679 | ) { | ||||
680 | if (defined (my $result = $filter->($data, $self))) { | ||||
681 | $parsed_string .= $result; | ||||
682 | last; | ||||
683 | } | ||||
684 | } | ||||
685 | |||||
686 | # FIXME: because of prototypes, p(@data) becomes a ref (that we don't care about) | ||||
687 | # to the data (that we do care about). So we should not show refcounts, memsize | ||||
688 | # or readonly status for something guaranteed to be ephemeral. | ||||
689 | $parsed_string .= $self->_check_readonly($data); | ||||
690 | $parsed_string .= $str_weak if ref($data) ne 'REF'; | ||||
691 | $parsed_string .= $self->_check_memsize($data); | ||||
692 | |||||
693 | if ($self->show_refcount && ref($data) ne 'SCALAR' && $seen->{refcount} > 1 ) { | ||||
694 | $parsed_string .= ' (refcount: ' . $seen->{refcount} .')'; | ||||
695 | } | ||||
696 | |||||
697 | if (--$self->{'_position'} == 0) { | ||||
698 | $self->{'_seen'} = {}; | ||||
699 | $self->{'_refcount_base'} = 3; | ||||
700 | $self->{'_position'} = 0; | ||||
701 | } | ||||
702 | |||||
703 | return $parsed_string; | ||||
704 | } | ||||
705 | |||||
706 | sub _check_memsize { | ||||
707 | my ($self, $data) = @_; | ||||
708 | return '' unless $self->show_memsize | ||||
709 | && ( $self->show_memsize eq 'all' | ||||
710 | || $self->show_memsize >= $self->{_position}); | ||||
711 | my $size; | ||||
712 | my $unit; | ||||
713 | my $error = Data::Printer::Common::_tryme(sub { | ||||
714 | require Devel::Size; | ||||
715 | $size = Devel::Size::total_size($data); | ||||
716 | $unit = uc $self->memsize_unit; | ||||
717 | if ($unit eq 'M' || ($unit eq 'AUTO' && $size > 1024*1024)) { | ||||
718 | $size = $size / (1024*1024); | ||||
719 | $unit = 'M'; | ||||
720 | } | ||||
721 | elsif ($unit eq 'K' || ($unit eq 'AUTO' && $size > 1024)) { | ||||
722 | $size = $size / 1024; | ||||
723 | $unit = 'K'; | ||||
724 | } | ||||
725 | else { | ||||
726 | $unit = 'B'; | ||||
727 | } | ||||
728 | }); | ||||
729 | if ($error) { | ||||
730 | if ($error =~ m{locate Devel/Size.pm}) { | ||||
731 | Data::Printer::Common::_warn($self, "Devel::Size not found, show_memsize will be ignored") | ||||
732 | if $self->{_position} == 1; | ||||
733 | } | ||||
734 | else { | ||||
735 | Data::Printer::Common::_warn($self, "error fetching memory usage: $error"); | ||||
736 | } | ||||
737 | return ''; | ||||
738 | } | ||||
739 | return '' unless $size; | ||||
740 | my $string = ' (' . ($size < 0 ? sprintf("%.2f", $size) : int($size)) . $unit . ')'; | ||||
741 | return $self->maybe_colorize($string, 'memsize'); | ||||
742 | } | ||||
743 | |||||
744 | sub _check_weak { | ||||
745 | my ($self) = shift; | ||||
746 | return '' unless $self->show_weak; | ||||
747 | |||||
748 | my $realtype = Scalar::Util::reftype($_[0]); | ||||
749 | my $isweak; | ||||
750 | if ($realtype && ($realtype eq 'REF' || $realtype eq 'SCALAR')) { | ||||
751 | $isweak = Scalar::Util::isweak($_[0]); | ||||
752 | } | ||||
753 | else { | ||||
754 | $isweak = Scalar::Util::isweak($_[0]); | ||||
755 | } | ||||
756 | return '' unless $isweak; | ||||
757 | return ' ' . $self->maybe_colorize('(weak)', 'weak'); | ||||
758 | } | ||||
759 | |||||
760 | sub _write_label { | ||||
761 | my ($self) = @_; | ||||
762 | return '' unless $self->caller_info; | ||||
763 | my @caller = caller 1; | ||||
764 | |||||
765 | my $message = $self->caller_message; | ||||
766 | |||||
767 | $message =~ s/\b__PACKAGE__\b/$caller[0]/g; | ||||
768 | $message =~ s/\b__FILENAME__\b/$caller[1]/g; | ||||
769 | $message =~ s/\b__LINE__\b/$caller[2]/g; | ||||
770 | |||||
771 | my $separator = $self->caller_message_newline ? "\n" : ' '; | ||||
772 | $message = $self->maybe_colorize($message, 'caller_info'); | ||||
773 | $message = $self->caller_message_position eq 'before' | ||||
774 | ? $message . $separator | ||||
775 | : $separator . $message | ||||
776 | ; | ||||
777 | return $message; | ||||
778 | } | ||||
779 | |||||
780 | sub maybe_colorize { | ||||
781 | my ($self, $output, $color_type, $default_color, $end_color) = @_; | ||||
782 | |||||
783 | if ($self->{_output_color_level} && defined $color_type) { | ||||
784 | my $theme = $self->theme; | ||||
785 | my $sgr_color = $theme->sgr_color_for($color_type); | ||||
786 | if (!defined $sgr_color && defined $default_color) { | ||||
787 | $sgr_color = $theme->_parse_color($default_color); | ||||
788 | } | ||||
789 | if ($sgr_color) { | ||||
790 | $output = $sgr_color | ||||
791 | . $output | ||||
792 | . (defined $end_color | ||||
793 | ? $theme->sgr_color_for($end_color) | ||||
794 | : $theme->color_reset | ||||
795 | ); | ||||
796 | } | ||||
797 | } | ||||
798 | return $output; | ||||
799 | } | ||||
800 | |||||
801 | sub _check_readonly { | ||||
802 | my ($self) = @_; | ||||
803 | return ' (read-only)' if $self->show_readonly && &Internals::SvREADONLY($_[1]); | ||||
804 | return ''; | ||||
805 | } | ||||
806 | |||||
807 | 1 | 6µs | 42; | ||
808 | __END__ | ||||
# spent 4µs within Data::Printer::Object::__ANON__ which was called 11 times, avg 382ns/call:
# once (700ns+0s) by Data::Printer::Object::BEGIN@51 at line 51
# once (700ns+0s) by Data::Printer::Object::BEGIN@56 at line 56
# once (400ns+0s) by Data::Printer::Object::BEGIN@61 at line 61
# once (300ns+0s) by Data::Printer::Object::BEGIN@60 at line 60
# once (300ns+0s) by Data::Printer::Object::BEGIN@54 at line 54
# once (300ns+0s) by Data::Printer::Object::BEGIN@58 at line 58
# once (300ns+0s) by Data::Printer::Object::BEGIN@57 at line 57
# once (300ns+0s) by Data::Printer::Object::BEGIN@55 at line 55
# once (300ns+0s) by Data::Printer::Object::BEGIN@52 at line 52
# once (300ns+0s) by Data::Printer::Object::BEGIN@59 at line 59
# once (300ns+0s) by Data::Printer::Object::BEGIN@53 at line 53 | |||||
# spent 2µs within Data::Printer::__ANON__ which was called 4 times, avg 625ns/call:
# once (1µs+0s) by Data::Printer::BEGIN@4 at line 4 of Data/Printer.pm
# once (700ns+0s) by Data::Printer::BEGIN@6 at line 6 of Data/Printer.pm
# once (500ns+0s) by Data::Printer::BEGIN@3.28 at line 3
# once (200ns+0s) by Data::Printer::BEGIN@5 at line 5 of Data/Printer.pm |