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
|
|
|
|
|
|
|
|