Better tests
[data-dump-sexp.git] / lib / Data / Dump / Sexp.pm
CommitLineData
9336e296
MG
1package Data::Dump::Sexp;
2
3use 5.014000;
4use strict;
5use warnings;
6use parent qw/Exporter/;
7
8our @EXPORT = qw/dump_sexp/;
9our @EXPORT_OK = @EXPORT;
10
11our $VERSION = '0.001';
12
13use Carp qw/croak/;
14use Data::SExpression;
15use Scalar::Util qw/reftype looks_like_number/;
16
17sub dump_sexp;
18
19sub dump_scalar {
20 my ($expr) = @_;
21 if (!defined $expr) {
22 "()"
23 } elsif (looks_like_number $expr) {
24 "$expr"
25 } else {
26 my $escaped = $expr;
27 $escaped =~ s,\\,\\\\,g;
28 $escaped =~ s,",\\",g;
29 qq,"$escaped",
30 }
31}
32
33sub dump_cons {
34 my ($expr) = @_;
35 my $cdr = $expr->cdr;
36 my $car = $expr->car;
37 my $acc = '(' . dump_sexp($car);
38 while (eval { $cdr->isa('Data::SExpression::Cons') }) {
39 $car = $cdr->car;
40 $cdr = $cdr->cdr;
41 $acc .= ' ' . dump_sexp($car);
42 }
43 if (defined $cdr) {
44 $acc .= ' . ' . dump_sexp($cdr);
45 }
46 $acc . ')'
47}
48
49sub dump_array {
50 my ($expr) = @_;
51 '(' . join (' ', map { dump_sexp($_) } @$expr). ')'
52}
53
54sub dump_hash {
55 my ($expr) = @_;
56 my @alist = map { Data::SExpression::cons $_, $expr->{$_} } sort keys %$expr;
57 dump_array \@alist
58}
59
60
61sub dump_sexp {
62 my ($expr) = @_;
63 my $type = reftype $expr;
64 if (eval { $expr->can('to_sexp') }) {
65 dump_sexp $expr->to_sexp
66 } elsif (eval { $expr->isa('Data::SExpression::Symbol') }) {
67 "$expr"
68 } elsif (eval { $expr->isa('Data::SExpression::Cons') }) {
69 dump_cons $expr
70 } elsif (!defined $type) {
71 dump_scalar $expr
72 } elsif ($type eq 'ARRAY') {
73 dump_array $expr
74 } elsif ($type eq 'HASH') {
75 dump_hash $expr
76 } elsif ($type eq 'SCALAR' || $type eq 'REF' || $type eq 'LVALUE') {
77 dump_sexp $$expr
78 } else {
79 croak "Cannot dump value of type $type as sexp"
80 }
81}
82
831;
84__END__
85
86=encoding utf-8
87
88=head1 NAME
89
90Data::Dump::Sexp - convert arbitrary scalars to s-expressions
91
92=head1 SYNOPSIS
93
94 use Data::Dump::Sexp;
95 use Data::SExpression qw/cons/;
96 say dump_sexp 5; # 5
97 say dump_sexp "yes"; # "yes"
98 say dump_sexp [1, "yes", 2]; # (1 "yes" 2)
99 say dump_sexp { b => 5, a => "yes"} # (("a" . "yes") ("b" . 5))
100
101=head1 DESCRIPTION
102
103B<This module is not well-tested, proceed with caution>.
104
105Data::Dump::Sexp converts Perl structures to S-expressions.
106
107The conversion rules are as follows:
108
109=over
110
111=item 1
112
113A blessed object with a B<to_sexp> method is replaced with the result
114of calling the method, and this procedure is restarted.
115
116=item 2
117
118An instance of L<Data::SExpression::Symbol> is converted to a symbol.
119
120=item 3
121
122An instance of L<Data::SExpression::Cons> is converted to a cons cell
123(like C<(A . B)>), a proper list (like C<(A B C)>) or an improper list
124(like C<(A B . C)>), where A, B, C are S-expressions.
125
126=item 4
127
128undef is converted to the empty list.
129
130=item 5
131
132A defined scalar that looks like a number is left as-is.
133
134=item 6
135
136A defined scalar that does not look like a number is surrounded by
137double quotes after any backslashes and double quote characters are
138escaped with a backslash.
139
140=item 7
141
142An arrayref is converted to a proper list.
143
144=item 8
145
146A hashref is converted to an alist, which is a proper list of cons
147cells (like C<((A . B) (C . D) (E . F))>).
148
149=item 9
150
151A scalarref or a reference to another ref is dereferenced and this
152procedure is restarted.
153
154=item 10
155
0babca11
MG
156Anything else (coderef, regexp, filehandle, format, globref, version
157string) causes an exception to be raised
9336e296
MG
158
159=back
160
161A single function is exported by default:
162
163=over
164
165=item B<dump_sexp> I<$expr>
166
167Given any Perl scalar, convert it to a S-expression and return the
168sexp as a string.
169
170=back
171
172=head1 AUTHOR
173
174Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
175
176=head1 COPYRIGHT AND LICENSE
177
178Copyright (C) 2018 by Marius Gavrilescu
179
180This library is free software; you can redistribute it and/or modify
181it under the same terms as Perl itself, either Perl version 5.24.1 or,
182at your option, any later version of Perl 5 you may have available.
183
184
185=cut
This page took 0.0215 seconds and 4 git commands to generate.