File Coverage

blib/lib/Dump/Krumo.pm
Criterion Covered Total %
statement 196 361 54.2
branch 76 150 50.6
condition 47 78 60.2
subroutine 31 40 77.5
pod 2 20 10.0
total 352 649 54.2


line stmt bran cond sub pod time code
1             #!/usr/bin/env perl
2              
3 2     2   244796 use strict;
  2         5  
  2         114  
4 2     2   20 use warnings;
  2         4  
  2         145  
5 2     2   33 use v5.16;
  2         8  
6 2     2   15 use Scalar::Util;
  2         19  
  2         163  
7              
8             package Dump::Krumo;
9              
10 2     2   25 use Exporter 'import';
  2         3  
  2         13209  
11             our @EXPORT = qw(kx kxd);
12              
13             # https://blogs.perl.org/users/grinnz/2018/04/a-guide-to-versions-in-perl.html
14             our $VERSION = 'v0.1.4';
15              
16             our $use_color = 1; # Output in color
17             our $return_string = 0; # Return a string instead of printing it
18             our $hash_sort = 1; # Sort hash keys before output
19             our $debug = 0; # Low level developer level debugging
20             our $disable = 0; # Disable Dump::Krumo
21             our $indent_spaces = 2; # Number of spaces to use for each level of indent
22             our $promote_bool = 1; # Convert JSON::PP::Boolean to raw true/false
23              
24             # Global var to track how many levels we're indented
25             my $current_indent_level = 0;
26             # Global var to track the indent to the right end of the most recent hash key
27             my $left_pad_width = 0;
28              
29             our $COLORS = {
30             'string' => 230, # Standard strings
31             'control_char' => 226, # the `\n`, `\r`, and `\t` inside strings
32             'undef' => 196, # undef
33             'hash_key' => 208, # hash keys on the left of =>
34             'integer' => 33, # integers
35             'float' => 51, # things that look like floating point
36             'class' => 118, # Classes/Object names
37             'binary' => 226, # Strings that contain non-printable chars
38             'scalar_ref' => 225, # References to scalar variables
39             'boolean' => 141, # Native boolean types
40             'regexp' => 164, # qr() style regexp variables
41             'glob' => 40, # \*STDOUT variables
42             'coderef' => 168, # code references
43             'vstring' => 153, # Version strings
44             'empty_braces' => '15_bold', # Either [] or {}
45             };
46              
47             my $WIDTH = get_terminal_width();
48             $WIDTH ||= 100;
49              
50             ###############################################################################
51             ###############################################################################
52              
53             # Dump the variable information
54             sub kx {
55 34     34 1 213425 my @arr = @_;
56              
57 34 50       118 if ($disable) { return -1; }
  0         0  
58              
59 34         60 my @items = ();
60 34         63 my $cnt = scalar(@arr);
61 34         58 my $is_array = 0;
62              
63             # If someone passes in a real array (not ref) we fake it out
64 34 100 100     169 if ($cnt > 1 || $cnt == 0) {
65 3         25 @arr = (\@_); # Convert to arrayref
66 3         7 $is_array = 1;
67             }
68              
69             # Loop through each item and dump it out
70 34         77 foreach my $item (@arr) {
71 34         86 push(@items, __dump($item));
72             }
73              
74 34 50       80 if (!@items) {
75 0         0 @items = ("UNKNOWN TYPE");
76             }
77              
78 34         97 my $str = join(", ", @items);
79              
80             # If it's a real array we remove the false [ ] added by __dump()
81 34 100       75 if ($is_array) {
82 3         7 my $len = length($str) - 2;
83 3         10 $str = substr($str, 1, $len);
84             }
85              
86 34 100 100     132 if ($cnt > 1 || $cnt == 0) {
87 3         5 $str = "($str)";
88             }
89              
90 34 50       71 if ($return_string) {
91 34         215 return "$str";
92             } else {
93 0         0 print "$str\n";
94             }
95             }
96              
97             # Dump the variable and die and output file/line
98             sub kxd {
99 0     0 1 0 kx(@_);
100              
101 0         0 my @call = caller();
102 0         0 my $file = $call[1];
103 0         0 my $line = $call[2];
104              
105 0         0 printf("\nDump::Krumo called from %s line %s\n", color('white', $file), color(194, "#$line"));
106 0         0 exit(15);
107             }
108              
109             # Generic dump that handles each type appropriately
110             sub __dump {
111 48     48   86 my $x = shift();
112 48         105 my $type = ref($x);
113 48   100     157 my $class = Scalar::Util::blessed($x) || "";
114              
115 48         82 my $ret;
116              
117 48 100 100     299 if ($type eq 'ARRAY') {
    100 100        
    100 100        
    100 100        
    100 66        
    100          
    100          
    100          
    100          
    100          
    50          
    0          
    0          
118 10         29 $ret = __dump_array($x);
119             } elsif ($type eq 'HASH') {
120 1         5 $ret = __dump_hash($x);
121             } elsif ($type eq 'SCALAR') {
122 3         11 $ret = color(get_color('scalar_ref'), '\\' . quote_string($$x));
123             } elsif (!$type && is_bool_val($x)) {
124 2         41 $ret = __dump_bool($x);
125             } elsif (!$type && is_integer($x)) {
126 10         26 $ret = __dump_integer($x);
127             } elsif (!$type && is_float($x)) {
128 1         4 $ret = __dump_float($x);
129             } elsif (!$type && is_string($x)) {
130 14         35 $ret = __dump_string($x);
131             } elsif (!$type && is_undef($x)) {
132 2         6 $ret = __dump_undef();
133             } elsif ($class eq "Regexp") {
134 3         9 $ret = __dump_regexp($class, $x);
135             } elsif ($type eq "GLOB") {
136 1         6 $ret = __dump_glob($class, $x);
137             } elsif ($type eq "CODE") {
138 1         4 $ret = __dump_coderef($class, $x);
139             } elsif ($type eq "VSTRING") {
140 0         0 $ret = __dump_vstring($x);
141             } elsif ($class) {
142 0         0 $ret = __dump_class($class, $x);
143             } else {
144 0         0 $ret = "Unknown variable type: '$type'";
145             }
146              
147 48         158 return $ret;
148             }
149              
150             ################################################################################
151             # Each variable type gets it's own dump function
152             ################################################################################
153              
154             sub __dump_bool {
155 2     2   7 my $x = shift();
156 2         3 my $ret;
157              
158 2 100       6 if ($x) {
159 1         4 $ret = color(get_color('boolean'), "true");
160             } else {
161 1         5 $ret = color(get_color('boolean'), "false");
162             }
163              
164 2         5 return $ret;
165             }
166              
167             sub __dump_regexp {
168 3     3   8 my ($class, $x) = @_;
169              
170 3         10 my $ret = color(get_color('regexp'), "qr$x");
171              
172 3         9 return $ret;
173             }
174              
175             sub __dump_coderef {
176 1     1   3 my ($class, $x) = @_;
177              
178 1         4 my $ret = color(get_color('coderef'), "sub { ... }");
179              
180 1         4 return $ret;
181             }
182              
183             sub __dump_glob {
184 1     1   3 my ($class, $x) = @_;
185              
186 1         4 my $ret = color(get_color('glob'), "\\" . $$x);
187              
188 1         4 return $ret;
189             }
190              
191             sub __dump_class {
192 0     0   0 my ($class, $x) = @_;
193              
194 0         0 my $ret = '"' . color(get_color('class'), $class) . "\" :: ";
195 0         0 my $reftype = Scalar::Util::reftype($x);
196 0         0 my $y;
197              
198 0 0 0     0 if ($promote_bool && $class eq 'JSON::PP::Boolean') {
199 0         0 my $val = $$x;
200 0         0 return __dump_bool(!!$val);
201             }
202              
203 0         0 my $len = length($class) + 6; # 2x quotes and ' :: '
204 0         0 $left_pad_width += $len;
205              
206             # We need an unblessed copy of the data so we can display it
207 0 0       0 if ($reftype eq 'ARRAY') {
    0          
    0          
208 0         0 $y = [@$x];
209             } elsif ($reftype eq 'HASH') {
210 0         0 $y = {%$x};
211             } elsif ($reftype eq 'SCALAR') {
212 0         0 $y = $$x;
213             } else {
214 0         0 $y = "Unknown class?";
215             }
216              
217 0         0 $ret .= __dump($y);
218              
219 0         0 $left_pad_width -= $len;
220              
221 0         0 return $ret;
222             }
223              
224             sub __dump_integer {
225 10     10   17 my $x = shift();
226 10         23 my $ret = color(get_color('integer'), $x);
227              
228 10         42 return $ret;
229             }
230              
231             sub __dump_float {
232 1     1   2 my $x = shift();
233 1         5 my $ret = color(get_color('float'), $x);
234              
235 1         9 return $ret;
236             }
237              
238             sub __dump_vstring {
239 0     0   0 my $x = shift();
240              
241 0         0 my @parts = unpack("C*", $$x);
242 0         0 my $str = "\\v" .(join ".", @parts);
243              
244 0         0 my $ret = color(get_color('vstring'), $str);
245              
246 0         0 return $ret;
247             }
248              
249             sub __dump_string {
250 14     14   28 my $x = shift();
251              
252 14 100       32 if (length($x) == 0) {
253 2         7 return color(get_color('empty_braces'), "''"),
254             }
255              
256 12         47 my $printable = is_printable($x);
257              
258             # Convert all \n to printable version
259 12         49 my $slash_n = color(get_color('control_char'), '\\n') . color(get_color('string'));
260 12         35 my $slash_r = color(get_color('control_char'), '\\r') . color(get_color('string'));
261 12         25 my $slash_t = color(get_color('control_char'), '\\t') . color(get_color('string'));
262              
263 12         26 my $ret = '';
264              
265             # For short strings we show the unprintable chars as \x{00} escapes
266 12 100 66     74 if (!$printable && (length($x) < 20)) {
    50          
    100          
267 1         7 my @p = unpack("C*", $x);
268              
269 1         3 my $str = '';
270 1         4 foreach my $x (@p) {
271 3         9 my $is_printable = is_printable(chr($x));
272              
273 3 100       9 if ($is_printable) {
274 2         6 $str .= color(get_color('string'),chr($x));
275             } else {
276 1         15 $str .= color(get_color('binary'), '\\x{' . sprintf("%02X", $x) . '}');
277             }
278             }
279              
280 1         3 $ret = "\"$str\"";
281             # Longer unprintable stuff we just spit out the raw HEX
282             } elsif (!$printable) {
283 0         0 $ret = color(get_color('binary'), 'pack("H*", ' . bin2hex($x) . ")");
284             # If it's a simple string we single quote it
285             } elsif ($x =~ /^[\w .,":;?!#\$%^*&\/=-]*$/g) {
286 5         13 $ret = "'" . color(get_color('string'), "$x") . "'";
287             # Otherwise we clean it up and then double quote it
288             } else {
289             # Do some clean up here?
290 6         13 $ret = '"' . color(get_color('string'), "$x") . '"';
291             }
292              
293 12         37 $ret =~ s/\n/$slash_n/g;
294 12         20 $ret =~ s/\r/$slash_r/g;
295 12         21 $ret =~ s/\t/$slash_t/g;
296              
297 12         84 return $ret;
298             }
299              
300             sub __dump_undef {
301 2     2   7 my $ret = color(get_color('undef'), 'undef');
302              
303 2         7 return $ret;
304             }
305              
306             sub __dump_array {
307 10     10   45 my $x = shift();
308              
309             # If it's only a single element we return the stringified version of that
310 10 50       28 if (ref($x) ne 'ARRAY') {
311 0         0 return __dump("$x");
312             }
313              
314 10         17 $current_indent_level++;
315              
316 10         19 my $cnt = scalar(@$x);
317 10 100       25 if ($cnt == 0) {
318 2         4 $current_indent_level--;
319 2         5 return color(get_color('empty_braces'), '[]'),
320             }
321              
322             # See if we need to switch to column mode to output this array
323 8         19 my $column_mode = needs_column_mode($x);
324              
325 8         16 my $ret = '';
326 8         12 my @items = ();
327 8         16 foreach my $z (@$x) {
328 14         50 push(@items, __dump($z));
329             }
330              
331 8 50       18 if ($column_mode) {
332 0         0 $ret = "[\n";
333 0         0 my $pad = " " x ($current_indent_level * $indent_spaces);
334 0         0 foreach my $x (@items ) {
335 0         0 $ret .= $pad . "$x,\n";
336             }
337              
338 0         0 $pad = " " x (($current_indent_level - 1) * $indent_spaces);
339 0         0 $ret .= $pad . "]";
340             } else {
341 8         29 $ret = '[' . join(", ", @items) . ']';
342             }
343              
344 8         14 $current_indent_level--;
345              
346 8         21 return $ret;
347             }
348              
349             sub __dump_hash {
350 1     1   3 my $x = shift();
351 1         2 $current_indent_level++;
352              
353 1         2 my $ret;
354 1         3 my @items = ();
355 1         3 my @keys = keys(%$x);
356 1         3 my @vals = values(%$x);
357 1         3 my $cnt = scalar(@keys);
358              
359             # There may be some weird scenario where we do NOT want to sort
360 1 50       4 if ($hash_sort) {
361 1         3 @keys = sort(@keys);
362             }
363              
364 1 50       3 if ($cnt == 0) {
365 1         2 $current_indent_level--;
366 1         4 return color(get_color('empty_braces'), '{}'),
367             }
368              
369 0         0 my $key_len = 0;
370 0         0 foreach my $x (@keys) {
371 0         0 $key_len += length($x) + 4; # Add four for ' => '
372             }
373              
374             # See if we need to switch to column mode to output this array
375 0         0 my $max_length = max_length(@keys);
376 0         0 $left_pad_width = $max_length;
377 0         0 my $column_mode = needs_column_mode($x, $key_len);
378              
379             # If we're not in column mode there is no need to compensate for this
380 0 0       0 if (!$column_mode) {
381 0         0 $max_length = 0;
382             }
383              
384             # Check to see if any of the array keys need to be quoted
385 0         0 my $keys_need_quotes = 0;
386 0         0 foreach my $key (@keys) {
387 0 0       0 if ($key =~ /\W/) {
388 0         0 $keys_need_quotes = 1;
389 0         0 last;
390             }
391             }
392              
393             # Loop through each key and build the appropriate string for it
394 0         0 foreach my $key (@keys) {
395 0         0 my $val = $x->{$key};
396              
397 0         0 my $key_str = '';
398 0 0       0 if ($keys_need_quotes) {
399 0         0 $key_str = "'" . color(get_color('hash_key'), $key) . "'";
400             } else {
401 0         0 $key_str = color(get_color('hash_key'), $key);
402             }
403              
404             # Align the hash keys
405 0 0       0 if ($column_mode) {
406 0         0 my $raw_len = length($key);
407 0         0 my $append_cnt = $max_length - $raw_len;
408              
409             # Sometimes this goes negative?
410 0 0       0 if ($append_cnt < 0) {
411 0         0 $append_cnt = 0;
412             }
413              
414 0         0 $key_str .= " " x $append_cnt;
415             }
416              
417 0         0 push(@items, $key_str . ' => ' . __dump($val));
418             }
419              
420             # If we're too wide for the screen we drop to column mode
421 0 0       0 if ($column_mode) {
422 0         0 $ret = "{\n";
423              
424 0         0 foreach my $x (@items) {
425 0         0 my $pad = " " x ($current_indent_level * $indent_spaces);
426 0         0 $ret .= $pad . "$x,\n";
427             }
428              
429 0         0 my $pad = " " x (($current_indent_level - 1) * $indent_spaces);
430 0         0 $ret .= $pad . "}";
431             } else {
432 0         0 $ret = '{ ' . join(", ", @items) . ' }';
433             }
434              
435 0         0 $current_indent_level--;
436              
437 0         0 return $ret;
438             }
439              
440             ################################################################################
441             # Various helper functions
442             ################################################################################
443              
444             # Calculate the length of the longest string in an array
445             sub max_length {
446 0     0 0 0 my $max = 0;
447              
448 0         0 foreach my $item (@_) {
449 0         0 my $len = length($item);
450 0 0       0 if ($len > $max) {
451 0         0 $max = $len;
452             }
453             }
454              
455 0         0 return $max;
456             }
457              
458             # Calculate the length in chars of this array
459             sub array_str_len {
460 8     8 0 16 my @arr = @_;
461              
462 8         12 my $len = 0;
463 8         15 foreach my $x (@arr) {
464 14 100 33     69 if (!defined($x)) {
    50          
    50          
    50          
    50          
465 1         3 $len += 5; # The string "undef"
466             } elsif (ref $x eq 'ARRAY') {
467 0         0 $len += array_str_len(@$x);
468             } elsif (ref $x eq 'HASH') {
469 0         0 $len += array_str_len(%$x);
470             } elsif (is_bool_val($x) && $x) {
471 0         0 $len += 6; # 'true'
472             } elsif (is_bool_val($x)) {
473 0         0 $len += 7; # 'false'
474             } else {
475 13         27 $len += length($x);
476              
477 13 100       26 if (!is_numeric($x)) {
478 6         12 $len += 2; # For the quotes around the string
479             }
480             }
481              
482             # We stop counting after we hit $WIDTH so we don't
483             # waste a bunch of CPU cycles counting something we
484             # won't ever use (useful in big nested objects)
485 14 50       38 if ($len > $WIDTH) {
486 0         0 return $WIDTH + 999;
487             }
488             }
489              
490 8         19 return $len;
491             }
492              
493             # Calculate if this data structure will wrap the screen and needs to be in column mode instead
494             sub needs_column_mode {
495 8     8 0 17 my ($x, $extra_len) = @_;
496 8   50     39 $extra_len //= 0;
497              
498 8         11 my $ret = 0;
499 8         13 my $len = 0;
500 8         15 my $type = ref($x);
501              
502 8 50       19 if ($type eq "ARRAY") {
    0          
    0          
503 8         11 my $cnt = scalar(@$x);
504              
505 8         23 $len += array_str_len(@$x);
506 8         13 $len += 2; # For the '[' on the start/end
507 8         18 $len += 2 * $cnt; # ', ' for each item
508             } elsif ($type eq "HASH") {
509 0         0 my @keys = keys(%$x);
510 0         0 my @vals = values(%$x);
511 0         0 my $cnt = scalar(@keys);
512              
513 0         0 $len += array_str_len(@keys);
514 0         0 $len += array_str_len(@vals);
515 0         0 $len += 4; # For the '{ ' on the start/end
516 0         0 $len += 6 * $cnt; # ' => ' and the ', ' for each item
517             # This is a class/obj
518             } elsif ($type) {
519 0         0 my $cnt = scalar(@$x);
520              
521 0         0 $len += array_str_len(@$x);
522 0         0 $len += 2; # For the '[' on the start/end
523 0         0 $len += 2 * $cnt; # ' => ' and the ', ' for each item
524             }
525              
526 8         14 my $content_len = $len;
527              
528             # Current number of spaces we're indented from the left
529 8         34 my $left_indent = ($current_indent_level - 1) * $indent_spaces;
530             # Where the ' => ' in the hash key ends
531 8         16 my $pad_width = $left_pad_width + 4; # For the ' => '
532              
533             # Add it all together
534 8         16 $len = $left_indent + $pad_width + $len + $extra_len;
535              
536             # If we're too wide for the screen we drop to column mode
537             # Our math isn't 100% down the character so we use 97% to give
538             # ourselves some wiggle room
539 8 50       24 if ($len > ($WIDTH * .97)) {
540 0         0 $ret = 1;
541             }
542              
543             # This math is kinda gnarly so if we turn on debug mode we can
544             # see each array/hash and how we calculate the length
545 8 50       18 if ($debug) {
546 0         0 state $first = 1;
547              
548 0 0       0 if ($first) {
549 0         0 printf("Screen width: %d\n\n", $WIDTH * .97);
550 0         0 printf("Left Indent | Hash Padding | Content | Extra | Total\n");
551 0         0 $first = 0;
552             }
553              
554 0         0 printf("%8d + %6d + %4d + %4d = %4d (%d)\n", $left_indent, $pad_width, $content_len, $extra_len, $len, $ret);
555             }
556              
557 8         19 return $ret;
558             }
559              
560             # Convert raw bytes to hex for easier printing
561             sub bin2hex {
562 0     0 0 0 my $bytes = shift();
563 0         0 my $ret = uc(unpack("H*", $bytes));
564              
565 0         0 return $ret;
566             }
567              
568             ################################################################################
569             # Test functions to determine what type of variable something is
570             ################################################################################
571              
572             # Does the string contain only printable characters
573             sub is_printable {
574 15     15 0 30 my ($str) = @_;
575              
576 15 50 66     46 if (length($str) == 1 && (ord($str) >= 127)) {
577 0         0 return 0;
578             }
579              
580 15         25 my $ret = 0;
581 15 100 66     81 if (defined($str) && $str =~ /^[[:print:]\n\r\t]*$/) {
582 13         22 $ret = 1;
583             }
584              
585 15         49 return $ret;
586             }
587              
588             sub is_undef {
589 2     2 0 4 my $x = shift();
590              
591 2 50       6 if (!defined($x)) {
592 2         8 return 1;
593             } else {
594 0         0 return 0;
595             }
596             }
597              
598             # Veriyf this
599             sub is_nan {
600 0     0 0 0 my $x = shift();
601 0         0 my $ret = 0;
602              
603 0 0       0 if ($x != $x) {
604 0         0 $ret = 1;
605             }
606              
607 0         0 return $ret;
608             }
609              
610             # Veriyf this
611             sub is_infinity {
612 0     0 0 0 my $x = shift();
613 0         0 my $ret = 0;
614              
615 0 0       0 if ($x * 2 == $x) {
616 0         0 $ret = 1;
617             }
618              
619 0         0 return $ret;
620             }
621              
622             sub is_string {
623 16     16 0 27 my ($value) = @_;
624 16   66     97 return defined($value) && $value !~ /^-?\d+(?:\.\d+)?$/;
625             }
626              
627             sub is_integer {
628 27     27 0 54 my ($value) = @_;
629 27   100     273 return defined($value) && $value =~ /^-?\d+$/;
630             }
631              
632             sub is_float {
633 17     17 0 33 my ($value) = @_;
634             #my $ret = defined($value) && $value =~ /^-?\d+\.\d+$/;
635 17   100     97 my $ret = defined($value) && $value =~ /^-?\d+\.\d+(e[+-]\d+)?$/;
636              
637 17         103 return $ret;
638             }
639              
640             # Borrowed from builtin::compat
641             sub is_bool_val {
642 55     55 0 90 my $value = shift;
643              
644             # Make sure the variable is defined, is not a reference and is a dualval
645 55 100       176 if (!defined($value)) { return 0; }
  2         14  
646 53 100       122 if (length(ref($value)) != 0) { return 0; }
  2         6  
647 51 100       144 if (!Scalar::Util::isdual($value)) { return 0; }
  49         185  
648              
649             # Make sure the string and integer versions match
650 2 100 66     15 if ($value == 1 && $value eq '1') { return 1; }
  1         6  
651 1 50 33     8 if ($value == 0 && $value eq '') { return 1; }
  1         4  
652              
653 0         0 return 0;
654             }
655              
656             sub is_numeric {
657 13     13 0 37 my $ret = Scalar::Util::looks_like_number($_[0]);
658              
659 13         38 return $ret;
660             }
661              
662             ################################################################################
663              
664             # String format: '115', '165_bold', '10_on_140', 'reset', 'on_173', 'red', 'white_on_blue'
665             sub color {
666 114     114 0 232 my ($str, $txt) = @_;
667              
668             # If we're NOT connected to a an interactive terminal don't do color
669 114   33     181 state $color_available = (!$use_color || -t STDOUT == 0);
670 114 50       231 if ($color_available) {
671 114   100     356 return $txt // "";
672             }
673              
674             # No string sent in, so we just reset
675 0 0 0     0 if (!length($str) || $str eq 'reset') { return "\e[0m"; }
  0         0  
676              
677             # Some predefined colors
678 0         0 my %color_map = qw(red 160 blue 27 green 34 yellow 226 orange 214 purple 93 white 15 black 0);
679 0   0     0 $str =~ s|([A-Za-z]+)|$color_map{$1} // $1|eg;
  0         0  
680              
681             # Get foreground/background and any commands
682 0         0 my ($fc,$cmd) = $str =~ /^(\d{1,3})?_?(\w+)?$/g;
683 0         0 my ($bc) = $str =~ /on_(\d{1,3})$/g;
684              
685 0 0 0     0 if (defined($fc) && int($fc) > 255) { $fc = undef; } # above 255 is invalid
  0         0  
686              
687             # Some predefined commands
688 0         0 my %cmd_map = qw(bold 1 italic 3 underline 4 blink 5 inverse 7);
689 0   0     0 my $cmd_num = $cmd_map{$cmd // 0};
690              
691 0         0 my $ret = '';
692 0 0       0 if ($cmd_num) { $ret .= "\e[${cmd_num}m"; }
  0         0  
693 0 0       0 if (defined($fc)) { $ret .= "\e[38;5;${fc}m"; }
  0         0  
694 0 0       0 if (defined($bc)) { $ret .= "\e[48;5;${bc}m"; }
  0         0  
695 0 0       0 if (defined($txt)) { $ret .= $txt . "\e[0m"; }
  0         0  
696              
697 0         0 return $ret;
698             }
699              
700             sub get_terminal_width {
701             # If there is no $TERM then tput will bail out
702 2 50 33 2 0 38 if (!$ENV{TERM} || -t STDOUT == 0) {
703 2         13 return 0;
704             }
705              
706 0         0 my $tput = `tput cols`;
707              
708 0         0 my $width = 0;
709 0 0       0 if ($tput) {
710 0         0 $width = int($tput);
711             } else {
712 0         0 print color('orange', "Warning:") . " `tput cols` did not return numeric input\n";
713 0         0 $width = 80;
714             }
715              
716 0         0 return $width;
717             }
718              
719             # See also B::perlstring as a possible alternative
720             sub quote_string {
721 3     3 0 8 my ($s) = @_;
722              
723             # Use single quotes if no special chars
724 3 50       15 if ($s !~ /[\'\\\n\r\t\f\b\$@"]/ ) {
725 3         16 return "'$s'";
726             }
727              
728             # Otherwise, escape for double quotes
729 0         0 (my $escaped = $s) =~ s/([\\"])/\\$1/g;
730 0         0 $escaped =~ s/\n/\\n/g;
731 0         0 $escaped =~ s/\r/\\r/g;
732 0         0 $escaped =~ s/\t/\\t/g;
733 0         0 $escaped =~ s/\f/\\f/g;
734 0         0 $escaped =~ s/\b/\\b/g;
735              
736 0         0 return "\"$escaped\"";
737             }
738              
739             sub get_color {
740 114   50 114 0 299 my $str = $_[0] || "";
741              
742 114   50     324 my $ret = $COLORS->{$str} // 251;
743              
744 114         312 return $ret;
745             }
746              
747             # Creates methods k() and kd() to print, and print & die respectively
748 0         0 BEGIN {
749 2 50   2   11 if (eval { require Data::Dump::Color }) {
  2         1390  
750 0         0 *k = sub { Data::Dump::Color::dd(@_) };
  0         0  
751             } else {
752 2         1502 require Data::Dumper;
753 2     0   23804 *k = sub { print Data::Dumper::Dumper(\@_) };
  0         0  
754             }
755              
756             sub kd {
757 0     0 0   k(@_);
758              
759 0           printf("Died at %2\$s line #%3\$s\n",caller());
760 0           exit(15);
761             }
762             }
763              
764             ################################################################################
765             ################################################################################
766             ################################################################################
767              
768             =encoding utf8
769              
770             =head1 NAME
771              
772             Dump::Krumo - Fancy, colorful, human readable dumps of your data
773              
774             =head1 SYNOPSIS
775              
776             use Dump::Krumo;
777              
778             my $data = { one => 1, two => 2, three => 3 };
779             kx($data);
780              
781             my $list = ['one', 'two', 'three', 'four'];
782             kxd($list);
783              
784             =head1 DESCRIPTION
785              
786             Colorfully dump your data to make debugging variables easier. C
787             focuses on making your data human readable and easily parseable.
788              
789             =begin markdown
790              
791             # SCREENSHOTS
792              
793             dk-ss
794              
795             =end markdown
796              
797             =head1 METHODS
798              
799             =over 4
800              
801             =item B
802              
803             Debug print C<$var>.
804              
805             =item B
806              
807             Debug print C<$var> and C. This outputs file and line information.
808              
809             =back
810              
811             =head1 OPTIONS
812              
813             =over 4
814              
815             =item C<$Dump::Krumo::use_color = 1>
816              
817             Turn color on/off
818              
819             =item C<$Dump::Krumo::return_string = 0>
820              
821             Return a string instead of printing out
822              
823             =item C<$Dump::Krumo::indent_spaces = 2>
824              
825             Number of spaces to indent each level
826              
827             =item C<$Dump::Krumo::disable = 0>
828              
829             Disable all output from C. This allows you to leave all of your
830             debug print statements in your code, and disable them at runtime as needed.
831              
832             =item C<$Dump::Krumo::promote_bool = 1>
833              
834             Convert JSON::PP::Booleans to true/false instead of treating them as objects.
835              
836             =item C<$Dump::Krumo::COLORS>
837              
838             Reference to a hash of colors for each variable type. Update this and create
839             your own color scheme.
840              
841             =back
842              
843             =head1 SEE ALSO
844              
845             =over
846              
847             =item *
848             L
849              
850             =item *
851             L
852              
853             =item *
854             L
855              
856             =item *
857             L
858              
859             =back
860              
861             =head1 AUTHOR
862              
863             Scott Baker - L
864              
865             =cut
866              
867             1;
868              
869             # vim: tabstop=4 shiftwidth=4 noexpandtab autoindent softtabstop=4