Git Product home page Git Product logo

data-printer's Introduction

Data::Printer

Coverage Status CPAN version

Data::Printer is a Perl module to pretty-print Perl data structures and objects in full color, in a way that is properly formatted to be inspected by a human.

Basic Usage:

    my $data = get_some_data_from_somewhere();
    ...
    use DDP; p $data;  # <-- pretty-prints $data's content to STDERR

See Data::Printer in action

Main features:

  • Variable dumps designed for easy parsing by the human brain, not a machine;

  • Highly customizable, from indentation size to depth level. You can even rename the exported p() function!

  • Beautiful (and customizable) colors to highlight variable dumps and make issues stand-out quickly on your console. Comes bundled with several themes for you to pick.

  • Filters for specific data structures and objects to make debugging much, much easier. Includes filters for several popular classes from CPAN like JSON::*, URI, HTTP::*, LWP, Digest::*, DBI and DBIx::Class, printing what really matters to developers debugging code. It also lets you create your own custom filters easily.

  • Lets you inspect information that's otherwise difficult to find/debug in Perl 5, like circular references, reference counting (refcount), weak/read-only information, even estimated data size - all to help you spot issues with your data like leaks without having to know a lot about internal data structures or install heavy-weight tools like Devel::Gladiator.

  • keep your custom settings on a .dataprinter file that allows different options per module being analyzed! You may also create a custom profile class with your preferences and filters and upload it to CPAN.

  • output to many different targets like files, variables or open handles (defaults to STDERR). You can send your dumps to the screen or anywhere else, and customize this setting on a per-project or even per-module basis, like print everything from Some::Module to a debug.log file with extra info, and everything else to STDERR.

  • Easy to learn, easy to master. Seriously, what you already know cover about 90% of all use cases.

  • Works on Perl 5.8 and later Because you can't control where you debug, we try our best to be compatible with all versions of Perl 5.

  • Best of all? No non-core dependencies, Zero. Nada. so don't worry about adding extra weight to your project, as Data::Printer can be easily added/removed.

Please refer to Data::Printer's complete documentation for details on how to customize the output to your needs. Or (after installation) type:

perldoc Data::Printer

To view the complete docs on your terminal.

Installation

To install this module via cpanm:

> cpanm Data::Printer

Or, at the cpan shell:

cpan> install Data::Printer

If you wish to install it manually, download and unpack the tarball and run the following commands:

perl Makefile.PL
make
make test
make install

Of course, instead of downloading the tarball you may simply clone the git repository:

$ git clone git://github.com/garu/Data-Printer.git

Thank you for using Data::Printer! Please let me know of potential issues, bugs and wishlists :)

LICENSE AND COPYRIGHT

Copyright (C) 2011-2024 Breno G. de Oliveira

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

data-printer's People

Contributors

2shortplanks avatar arpadszasz avatar bessarabov avatar bk avatar book avatar dsteinbrunner avatar dur-randir avatar fschlich avatar garu avatar haarg avatar hakonhagland avatar iarna avatar jberger avatar jest avatar karenetheridge avatar klaernie avatar leonerd avatar leont avatar manwar avatar nrdvana avatar oalders avatar oylenshpeegul avatar rabbiveesh avatar renatocron avatar rwp0 avatar sdt avatar shadowcat-mst avatar smonff avatar sugyan avatar yanick avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

data-printer's Issues

Test Failures on Perl 5.16.3

Output from make test on CentOS 7's system Perl 5.16.3:

t/05-obj.t .................. 1/? 
#   Failed test 'testing objects (inherited => "all")'
#   at t/05-obj.t line 126.
#          got: 'Foo  {
#     Parents       Bar
#     public methods (9) : bar (Bar), baz, borg, can (UNIVERSAL), DOES (UNIVERSAL), foo, import (UNIVERSAL), isa (UNIVERSAL), new
#     private methods (3) : _moo (Bar), _other, _VERSION (version::vpp)
#     internals: {
#         test   42
#     }
# }'
#     expected: 'Foo  {
#     Parents       Bar
#     public methods (9) : bar (Bar), baz, borg, can (UNIVERSAL), DOES (UNIVERSAL), foo, isa (UNIVERSAL), new, VERSION (UNIVERSAL)
#     private methods (2) : _moo (Bar), _other
#     internals: {
#         test   42
#     }
# }'

#   Failed test 'testing objects (inherited => "public")'
#   at t/05-obj.t line 144.
#          got: 'Foo  {
#     Parents       Bar
#     public methods (9) : bar (Bar), baz, borg, can (UNIVERSAL), DOES (UNIVERSAL), foo, import (UNIVERSAL), isa (UNIVERSAL), new
#     private methods (1) : _other
#     internals: {
#         test   42
#     }
# }'
#     expected: 'Foo  {
#     Parents       Bar
#     public methods (9) : bar (Bar), baz, borg, can (UNIVERSAL), DOES (UNIVERSAL), foo, isa (UNIVERSAL), new, VERSION (UNIVERSAL)
#     private methods (1) : _other
#     internals: {
#         test   42
#     }
# }'

#   Failed test 'testing objects (inherited => "private")'
#   at t/05-obj.t line 162.
#          got: 'Foo  {
#     Parents       Bar
#     public methods (4) : baz, borg, foo, new
#     private methods (3) : _moo (Bar), _other, _VERSION (version::vpp)
#     internals: {
#         test   42
#     }
# }'
#     expected: 'Foo  {
#     Parents       Bar
#     public methods (4) : baz, borg, foo, new
#     private methods (2) : _moo (Bar), _other
#     internals: {
#         test   42
#     }
# }'
# Looks like you failed 3 tests of 21.
t/05-obj.t .................. Dubious, test returned 3 (wstat 768, 0x300)

Use faster sorting module if available

Sort::Key::Natural is faster than Sort::Naturally, and the newer Sort::Naturally::XS is even faster. If the user has them installed already, they should be used.

Suggestion: support for extended colors

Hi garu,

I really like this module. I am wondering if you'd consider supporting the extended colorset (color index 16 - 255). I am thinking that all this would be possible:

use Data::Printer {
  color => {
     array       => 'bright_white',  # ANSI, index 15
     number      => 4,               # ANSI, index 4, blue
     string      => 220,             # Extended; index 220, yellow
     string      => 'red1',          # Extended; index 196, ff0000
     class       => 'orchid',        # X11 color name
     undef       => 'sandybrown',    # X11 color name

    ...
  },
};

Term::ExtendedColor can do this. Of course, it doesn't make sense to add another dependency for this (although it can replace Term::ANSIColor, but that'd need some rewriting...), but perhaps it could be added as an optional one; if the user happens to have it installed, this could be allowed.

Or do you think it'd just bring clutter to the table?

Cheers,

Doesn't play nicely with Hash::Objectify

Hi @garu. I hope all is well. :)

Ran across this at $work this morning. I haven't poked around too much, but I do see that this is happening in Hash::Objectified::AUTOLOAD

use strict;
use warnings;

use Data::Printer;
use Hash::Objectify qw( objectify );

my $object = objectify({ foo => 'bar' });

p( $object );
bash-3.2$ perl objectify.pl
Can't locate object method "_data_printer" via package "Hash::Objectified0" at /Users/olaf/perl5/lib/perl5/Hash/Objectify.pm line 83.

DDP if falling with '... is not a module name'

I'm using DDP v0.35. I'm getting YAML from external server, decoding it and
trying to view using DDP. But instead of showing me strucute DDP dies with a
message:

some.method is not a module name at /usr/share/perl5/Package/Stash/PP.pm line 28
        Package::Stash::PP::new('Package::Stash', 'some.method') called at /usr/share/perl5/Data/Printer.pm line 696
        Data::Printer::_class('some.method=HASH(0x2419b40)', 'HASH(0x2218580)') called at /usr/share/perl5/Data/Printer.pm line 281
        Data::Printer::_p('some.method=HASH(0x2419b40)', 'HASH(0x2218580)') called at /usr/share/perl5/Data/Printer.pm line 405
        Data::Printer::ARRAY('ARRAY(0x2222198)', 'HASH(0x2218580)') called at /usr/share/perl5/Data/Printer.pm line 270
        Data::Printer::_p('ARRAY(0x2222198)', 'HASH(0x2218580)') called at /usr/share/perl5/Data/Printer.pm line 535
        Data::Printer::HASH('HASH(0x22221c8)', 'HASH(0x2218580)') called at /usr/share/perl5/Data/Printer.pm line 270
        Data::Printer::_p('HASH(0x22221c8)', 'HASH(0x2218580)') called at /usr/share/perl5/Data/Printer.pm line 236
        Data::Printer::_data_printer('', 'HASH(0x22221c8)') called at /usr/share/perl5/Data/Printer.pm line 162
        Data::Printer::np('HASH(0x22221c8)') called at a.pl line 18

Data::Dumper works ok with this strucure and shows:

$VAR1 = {
          'sample' => [
                        bless( {
                                 'value' => 'bar',
                                 'name' => 'foo'
                               }, 'some.method' )
                      ]
        };

Here is the script to reproduce this behaviour:

#!/usr/bin/perl

use strict;
use warnings FATAL => 'all';

use DDP;
use YAML::Syck;

my $yaml = qq{---
sample:
-  !!some.method
    name: 'foo'
    value: 'bar'
};

my $data = Load($yaml);

p $data;

Data::Printer "bugfix". Please read and comment!

Data::Printer has a problem with return values. By default, it tries to be smart for the user, so if you do:

   use DDP; p $data;

it will dump the data to STDERR. But if you do:

   use DDP; my $ret = p $data;

it will return the dump instead of printing it. This also let's you do stuff like:

   use DDP; print p $data;

in case you want the dump to go to STDOUT instead of STDERR. Of course, you can also achieve this
by doing something like:

  use DDP output => 'stdout'; p $data;

But I digress.

The problem is that, to detect whether the user wants us to return something or not, we rely
on Perl's "wantarray" function. This is all nice and well, except if you look at wantarray's documentation
you'll see a minor catch:

"wantarray()"'s result is unspecified in the top level of a
file, in a "BEGIN", "UNITCHECK", "CHECK", "INIT" or "END"
block, or in a "DESTROY" method.

This means that if you're debugging stuff in BEGIN, DESTROY, etc, you might do something like:

   use DDP; p $data;

and get absolutely nothing. The reverse would also happen, where you could do:

   use DDP; my $str = p $data;

and see it printed on STDERR instead of returned. Of course, since you'll see the data on the screen,
this is less annoying than the former.

I have received some reports that p($data) "wasn't working" meaning it wasn't printing anything on the screen,
and after a lot of debugging I think wantarray's odd behavior might be the cause - specially since the user was within a BEGIN block.

Another huge annoyance where Data::Printer doesn't DWIM is when it's the very last statement of your function.
Let's say you have this:

  sub do_something {
     ...
  }

  my $data = do_something();

and you're debugging the do_something() function, so you want to call p() to see your data before you
continue coding. If you did something like:

  my $data = do_something();
  use DDP; p $data;

then you'd be just fine. The problem lies when you try to mangle inside do_something(). And why
shouldn't you? I mean, you're debugging, right? So you do something like:

  sub do_something {
     ...
     use DDP; p $struct;
  }

  my $data = do_something;

and you get nothing on the output. WTF?

Did you spot what happended?

If you check the docs, you'll see mst warned about this months ago (but who wants
to look at the docs? It's a tool to print data structures. You want it to work, dammit!)

The problem here is that you want something from do_something(), and since you called
p() as the last statement, you basically told perl that do_something() should return
whatever it gets from p(), meaning now p() is NOT in void context, so it returns
the dump instead of printing it on the screen.

If you had made sure p() wasn't the last statement in the function ( p $struct; 1; ) or
if you had called do_something() in void context, or if you had set DDP with the 'pass' return
value (which triggers the pass-through behavior in which p() will always print and
return the value of the actual variable, not the dump string), then everything would have
worked just fine.

Except you didn't, and now you're debugging the debugging tool. Not cool.

At first I thought it wasn't that big a deal, that it was a very specific debugging scenario
and the user would likely known what it was doing. So as long as it was documented,
everything would be fine. Turns out it's not that specific at all, and
the very last thing you want when debugging code is to be bitten by your debugging tool.

I clearly had made a poor design decision, and now that Data::Printer is being used all over (thanks, guys!)
I feel like you should help me out with making the right decision this time, if you want/care.

What should I do? What should Data::Printer do?

Leon Timmermans already helped by pointing out a way to query caller() and see if we're inside the
BEGIN, INIT, etc, blocks, but this doesn't solve the latter issue, which can be even more annoying.

As I see it (and I'm VERY open to other ideas) I have a few ways to "fix" this:

=> Leave it as it is, and add a bigger note on such behavior. I don't like this one, otherwise
I wouldn't be having this argument. But I'm adding it just for thorougness' sake.

=> make p() pass-through by default. This will make p() print the dump to STDERR always
unless you do something about it, where something is:

   use DDP return_value => 'dump'; # go back to the (now, so far) default behavior
   use DDP output => \$var;        # append the dump to $var
   use DDP output => 'stdout';     # use STDOUT instead of STDERR

If we change the default behavior to that, it means that if you ever did something like:

   use DDP; print p $data;

or

   use DDP; warn p $data;

You'll get $data dumped to STDERR and will print whatever is in $data back to STDOUT (via the print() call).

It also means that if you wanted the dump string back, you'd have to change return_value back to "dump" or
point the output property to a scalar reference, like in the first two examples above.

Do people really use the return values? I think they can be quite useful for something like printing to a
debugging webpage, or maybe a log file.

Which brings me to solution #2:

=> Change p()'s default return_value behavior to 'pass' just like in #1, but also exporting a d() function
that would be like p() except always returning the string instead of printing, just like Data::Dumper does.

The reason I'm not in love with this idea is because I don't want to pollute the caller's namespace with
more functions - one should be enough I guess.

We could of course add an alias for d() like we do for p(), or even make the exporting optional. But if the
user has to adjust his/hers "use DDP" parameters, then why can't he/she simply make the changes above?

Which brings me to potential solution #3:

=> Change p()'s default return_value behavior to 'pass' just like in #1, but create a new package called,
say, DDX (heck, we could even use DDP itself so it wouldn't be just an alias do Data::Printer), that
would export 2 functions to the user's namespace (and not just one, as Data::Printer would):

p() - always prints stuff
d() - always returns the string

This could even be enough to fix another annoyance to more advanced Data::Printer users: prototypes.

p() - always prints stuff, uses prototypes
np() - always prints stuff, no prototypes
d() - always returns the string, uses prototypes

Does it look sane-ish to you? Not really? Alternatives?

It could be the case of creating solution #4 in which Data::Printer's p() won't change its default
behavior, but DDP's p() will. But I'm not sure I want to maintain this sort of thing, so I'm more inclined to #2 or #3.

Of course, I'd have to make sure all other customization options are in sync with whatever is chosen
as solution.

If you care and/or have any suggestions, please add a comment below. I'm going to think about this for the next few days and make a decision that hopefully will make Data::Printer an even more reliable tool, specially for beginners.

Create your own IRC channel

Put this into your META.json

{
   "resources" : {
      "x_IRC" : "irc://irc.perl.org/#debughooks"
   },
}

This will create additional link at menu on metacpan: Questions? Chat with us! ( I also available there)
Demo1, Demo2

If you do so your users will reach you simpler and vice versa =)

Maybe it is time to release a new version?

The current CPAN version of Data::Dumper is 0.38. But since that several commits have appeared in master.

The CPAN version thinks the data is a number and does not use quotes around it:

$ perl -MDDP -E '%h = ( a => "asdf", bb => "2016-11-02"); p %h;'
{
    a    "asdf",
    bb   2016-11-02
}

But in master this bug is fixed:

$ perl -Ilib -MDDP -E '%h = ( a => "asdf", bb => "2016-11-02"); p %h;'
{
    a    "asdf",
    bb   "2016-11-02"
}

(here is commit that fixes this c30d6f0 ).

I have stepped several times into this pitfall. My .dataprinter ( https://gist.github.com/bessarabov/1c889f2103101b995ca3cb9abe44d614 ) shows data that can be used in perl code:

$ perl -MDDP -E '%h = ( a => "asdf", bb => "2016-11-02"); p \%h;'
{
    a => 'asdf',
    bb => 2016-11-02,
}

and because there are no quotes around 2016-11-02 in perl this converted into number 2003. This error is super simple, but several times it took me some time to find out what is going on.

So, maybe you can release a new version of Data::Printer?

Why does Data::Printer has and alias DDP

I'm curios to know why does Data::Printer has a short alias DDP. I can imagine
that the first D is for Data and the last P is for Printer, but what does the
middle D means? Maybe it is worth mentioning in the docs.

Tests are broken in master

Commit 81928a7 broke CI tests:

t/26.7-unicode.t ............ 1/? Wide character in print at /home/travis/build/garu/Data-Printer/blib/lib/Data/Printer.pm line 183.
"โ˜ƒ" (U)
#   Failed test 'unicode scalar gets suffix'
#   at t/26.7-unicode.t line 20.
Wide character in print at /home/travis/perl5/perlbrew/perls/5.10/lib/5.10.1/Test/Builder.pm line 1826.
#          got: 'โ˜ƒ'
#     expected: '"โ˜ƒ" (U)'
"๏ฟฝ"
#   Failed test 'ascii scalar without suffix'
#   at t/26.7-unicode.t line 27.
#          got: '๏ฟฝ'
#     expected: '"๏ฟฝ"'
# Looks like you failed 2 tests of 4.
t/26.7-unicode.t ............ Dubious, test returned 2 (wstat 512, 0x200)
Failed 2/4 subtests 

Error with JSON::JOM

Just ran into this yesterday:

$ use JSON::JOM qw/from_json/; 
$ use Data::Printer;           
$ use Data::Dumper;            

my test case

$ my $min_json = '{"alpha":1}';
{"alpha":1}

and the output with Data::Dumper

$ Dumper from_json $min_json
$VAR1 = bless( {
                 'alpha' => bless( do{\(my $o = 1)}, 'JSON::JOM::Value' )
               }, 'JSON::JOM::Object' );

and where Data::Printer breaks

$ p from_json $min_json
Use of uninitialized value $ref in exists at /home/nuba/perl5/perlbrew/perls/perl-5.16.0/lib/site_perl/5.16.0/Data/Printer.pm line 257.
Use of uninitialized value $ref in exists at /home/nuba/perl5/perlbrew/perls/perl-5.16.0/lib/site_perl/5.16.0/Data/Printer.pm line 269.
Runtime error: Package::Stash->new must be passed the name of the package to access at /home/nuba/perl5/perlbrew/perls/perl-5.16.0/lib/site_perl/5.16.0/Data/Printer.pm line 703.

versions I have here:

Data::Dumper 2.135_06
JSON::JOM 0.501
Data::Printer 0.32

support message type "is_complete_request"

Seems this is a new message type in Jupyter 5.0. See http://jupyter-client.readthedocs.io/en/latest/messaging.html#code-completeness

I am getting below error when running the console mode.

$ ./iperl console
[TerminalIPythonApp] WARNING | Subcommand `ipython console` is deprecated and will be removed in future versions.
[TerminalIPythonApp] WARNING | You likely want to use `jupyter console` in the future
Jupyter console 5.0.0

IPerl!


In [1]: 1/usr/lib/python3.5/site-packages/jupyter_console/ptshell.py:571: UserWarning: The kernel did not respond to .
  warn('The kernel did not respond to an is_complete_request. '
In [1]: 1
1

In [2]:                                                                                                               
^[[24;1RTraceback (most recent call last):
  File "/usr/bin/ipython", line 5, in <module>
    start_ipython()
  File "/usr/lib/python3.5/site-packages/IPython/__init__.py", line 119, in start_ipython
    return launch_new_instance(argv=argv, **kwargs)
  File "/usr/lib/python3.5/site-packages/traitlets/config/application.py", line 658, in launch_instance
    app.start()
  File "/usr/lib/python3.5/site-packages/IPython/terminal/ipapp.py", line 344, in start
    return self.subapp.start()
  File "/usr/lib/python3.5/site-packages/jupyter_console/app.py", line 151, in start
    self.shell.mainloop()
  File "/usr/lib/python3.5/site-packages/jupyter_console/ptshell.py", line 463, in mainloop
    self.interact()
  File "/usr/lib/python3.5/site-packages/jupyter_console/ptshell.py", line 448, in interact
    code = self.prompt_for_code()
  File "/usr/lib/python3.5/site-packages/jupyter_console/ptshell.py", line 408, in prompt_for_code
    reset_current_buffer=True)
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/interface.py", line 394, in run
    self.eventloop.run(self.input, self.create_eventloop_callbacks())
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/eventloop/posix.py", line 164, in run
    t()
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/eventloop/posix.py", line 83, in read_from_stdin
    inputstream.feed(data)
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/terminal/vt100_input.py", line 395, in feed
    self._input_parser.send(c)
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/terminal/vt100_input.py", line 304, in _input_parser_generator
    self._call_handler(match, prefix)
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/terminal/vt100_input.py", line 337, in _call_handler
    self.feed_key_callback(KeyPress(key, insert_text))
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/interface.py", line 1023, in feed_key
    cli.input_processor.process_keys()
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/key_binding/input_processor.py", line 201, in process_keys
    self._process_coroutine.send(key_press)
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/key_binding/input_processor.py", line 158, in _process
    self._call_handler(matches[-1], key_sequence=buffer)
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/key_binding/input_processor.py", line 228, in _call_handler
    handler.call(event)
  File "/usr/lib/python3.5/site-packages/prompt_toolkit/key_binding/registry.py", line 31, in call
    return self.handler(event)
  File "/usr/lib/python3.5/site-packages/jupyter_console/ptshell.py", line 342, in _
    more, indent = self.check_complete(d.text)
  File "/usr/lib/python3.5/site-packages/jupyter_console/ptshell.py", line 426, in check_complete
    more = (code.splitlines()[-1] != "")
IndexError: list index out of range

If you suspect this is an IPython bug, please report it at:
    https://github.com/ipython/ipython/issues
or send an email to the mailing list at [email protected]

You can print a more detailed traceback right now with "%tb", or use "%debug"
to interactively debug it.

Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
    c.Application.verbose_crash=True

Clarification on colours, suggestion for prefs file

Great module!

Maybe a documentation clarification/suggestion??

On the first test run, I got this error:

Invalid attribute name bright_white at /usr/local/share/perl5/Data/Printer.pm line 285

I suppose that these colours are defined in Term::ANSIColor v3 (????)

with Term::ANSIColor 2.02 (fedora perl version perl-5.12) no such luck :-/

Off course cleaning out the "bright" in the colours in the .dataprinter config file solves this "issue".

This brings me to the suggestion:

Would it be possible having a global prefs file?
For usage of shared devel boxes, it is easier to manage that having to create files in all the users homes...

once again, thanks for the great module :)

Lack of documentation

Please clear what does this mean: As of version 0.13, you may also use the '-class' filter, which will be called for all non-perl types (objects).

I may suppose you mean this but there is no description for -class

Fix the filter output color and style

Here is the sample script:

#!/usr/bin/perl

use DateTime;
use Data::Printer filters => {
    'DateTime' => sub { $_[0]->ymd },
};

my $foo = {
    dt_filter => DateTime->now(),
    dt_string => '2012-07-13',
};

p $foo;

The output of this script is:

Script output

From my point of view, the filter output should be the same as the
output from the string. I can't imagine when the current output is better
than the one I'm proposing.

Tests fail with bleadperl (scalar(%hash) changes?)

With perl 5.25.3 and later some tests fail like this:

#   Failed test 'pass-through return (hash scalar)'
#   at t/27-pass_through.t line 47.
#                   '1'
#     doesn't match '(?^:^1/\d+$)'
# Looks like you failed 1 test of 24.
t/27-pass_through.t ......... 
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/24 subtests 

I did not look into the issue, but probably it's related to this change (from perl5.25.3's perldelta):

"scalar(%hash)" return signature changed
The value returned for "scalar(%hash)" will no longer show information
about the buckets allocated in the hash. It will simply return the count
of used keys. It is thus equivalent to "0+keys(%hash)".

A form of backwards compatibility is provided via
"Hash::Util::bucket_ratio()" which provides the same behavior as
"scalar(%hash)" provided prior to Perl 5.25.

Not enough care for hash keys

Self explanatory code example:

$ perl -MData::Printer -e '$v={q()=>"empty", q(   )=>"blank", qq(\0\0\0)=>"unescaped", qq(new\nline)=>"multiline"}; p $v'
\ {
           => "empty",
        => "unescaped",
           => "blank",
  new
line => "multiline"
}

(Today I was confused about a hash dump that had an empty string key; it is especially confusing having hash_separator set to default value.)

Probably it would be good to surround key names with quotes if they contain any blank chars (but don't color them so still can distinguish between key quotes and key itself).

Data::Printer should not use $/ as newline

Consider the output from:

my $var = 2;
p $var;

it should give 2 as output. However if I set the input record separator ( note: not the output record separator), for example:

local $/ = "00\n";

# some code ...

my $var = 2;
p $var;

the output is suddenly 200 and not 2 as it should. This is because the input record separator is used to add a newline character to the output in Data::Printer.

I think this is a bug. To fix it, simply replace $/ (inside Data/Printer.pm) with "\n". According to perlport :

Perl uses \n to represent the "logical" newline, where what is logical may depend on the platform in use.

I added a pull request.

filter function with inheritance

I want to add a filter function to display Teng::Row object.
But Data::Printer::Filter checks just the named class. I guess filter function should work with child classes.

code example:

package Foo;
use Moo;
package Bar;
use Moo;
extends 'Foo';
package Data::Printer::Filter::Foo;
filter 'Foo' => sub { };

In this case, just Foo is handled by filter, Bar is not filtered. I think it makes hard to create filters in some case(e.g. Data::Printer::Filter::URI's code can make shorter).

Bug. Data::Printer does not recognize object.

Here is the expected behaviour:

$ perl -MDDP -E '$obj = {}; bless $obj, "MyObj"; p $obj;'
MyObj  {
    public methods (0)
    private methods (0)
    internals: {}
}

But if I use HASH as a CLASSNAME for the bless, Data::Printers starts thinking that this is not an object, but a simple hashref:

$ perl -MDDP -E '$obj = {}; bless $obj, "HASH"; p $obj;'
\ {}

Data::Dumper does not have this problem:

$ perl -MData::Dumper -E '$obj = {}; bless $obj, "MyObj"; warn Dumper $obj;'
$VAR1 = bless( {}, 'MyObj' );
$ perl -MData::Dumper -E '$obj = {}; bless $obj, "HASH"; warn Dumper $obj;'
$VAR1 = bless( {}, 'HASH' );

The same problem is with the ARRAY CLASSNAME:

$ perl -MDDP -E '$obj = []; bless $obj, "ARRAY"; p $obj;'
\ []

class_method invokation doesn't pass properties to method

In writing _data_printer method for PDL I have noticed that the properties hashref is not passed to the method. For example.

sub _data_printer {
  my $self = shift;
  my $p = shift; # <---- undef

}

Here you can see that the method is invoked with no arguments, so my guess is that this is where the problem occurs. I will try to make a patch soon.

Allow filters to tweak handling of repeated objects

While writing Data::Printer::FIlter::JSON I found both JSON::PP and JSON::XS reuse the same address for JSON::PP::Boolean and JSON::XS::Boolean, respectively. This means this input

{
  "foo": false,
  "bar": false,
  "baz": true
}

becomes

DB<1> x decode_json $json
0  HASH(0x8b39b70)
   'bar' => JSON::XS::Boolean=SCALAR(0x8e0ec90)
      -> 0
   'baz' => JSON::XS::Boolean=SCALAR(0x8e0ec00)
      -> 1
   'foo' => JSON::XS::Boolean=SCALAR(0x8e0ec90)
      -> REUSED_ADDRESS

and here https://github.com/garu/Data-Printer/blob/master/lib/Data/Printer.pm#L256 adds it to $p->{_seen}

And my filter outputs just

\ {
    bar   false,
    baz   true,
    foo   var{bar}
}

A possible workaround would be to get Data::Printer to ask my filter whether it should use or skip its automated handling of repeated occurrences of objects of a given class or list of classes -- bonus points if you can read that aloud in one breath :)

Data::Printer::Filter could import np()

Right now Data::Printer::Filter doesn't import np(). I can get around this in my filter with:

require Data::Printer;
return Data::Printer::np( %foo );

That doesn't seem like it's the best way to do this, though. :) I can send a pull request if this is something you're open to.

[wishlist] Using default variable when calling p() without parameters.

Here is my .dataprinter:

{
    use_prototypes => 0,
}

And here is the test script:

#!/usr/bin/perl

use DDP;

foreach (1..2) {
    p;  
    p $_; 
}

It outputs:

undef
1
undef
2

but I'm expected it to output:

1
1
2
2

What you do think? Is this behaviour good and should it be implemented? Or this is the expected behaviour that should be left as it is? Or this is a bug?

By the way, If I run this scrip without custom .dataprinter I'll get error:

Not enough arguments for Data::Printer::p at a.pl line 6, near "p;"
Execution of a.pl aborted due to compilation errors.

Suggestion: support for "color themes"

Maybe color definitions could be extendable objects instead of the flat HashRefs; that would allow easier customizations on top of other's customizations (think Data::Printer::Theme:: namespace at CPAN). For instance, I've made the following color theme that would be interesting for many users of Solarized terminal emulators and would like to put it on the CPAN:

    color           => {
        array       => 'bright_green',      # base01
        number      => 'cyan',
        string      => 'cyan',
        class       => 'yellow',
        method      => 'blue',
        undef       => 'green',
        hash        => 'cyan',
        regex       => 'red',
        code        => 'green',
        glob        => 'bright_red',        # orange
        vstring     => 'cyan',
        repeated    => 'bright_magenta',    # violet
        caller_info => 'bright_green',      # base01
        weak        => 'magenta',
        tainted     => 'bright_magenta',    # violet
        escaped     => 'red',
    }

Devel::REPL colors

They don't work :(
I am able to do:

$ use Term::ANSIColor;

$ print color 'bold blue';
1
$ print "This text is bold blue.\n";
This text is bold blue.
1

(it is bold blue, indeed)
However, DDP simply ignores all the colors.

Problem with printing code references

Hi, I was trying to print a code reference:

use Data::Printer;
my $func = sub { say "Hello" };
p $func;

which gave me the following error:

Not a SCALAR reference at Printer.pm line 191.

Checking out lines 190-192 in Printer.pm:

elsif ( grep { $ref eq $_ } qw(REF SCALAR CODE Regexp GLOB VSTRING) ) {
     return $$item;
}

it seems that the reason for the error is that $item is code ref, and dereferencing code references ($$item) are not permitted.

However, it feels quite strange that no one else has reported this issue before, so it could very well be something that is broken with my setup also..

Anyway, here is the pull request that fixed the problem for me: pull #94

Allow returning dump with ANSI colors

Currently if you use p to return a dump (return_value => 'dump'), it will return the dump without colors. I wish there was a way to return it with the ANSI colors it sets for it if it were printing to STDERR.

This allows passing the colored output between functions and then printing them in due time.

I have one cool feature for a Perl module that could use this functionality. :)

Tests fail if PERL5OPT in use

In installing Data::Printer, I got a test failure from t/08-deparse.t, because I have $PERL5OPT set in my shell.

The test failure was:

#   Failed test 'deparsing'
#   at t/08-deparse.t line 18.
#          got: '\ [
#     [0] 6,
#     [1] sub {
#             BEGIN {
#                 $^H{'feature_say'} = q(1);
#                 $^H{'feature_state'} = q(1);
#                 $^H{'feature_switch'} = q(1);
#             }
#             print 42;
#         },
#     [2] 10
# ]'
#     expected: '\ [
#     [0] 6,
#     [1] sub {
#             print 42;
#         },
#     [2] 10
# ]'
# Looks like you failed 1 test of 1.
t/08-deparse.t .............. 
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/1 subtests

This happened because, in my environment, I have the env varPERL5OPT=-M5.010 to enable modern features.

It would be nice if the env var was cleared before the test ran, so it doesn't get tripped up by it.

Documentation doesn't reflect return_value change

The default return_value was changed from dump to pass, but the documentation hasn't been fully updated to reflect that. The "Minding the return value of p()" and "CUSTOMIZATION" sections both reflect the old default value.

Data::Printer always "autovivifiies" hash keys ?

I can't see an option that would control this.

Here $h{"one"} gets created with an undef value:

% perl -MDDP -E '%h = () ; p $h{"one"}; p %h;'
undef
{
    one   undef
}

The behaviour with Data:::Dumper is different:

% perl -MData::Dumper -E '%h = () ; print Dumper $h{"one"}; print Dumper \%h;'
$VAR1 = undef;
$VAR1 = {};

Create underlying (but not private) object for other modules to use

This is an attempt to fix https://rt.cpan.org/Ticket/Display.html?id=84103 .

My plan is to extract the core of Data::Printer into an object where you call methods on said object to print things. All configuration of the object will unsurprisingly be attributes on the (Moo based) object. If you would like me to implement it another way please comment :)

The first step after that will be to use a single global object for all exports, just to get going. After that we can have an object per package importing into, optionally. Finally, I'd recommend converting the importer to Sub::Exporter as the current alias functionality is also global.

Separate colors for classes and methods

In the current version of Data::Printer (v0.29) the class and the methods are
printed in the same color 'bright_green'. I think it will be a bit more
comfortable if that two this are separated in colors.

Feature Idea: Profiles

Sometimes, I'll be using Data::Printer like this:

use Data::Printer;
p $object;

...only to discover that $object is an inside-out object, and my output contains nothing useful. I then modify my code to look like this:

use Data::Printer
  filters => {
    'My::Class' => sub { p($_[0]->as_hash_ref()) },
  };
p $object;

Now I get useful output. However, I have to do this everywhere I'm debugging these types of objects, which can be across several files. I could put this logic into .dataprinter, but I'd rather keep such specifics out of my standard options. So I propose a new feature: profiles. My .dataprinter would look like this:

{
  profiles => {
   myclass => {
    filters => {
      'My::Class' => sub { p($_[0]->as_hash_ref()) },
    }
   }
  }
}

and I could refer to my profile like so:

use Data::Printer
  use_profile => 'myclass'; # could also be an array ref

p $object;

Thoughts?

Alias for p_without_prototypes

When debugging programs, I often tend to mix the standard "print a variable's value" p $var with simple
messages to STDOUT, like say "Hello" or something similar. However, I would like to replace the latter
say "Hello" with p "Hello" in order to get Data::Printer's caller_info attached to the string "Hello". (Other reasons could be consistency and that it is 2 character less to type). The problem is that p $var, uses prototypes, whereas p "Hello" would require not using prototypes. This means I cannot mix p $var with p "Hello" in a simple manner. The last call must be written:

  • Data::Printer::p_without_prototypes "Hello", or
  • p ${ \"Hello" },

(Note: p ("Hello", use_protypes => 0 ) does not work. ) Neither of these alternatives seems optimal to me compared to the simple p "Hello".

Possible solutions:

  • Let Data::Printer::import() export p_without_prototypes as pwp or pp, or
  • Add a configuration option alias_p_no_prototypes that can be set in the configuration file.

The first option is probably not good as it is not backwards compatible (it could pollute the callers namespace whithout the caller's knowledge and something could in theory break)..

The last option seems viable though: The user simply puts the following into his .dataprinter configuration file: alias_p_no_prototypes => 'pp', and then Data::Printer::import() will import the alias pp into the callers namespace.

I created a pull request

What do you think?

DDP adding too much magic to hash containers?

So, I have a strange issue using DDP in combination with JSON::XS. I'm not entirely sure who is at fault here but I thought I'd have a better chance bugging you and not MLehmann..

Here's the issue:

use DDP;
use JSON; 
my %teh = map {$_,1} qw(apple banana xylophone zephyr); 
np %teh; 
say JSON->new->canonical->encode(\%teh);

#Output:
{"banana":1,"xylophone":1,"apple":1,"zephyr":1}

Note the hash is unordered.. even though 'canonical' should order the keys alphabetically. This problem does not occur if I don't pass the hash to DDP, which means something in DDP is changing it (and Devel::Peek confirms that DDP adds a ton of magic to the hash).

Looking at JSON::XS source shows that it sorts differently based on SV magic, but I'm not enough of a wizard to know what it's actually doing. All I know is that someone is doing something wrong, somewhere.

Option to show overloaded stringification of objects

Hi,

since quite some time back I have a filter 'Path::Tiny' => sub { "$_[0] (Path::Tiny)" } in my .dataprinter, so that Path::Tiny objects are represented by their overloaded stringification. Today I discovered that I really wanted the same for Path::Class objects, but there was a snag: I had to throw in a filter each for Path::Class::File and Path::Class::Dir!
That got me thinking: next time I'll need the same for File::Temp objects too.

So I started writing a Data::Printer::Filter::Path module...

That's when I realized that objects which have an overloaded stringification have it for a reason, and that in practically all cases that stringification is the only really interesting thing about those objects from a data dumping perspective. So why not (a) general option(s) to show objects with overloaded stringification as their stringification? If you happen to be debugging a class with overloaded stringification you could add an overriding filter, or there could be an option no_stringification => ['My::Class', ...].

What do you think? That path filter module will probably come around sooner than later, because there are easily options which are relevant with path objects (at least absolute/relative representation and whether to actually show the path of tempfiles) but surely there is a case for the general case, no?

doc suggestion re circumventing prototypes

In the sections about circumventing prototypes, you might want to also include the trick of dereffing an anonymous structures to make it work with p. For example:

p %{ { foo => 123 } };
p @{ [ 1, 2, 3] };

Also, when 5.24 is released, postderef will no longer be experimental, and this is a little nicer:

p { foo => 123 }->%*;
p [ 1, 2, 3]->@*;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.