File Coverage

blib/lib/Data/Undump/PPI.pm
Criterion Covered Total %
statement 70 72 97.2
branch 32 46 69.5
condition 7 11 63.6
subroutine 8 8 100.0
pod 2 2 100.0
total 119 139 85.6


line stmt bran cond sub pod time code
1             #!perl
2             package Data::Undump::PPI;
3 4     4   62867 use warnings;
  4         7  
  4         127  
4 4     4   24 use strict;
  4         5  
  4         204  
5              
6             our $VERSION = '0.06';
7              
8             =head1 Name
9              
10             Data::Undump::PPI - Perl extension for limited undumping of data structures
11             (via PPI, not eval)
12              
13             =head1 Synopsis
14              
15             =for comment
16             Remember to test this by copy/pasting to/from 91_author_pod.t
17              
18             use Data::Dumper;
19             use Data::Undump::PPI; # "Undump()" is exported by default
20             $Data::Dumper::Purity=1; # should always be turned on for Undump
21            
22             my @input = ( {foo=>"bar"}, ["Hello","World"], "undumping!" );
23             my $str = Dumper(@input); # dump the data structure to a string
24             my @parsed = Undump($str); # parse the data structure back out
25             # @parsed now looks identical to @input (is a deep copy)
26            
27             use Data::Undump::PPI qw/Dump Undump/; # additionally import "Dump()"
28             Dump(\@input, file=>'/tmp/test.conf'); # Data::Dumper to file
29             my @conf = Undump(file=>'/tmp/test.conf'); # Undump directly from file
30              
31             =head1 Description
32              
33             This module allows for I undumping and round-tripping of data
34             structures from strings generated by L
35             (and possibly other dumper modules, but that's currently not explicitly supported).
36             It is a thin wrapper around L, so please
37             see L for more details, including the limitations.
38              
39             When using L, make sure to always turn on its
40             C option and turn off its C option, as otherwise
41             L may produce code that may not evaluate
42             back to the same data structure, sometimes even though it's valid,
43             parseable Perl! See also L for a helper function.
44              
45             =head2 C
46              
47             my @out = Undump($string);
48             my @out = Undump(file => $filename);
49             my @out = Undump(fh => $filehandle);
50              
51             Accepts either a string, a filename or a filehandle, parses it and
52             attempts to return the data as it would have been passed to
53             L's C. This means that the C<$VAR1>,
54             C<$VAR2> etc. variable names generated by C will be removed and the
55             argument list passed to C is returned, and if the string ends
56             on a true value, that will be ignored so that parsing files which end on
57             e.g. C<1;>, like those generated by the L helper function, will work.
58              
59             In list context, this function returns the list of values as they would
60             have been passed as the arguments to C. If you know that the
61             data contains only one value, you may call C in scalar context to
62             get that value.
63             If you call C in scalar context but the data contains more than
64             one value, currently the I value is returned and a warning is issued
65             (in the "Config::Perl" warnings category).
66              
67             If the string doesn't look like the output of L,
68             this function will throw an exception, and any errors from
69             L's C will also be passed through.
70              
71             If you used L's ability to give the dumped
72             variables user-specified names, you will need to use
73             L to parse that, since C only supports
74             the C<$VAR...> style output of C.
75              
76             This function is exported by default.
77              
78             =head2 C
79              
80             my $str = Dump(\@data);
81             Dump(\@data, file => $filename);
82             Dump(\@data, fh => $filehandle);
83             Dump(\@data, ..., %dumper_options); # e.g.:
84             Dump(\@data, file => $filename, Deepcopy=>1);
85              
86             This function is a simple helper for L which
87             sets some default options and always returns a string, optionally writing
88             that string to a file or filehandle.
89              
90             The L options that can be set are:
91             C (default: off), C (default: on),
92             C (default: off), C (default: on), and
93             C (default is L's default).
94             Note that C is always off and C is always on.
95              
96             When writing to a file, the output is prefixed with C<#!perl> and
97             ended with C<1;>, this is I the case when writing to a filehandle.
98              
99             =head2 More Details
100              
101             This module aims to support most of L's features
102             except code references and (currently) Ced objects.
103             If you find a L data structure that this module
104             does not yet support, please feel free to send in your data structure, as
105             it can help extend L's features and help fix bugs.
106             Currently, using modules other than L may not work,
107             for example, L sometimes generates code with the C<..>
108             range operator, which is currently not supported by L.
109             In the future, this module's features may be extended to more fully support
110             dumper modules like L as well.
111              
112             Although L now supports self-referential data
113             structures, you can also use L's C
114             option to get rid of references within data structures,
115             if the loss of references and copying of data is acceptable for your application.
116              
117             This module is part of the L distribution,
118             but was named separately in an attempt to make its purpose more clear
119             and its name a little easier to remember.
120              
121             This document describes version 0.06 of the module.
122             Although this module has a fair number of tests, it still lacks some
123             features (see L) and there may be bugs lurking.
124             Contributions are welcome!
125              
126             =head1 Author, Copyright, and License
127              
128             Copyright (c) 2015 Hauke Daempfling (haukex@zero-g.net).
129              
130             This library is free software; you can redistribute it and/or modify
131             it under the same terms as Perl 5 itself.
132              
133             For more information see the L,
134             which should have been distributed with your copy of Perl.
135             Try the command "C" or see
136             L.
137              
138             =cut
139              
140 4     4   12 use Carp;
  4         5  
  4         220  
141 4     4   14 use Exporter 'import';
  4         5  
  4         244  
142              
143             our @EXPORT = qw/Undump/; ## no critic (ProhibitAutomaticExportation)
144             our @EXPORT_OK = qw/Undump Dump/;
145             our %EXPORT_TAGS = ( ':all' => [qw/Undump Dump/] );
146              
147 4     4   1395 use Config::Perl;
  4         7  
  4         121  
148 4     4   1981 use Data::Dumper ();
  4         16517  
  4         2364  
149              
150             sub Undump { ## no critic (RequireArgUnpacking)
151 60     60 1 51756 my ($in);
152 60 100       157 if (@_==1)
    50          
153 58         94 { $in = \( shift ) }
154             elsif (@_==2) {
155 2         4 my ($k,$v) = @_;
156 2 100       6 if ($k eq 'file')
    50          
157 1         1 { $in = $v }
158             elsif ($k eq 'fh') {
159 1         3 local $/ = undef;
160 1         26 $in = \( scalar <$v> );
161             }
162             else
163 0         0 { croak "Undump: unknown option \"$k\"" }
164             }
165             else
166 0         0 { croak "bad number of arguments to Undump" }
167 60 50       153 croak "Undump was passed an undef value"
168             unless defined $in;
169            
170 60         233 my $parsed = Config::Perl->new->parse_or_die($in);
171 60         247 my $data_dumper=1; # does this look like Data::Dumper output?
172 60   100     16150 /^(?:\$VAR\d+|_)$/ or $data_dumper=0 for keys %$parsed;
173 60 100       152 if (exists $$parsed{_}) {
174 26 100 66     27 $data_dumper=0 unless @{ $$parsed{_} }==1 && $$parsed{_}[0];
  26         121  
175 26         48 delete $$parsed{_};
176             }
177 60 100       531 croak "input doesn't look like Data::Dumper output"
178             unless $data_dumper;
179             # sort the $VAR\d+ variables correctly
180             my @out =
181 289         412 map { $$parsed{ $$_[0] } }
182 724         641 sort { $$a[1] <=> $$b[1] }
183 55         135 map { [$_, /^\$VAR(\d+)$/] }
  289         846  
184             keys %$parsed;
185 55 100       179 if (wantarray)
186 54         361 { return @out }
187             else {
188 1 50       170 warnings::warnif('Config::Perl','Undump was called in scalar context '
189             .'but data contained more than one value') if @out>1;
190 1         10 return $out[-1]; # behave like comma operator in scalar context
191             }
192             }
193              
194             sub Dump { ## no critic (RequireArgUnpacking)
195 3     3 1 1377 my $data = shift;
196 3 50       10 croak "first argument to Dump must be an arrayref"
197             unless ref $data eq 'ARRAY';
198 3         8 my %opts = @_;
199 3         5 my %KNOWN_OPTS = map {$_=>1} qw/ fh file Deepcopy Useqq Quotekeys Sortkeys Indent /;
  21         31  
200             exists $KNOWN_OPTS{$_} or croak "Dump: unknown option \"$_\""
201 3   33     14 for keys %opts;
202             croak "Dump: options fh and file may not be used together"
203 3 50 66     13 if defined $opts{fh} && defined $opts{file};
204            
205 3         17 my $dd = Data::Dumper->new($data);
206 3 50       78 $dd->Deepcopy (defined $opts{Deepcopy} ? $opts{Deepcopy} : 0);
207 3 50       35 $dd->Useqq (defined $opts{Useqq} ? $opts{Useqq} : 1);
208 3 50       17 $dd->Quotekeys(defined $opts{Quotekeys} ? $opts{Quotekeys} : 0);
209 3 50       15 $dd->Sortkeys (defined $opts{Sortkeys} ? $opts{Sortkeys} : 1);
210 3 50       13 $dd->Indent($opts{Indent}) if defined $opts{Indent};
211 3         7 $dd->Purity(1)->Terse(0);
212 3         23 my $str = $dd->Dump;
213             # I think Data::Dumper always ends on a semicolon, but just to be paranoid...
214 3 50       138 $str .= ";" unless $str=~/;\s*$/;
215            
216 3         5 my $fh = $opts{fh};
217 3 100       7 if (defined $opts{file}) {
218             open $fh, '>', $opts{file} ## no critic (RequireBriefOpen)
219 1 50       55 or croak "Dump couldn't open \"$opts{file}\" for writing: $!";
220 1         16 print $fh "#!perl\n";
221             }
222 3 100       6 if (defined $fh) {
223 2         5 print $fh $str;
224             # I think Data::Dumper always ends on a newline, but just to be paranoid...
225 2 50       8 print $fh "\n" unless $str=~/\n\z/;
226             }
227 3 100       8 if (defined $opts{file}) {
228 1         2 print $fh "1;\n";
229 1         34 close $fh;
230             }
231            
232 3         28 return $str;
233             }
234              
235              
236             1;
237