File Coverage

blib/lib/Data/Printer/Object.pm
Criterion Covered Total %
statement 352 409 86.0
branch 110 172 63.9
condition 54 101 53.4
subroutine 62 63 98.4
pod 15 15 100.0
total 593 760 78.0


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