File Coverage

blib/lib/Acme/Data/Dumper/Extensions.pm
Criterion Covered Total %
statement 25 27 92.5
branch 3 6 50.0
condition n/a
subroutine 8 9 88.8
pod 0 1 0.0
total 36 43 83.7


line stmt bran cond sub pod time code
1 1     1   48885 use 5.006; # our
  1         3  
2 1     1   6 use strict;
  1         1  
  1         18  
3 1     1   4 use warnings;
  1         5  
  1         60  
4              
5             package Acme::Data::Dumper::Extensions;
6              
7             our $VERSION = '0.001000';
8              
9             # ABSTRACT: Experimental Enhancements to core Data::Dumper
10              
11             # AUTHORITY
12              
13 1     1   7 use Data::Dumper ();
  1         1  
  1         15  
14 1     1   4 use Exporter ();
  1         1  
  1         26  
15              
16             my $DD_Defaults;
17              
18             BEGIN {
19 1     1   5 no warnings 'once';
  1         1  
  1         107  
20 1     1   12 $DD_Defaults = {
21             Bless => q[bless],
22             Deepcopy => 0,
23             Deparse => 0,
24             Freezer => q[],
25             Indent => 2,
26             Maxdepth => 0,
27             Pad => q[],
28             Pair => q[ => ],
29             Purity => 0,
30             Quotekeys => 1,
31             Sortkeys => 0,
32             Terse => 0,
33             Toaster => q[],
34             Useperl => !( grep $_ eq 'Data::Dumper', @DynaLoader::dl_modules ),
35             Useqq => 0,
36             Varname => q[VAR],
37             };
38              
39 1 50       2 $DD_Defaults->{Sparseseen} = 0 if eval { Data::Dumper->VERSION(2.136) };
  1         24  
40 1 50       3 $DD_Defaults->{Maxrecurse} = 1000 if eval { Data::Dumper->VERSION(2.153) };
  1         8  
41 1 50       2 $DD_Defaults->{Trailingcomma} = 0 if eval { Data::Dumper->VERSION(2.160) };
  1         278  
42             }
43              
44             sub DD_Defaults {
45 0     0 0   { %$DD_Defaults }
  0            
46             }
47              
48             our $_new_with_defaults = sub {
49             my ( $self, $user_defaults ) = @_;
50              
51             my $instance = $self->new( [] );
52              
53             # Initialise with system defaults
54             my $instance_defaults = { %{$DD_Defaults} };
55              
56             # Validate and overwrite user defaults
57             for my $key ( sort keys %{ $user_defaults || {} } ) {
58             if ( not exists $DD_Defaults->{$key} ) {
59             my $guesskey = ucfirst( lc($key) );
60             my $dym =
61             exists $DD_Defaults->{$guesskey}
62             ? sprintf q[ (did you mean '%s'?)], $guesskey
63             : q[];
64             die sprintf "Unknown feature '%s'%s", $key, $dym;
65             }
66             $instance_defaults->{$key} = $user_defaults->{$key};
67             }
68              
69             # Set all values
70             for my $key ( sort keys %{$instance_defaults} ) {
71              
72             # Properties that aren't methods are bad?
73             my $sub = $instance->can($key);
74             die "No setter for feature '$key'" unless $sub;
75             $instance->$sub( $instance_defaults->{$key} );
76             }
77             return $instance;
78             };
79              
80             our $_DumpValues = sub {
81             my ( $self, $values, $names ) = @_;
82              
83             die "Expected array of values to dump" if not defined $values;
84             die "Dump values is not an array" unless q[ARRAY] eq ref $values;
85              
86             $names = [] unless defined $names;
87              
88             my (@out) = $self->Reset()->Names($names)->Values($values)->Dump;
89             $self->Reset()->Names( [] )->Values( [] );
90              
91             return wantarray ? @out : join q[], @out;
92             };
93              
94             our @EXPORT_OK = qw( $_new_with_defaults $_DumpValues );
95              
96 1     1   34 BEGIN { *import = \&Exporter::import; }
97              
98             1;
99              
100             =head1 NAME
101              
102             Acme::Data::Dumper::Extensions - Experimental Enhancements to core Data::Dumper
103              
104             =head1 SYNOPSIS
105              
106             use Data::Dumper;
107             use Acme::Data::Dumper::Extensions qw/$_new_with_defaults/;
108              
109             local $Data::Dumper::Indent = 5;
110              
111             my $instance = Data::Dumper->$_new_with_defaults({ }); # Indent is still 2!
112              
113             $instance = Data::Dumper->$_new_with_defaults({
114             Indent => 4, # Easier initalizer
115             });
116              
117             =head1 DESCRIPTION
118              
119             This is just a testing ground for things that I'm suggesting for Data::Dumper.
120              
121             It will likely be terrible because bolting on features after-the-fact its also
122             pretty ugly.
123              
124             But its just a prototype.
125              
126             For some, it will serve more as a proof-of-concept for various interfaces until
127             they get accepted into core.
128              
129             =head1 EXPORTS
130              
131             =head2 C<$_new_with_defaults>
132              
133             This is a prototype function for construcing a Data::Dumper instance without
134             being prone to leak from other people using the global values.
135              
136             At the time of this writing, if you need perfect consistency from Data::Dumper
137             in widely used code, you by necessity have to know every version of
138             Data::Dumper that exists, and know what the default values are of various
139             arguments, in order to revert them to your "known good" state if 3rd party
140             code decides to locally change those values for their own purposes.
141              
142             Getting an instance of a Data::Dumper object before anyone tweaks those values
143             would also work, but trying to bet on getting loaded and getting an instance
144             before anyone else does is just foolhardy
145              
146             Additionally, due to how C<< ->Values >> works, having a global instance of
147             Data::Dumper can lend itself to a memory leak and you have to take additional
148             care to make sure you free values passed to it.
149              
150             =head3 Syntax
151              
152             The name used here is C<$_new_with_defaults> as this makes it straight forward
153             to migrate code that uses this once its adopted, without needing to
154             monkey-patch Data::Dumper itself.
155              
156             Data::Dumper->$_new_with_defaults( ... )
157             Data::Dumper->new_with_defaults( ... )
158              
159             =head3 Arguments
160              
161             # Using the defaults
162             Data::Dumper->$_new_with_defaults()
163              
164             # Augmenting the defaults
165             Data::Dumper->$_new_with_defaults({ Name => value, Name => value });
166              
167             The approach I've taken here is to ignore the standard arguments to C,
168             because it wasn't clear to me how else to organise this with the existing
169             alternative interfaces.
170              
171             Given there's an alternative way of passing the dump values, its suggested
172             to just use those until this part of the design is sorted out:
173              
174             Data::Dumper->$_new_with_defaults()->Values([ stuff, to, dump ])->Dump();
175              
176             Or use the other feature suggested in this module:
177              
178             Data::Dumper->$_new_with_defaults()->$_DumpValues([ stuff, to, dump ]);
179              
180             =head3 Unrecognised Features
181              
182             I'm still not sure how to handle what happens when somebody passes the name
183             of a feature which doesn't exist yet, but does in a future version.
184              
185             Ideally, calling C<$_new_with_defaults()> should give you the same results in
186             perpetuity ( or at least, from the date this feature gets added )
187              
188             For now I think the best thing to do is die fatally if a feature that is
189             requested can't be provided, as that will produce output other than is desired
190             and violate output consistency as a result.
191              
192             This will just become a nightmare if somebody ever changes "The Default" for
193             a I feature wherein, users have to I<< Opt-B >>, causing an
194             explosion on older versions where that feature didn't exist.
195              
196             This should be a hazard to never even consider changing the default behaviour.
197              
198             =head2 C<$_DumpValues>
199              
200             This function is a helper that does what people who maintain a long-lived
201             C instance generally desire: The ability to just set up an
202             instance, and then call it an arbitrary number of times with arbitrary inputs
203             and have it act without side effects.
204              
205             However, the current implementation of Data::Dumper is such that if you have
206             an instance, you must B store the data in the object, and B
207             dump it, which introduces fun problems with your data living longer than you
208             intended it to.
209              
210             Currently, you also must call C<< ->Reset >> after dumping to reset the
211             C state.
212              
213             This function is designed to be used atomically. Any pre-existing variable
214             state (eg: C, C, C ) should be thouroughly ignored, and
215             any of those values will be left in a "reset" state after using this function.
216              
217             It is thus inadvisable to combine use of this function with others.
218              
219             If you need complex behaviours provided by the more advanced interfaces, its
220             recommended to use those instead.
221              
222             =head3 Syntax
223              
224             # Dump array of values as a string
225             $instance->$_DumpValues( [ values ] );
226              
227             # Dump array of values with predefined names
228             $instance->$_DumpValues( [ values, ... ], [ names, ... ]);
229              
230             =head3 Arguments
231              
232             The first argument (required) must be an C of values to dump.
233              
234             This value will B be used instead of any instances of C passed
235             earlier. Any values previously passed to C will be preserved.
236              
237             The second (optional) argument is an C of names to use for values.
238              
239             If this option is omitted, it will behave as if you'd passed C<[]>.
240              
241             If this option is present, passed values used instead.