The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Data::Dumper::Interp - interpolate Data::Dumper output into strings for human consumption

SYNOPSIS

  use open IO => ':locale';
  use Data::Dumper::Interp;

  @ARGV = ('-i', '/file/path');
  my %hash = (abc => [1,2,3,4,5], def => undef);
  my $ref = \%hash;
  my $obj = bless {}, "Foo::Bar";

  # Interpolate variables in strings with Data::Dumper output
  say ivis 'FYI ref is $ref\nThat hash is: %hash\nArgs are @ARGV';

    # -->FYI ref is {abc => [1,2,3,4,5], def => undef}
    #    That hash is: (abc => [1,2,3,4,5], def => undef)
    #    Args are ("-i","/file/path")

  # Label interpolated values with "expr="
  say dvis '$ref\nand @ARGV';

    # -->ref={abc => [1,2,3,4,5], def => undef}
    #    and @ARGV=("-i","/file/path")

  # Functions to format one thing
  say vis $ref;      #prints {abc => [1,2,3,4,5], def => undef}
  say vis \@ARGV;    #prints ["-i", "/file/path"]  # any scalar
  say avis @ARGV;    #prints ("-i", "/file/path")
  say hvis %hash;    #prints (abc => [1,2,3,4,5], def => undef)

  # Format a reference with abbreviated referent address
  say rvis $href;    #prints HASH<457:1c9>{abc => [1,2,3,4,5], ...}

  # Just abbreviate a referent address or arbitrary number
  say addrvis refaddr($ref);  # 457:1c9
  say addrvis $ref;           # HASH<457:1c9>
  say addrvis $obj;           # Foo::Bar<984:ef8>

  # Stringify objects
  { use bigint;
    my $struct = { debt => 999_999_999_999_999_999.02 };
    say vis $struct;
      # --> {debt => (Math::BigFloat)999999999999999999.02}

    # But if you do want to see object internals
    say visnew->Objects(0)->vis($struct);
    { local $Data::Dumper::Interp::Objects=0; say vis $struct; } #another way
      # --> {debt => bless({...lots of stuff...},'Math::BigInt')}
  }

  # Wide characters are readable
  use utf8;
  my $h = {msg => "My language is not ASCII ☻ ☺ 😊 \N{U+2757}!"};
  say dvis '$h' ;
    # --> h={msg => "My language is not ASCII ☻ ☺ 😊 ❗"}

  #-------- OO API --------

  say Data::Dumper::Interp->new()
            ->MaxStringwidth(50)->Maxdepth($levels)->vis($datum);

  say visnew->MaxStringwidth(50)->Maxdepth($levels)->vis($datum);

  #-------- UTILITY FUNCTIONS --------
  say u($might_be_undef);  # $_[0] // "undef"
  say quotekey($string);   # quote hash key if not a valid bareword
  say qsh($string);        # quote if needed for /bin/sh
  say qshpath($pathname);  # shell quote excepting ~ or ~username prefix
  say "Runing this: ", qshlist(@command_and_args);

    system "ls -ld ".join(" ",map{ qshpath }
                              ("/tmp", "~sally/My Documents", "~"));

DESCRIPTION

This Data::Dumper wrapper optimizes output for human consumption and avoids side-effects which interfere with debugging.

The namesake feature is interpolating Data::Dumper output into strings, but simple functions are also provided to show a scalar, array, or hash.

Internally, Data::Dumper is called to visualize (i.e. format) data with pre- and post-processing to "improve" the results:

  • Output is compact (1 line if possible, otherwise folded at your terminal width), WITHOUT a trailing newline.

  • Printable Unicode characters appear as themselves.

  • Object internals are not shown; Math:BigInt etc. are stringified.

  • "virtual" values behind overloaded deref operators are shown.

  • Data::Dumper bugs^H^H^H^Hquirks are circumvented.

See "DIFFERENCES FROM Data::Dumper".

Finally, a few utilities are provided to quote strings for /bin/sh.

FUNCTIONS

ivis 'string to be interpolated'

Returns the argument with variable references and escapes interpolated as in in Perl double-quotish strings, but using Data::Dumper to format variable values.

$var is replaced by its value, @var is replaced by "(comma, sparated, list)", and %hash by "(key => value, ...)" . Complex expressions with indexing, dereferences, slices and method calls are also recognized.

Expressions are evaluated in the caller's context using Perl's debugger hooks, and may refer to almost any lexical or global visible at the point of call (see "LIMITATIONS").

IMPORTANT: The argument must be single-quoted to prevent Perl from interpolating it beforehand.

dvis 'string to be interpolated'

Like ivis with the addition that interpolated items are prefixed with a "exprtext=" label.

The 'd' in 'dvis' stands for debugging messages, a frequent use case where brevity of typing is more highly prized than beautiful output.

vis optSCALAREXPR

avis LIST

hvis EVENLIST

vis formats a single scalar ($_ if no argument is given) and returns the resulting string.

avis formats an array (or any list) as comma-separated values in parenthesis.

hvis formats key => value pairs in parenthesis.

Variations

alvis, hlvis

The "l" variants return a bare list of array or hash members without the enclosing parenthesis.

ivisq dvisq visq avisq hvisq alvisq hlvisq

The "q" variants show strings 'single quoted' if possible.

Internally, Data::Dumper is called with Useqq(0), but depending on the version of Data::Dumper the result may be "double quoted" anyway if wide characters are present.

rivis rdvis rvis ravis rhvis rivisq rdvisq rvisq ravisq rhvisq

The "r" variants show the type<abbreviated refaddr> before refs (see addrvis). For example rvis([1..3]) returns something like "ARRAY<457:1c9>[1,2,3]".

viso visoq

The "o" variants show the internals of objects, the same as if $Objects is set to 0. By default object internals are never shown, see Objects(BOOL).

addrvis REF

addrvis NUMBER

These return a string showing the address in both decimal and hexadecimal, but abbreviated to only the last few digits.

The number of digits increases over time if necessary to keep new results unambiguous.

For REFs, the result is like "HASH<457:1c9>" or, for blessed objects, "Package::Name<457:1c9>".

If the argument is a plain number, just the abbreviated address like "<457:1c9>" is returned.

"undef" is returned if the argument is undefined.

OBJECT-ORIENTED INTERFACES

Data::Dumper::Interp->new()

visnew()

Creates an object initialized from the global configuration variables listed below (the function visnew is simply a shorthand wrapper).

No arguments are permitted.

The functions described above may then be called as methods on the object (when not called as a method the functions create a new object internally).

For example:

   $msg = visnew->Foldwidth(40)->avis(@ARGV);

returns the same string as

   local $Data::Dumper::Interp::Foldwidth = 40;
   $msg = avis(@ARGV);

Configuration Variables / Methods

These work the same way as variables/methods in Data::Dumper.

Each config method has a corresponding global variable in package Data::Dumper::Interp which provides the default.

When a method is called without arguments the current value is returned.

When a method is called with an argument to set a value, the object is returned so that method calls can be chained.

MaxStringwidth(INTEGER)

Truncsuffix("...")

Longer strings are truncated and Truncsuffix appended. MaxStringwidth=0 (the default) means no limit.

Foldwidth(INTEGER)

Defaults to the terminal width at the time of first use.

Objects(BOOL);

Objects("classname")

Objects([ list of classnames ])

A false value disables special handling of objects (that is, blessed things) and internals are shown as with Data::Dumper.

A "1" (the default) enables for all objects, otherwise only for the specified class name(s) [or derived classes].

When enabled, object internals are never shown. If the object overloads the stringification ('""') operator, or array-, hash-, scalar-, or glob- deref operators, then the first overloaded operator found will be evaluated, object replaced by the result, and the check repeated; otherwise only the class and abbreviated address are shown as with addrvis e.g. "Foo::Bar<392:0f0>".

Beginning with version 5.000 the deprecated Overloads method is an alias for Objects.

Sortkeys(subref)

The default sorts numeric substrings in keys by numerical value, e.g. "A.20" sorts before "A.100". See Data::Dumper documentation.

Useqq

The default value is "unicode" except for functions/methods with 'q' in their name, which force Useqq(0).

0 means generate 'single quoted' strings when possible.

1 means generate "double quoted" strings, as-is from Data::Dumper. Non-ASCII charcters will be shown as hex escapes.

Otherwise generate "double quoted" strings enhanced according to option keywords given as a :-separated list, e.g. Useqq("unicode:controlpics"). The avilable options are:

"unicode"

Printable ("graphic") characters are shown as themselves rather than hex escapes, and '\n', '\t', etc. are shown for ASCII control codes.

"controlpics"

Show ASCII control characters using single "control picture" characters, for example '␤' is shown for newline instead of '\n', and similarly for \0 \a \b \e \f \r and \t.

Every character occupies the same space with a fixed-width font. However the commonly-used "Last Resort" font for these characters can be hard to read on modern high-res displays. Set Useqq to just "unicode" to see traditional \n etc. backslash escapes while still seeing wide characters as themselves.

"spacedots"

Space characters are shown as '·' (Middle Dot).

"qq"
"qq=XY"

Show using Perl's qq{...} syntax, or qqX...Y if delimiters are specified, rather than "...".

Quotekeys

Maxdepth

Maxrecurse

Deparse

See Data::Dumper documentation.

UTILITY FUNCTIONS

u

u SCALAR

Returns the argument ($_ by default) if it is defined, otherwise the string "undef".

quotekey

quotekey SCALAR

Returns the argument ($_ by default) if it is a valid bareword, otherwise a "quoted string".

qsh [$string]

The string ($_ by default) is quoted if necessary for parsing by the shell (/bin/sh), which has different quoting rules than Perl. On Win32 quoting is for cmd.com.

If the string contains only "shell-safe" ASCII characters it is returned as-is, without quotes.

If the argument is a ref but is not an object which stringifies, then vis() is called and the resulting string quoted. An undefined value is shown as undef without quotes; as a special case to avoid ambiguity the string 'undef' is always "quoted".

qshpath [$might_have_tilde_prefix]

Similar to qsh except that an initial ~ or ~username is left unquoted. Useful for paths given to bash or csh.

qshlist @items

Format e.g. a shell command and arguments, quoting when necessary.

Returns a string with the items separated by spaces.

LIMITATIONS

Interpolated Strings

ivis and dvis evaluate expressions in the user's context using Perl's debugger support ('eval' in package DB -- see perlfunc). This mechanism has some limitations:

@_ will appear to have the original arguments to a sub even if "shift" has been executed. However if @_ is entirely replaced, the correct values will be displayed.

A lexical ("my") sub creates a closure, and variables in visible scopes which are not actually referenced by your code may not exist in the closure; an attempt to display them with ivis will fail. For example:

    our $global;
    sub outerfunc {
      my sub inner {
        say dvis '$global'; # croaks with "Error interpolating '$global'"
        # my $x = $global;  # ... unless this is un-commented
      }
      &inner();
    }
    &outerfunc;
Multiply-referenced items

If a structure contains several refs to the same item, the first ref will be visualized by showing the referenced item as you might expect.

However subsequent refs will look like $VAR1->place where place is the location of the first ref in the overall structure. This is how Data::Dumper indicates that the ref is a copy of the first ref and thus points to the same datum. "$VAR1" is an artifact of how Data::Dumper would generate code using its "Purity" feature. Data::Dumper::Interp does nothing special and simply passes through these annotations.

The special "_" stat filehandle may not be preserved

Data::Dumper::Interp queries the operating system to obtain the window size to initialize $Foldwidth, if it is not already defined; this may change the "_" filehandle. After the first call (or if you pre-set $Foldwidth), the "_" filehandle will not change across calls.

DIFFERENCES FROM Data::Dumper

Results differ from plain Data::Dumper output in the following ways (most substitutions can be disabled via Config options):

  • A final newline is never included.

    Everything is shown on a single line if possible, otherwise wrapped to your terminal width (or $Foldwidth) with indentation appropriate to structure levels.

  • Printable Unicode characters appear as themselves instead of \x{ABCD}.

    Note: If your data contains 'wide characters', you should use open IO => ':locale'; or otherwise arrange to encode the output for your terminal. You'll also want use utf8; if your Perl source contains characters outside the ASCII range.

    Undecoded binary octets (e.g. data read from a 'binmode' file) will still be escaped as individual bytes when necessary.

  • Spaces·may·be·shown·visibly.

  • '␤' may be shown for newline, and similarly for other ASCII control characters.

  • The internals of objects are not shown by default.

    If stringifcation is overloaded it is used to obtain the object's representation. For example, bignum and bigrat numbers are shown as easily readable values rather than "bless( {...}, 'Math::...')".

    Stingified objects are prefixed with "(classname)" to make clear what happened.

    The "virtual" value of objects which overload a dereference operator (@{} or %{}) is displayed instead of the object's internals.

  • Hash keys are sorted treating numeric "components" numerically. For example "A.20" sorts before "A.100".

  • Punctuation variables such as $@, $!, and $?, are preserved over calls.

  • Numbers and strings which look like numbers are kept distinct when displayed, i.e. "0" does not become 0 or vice-versa. Floating-point values are shown as numbers not 'quoted strings' and similarly for stringified objects.

    Although such differences might be immaterial to Perl during execution, they may be important when communicating to a human.

SEE ALSO

Data::Dumper

Jim Avera (jim.avera AT gmail)