Skip to content

Commit fbedf38

Browse files
committed
url_params_build implementation
1 parent 8833b73 commit fbedf38

File tree

3 files changed

+88
-2
lines changed

3 files changed

+88
-2
lines changed

Diff for: lib/URL/Encode.pod

+19
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ URL::Encode - Encoding and decoding of C<application/x-www-form-urlencoded> enco
1414
$params = url_params_mixed($octets [, $utf8 = false]);
1515
$params = url_params_multi($octets [, $utf8 = false]);
1616
url_params_each($octets, $callback [, $utf8 = false]);
17+
18+
$octets = url_params_build($params [, $utf8 = false [, delim = '&'] ]);
1719

1820
=head1 DESCRIPTION
1921

@@ -117,6 +119,23 @@ Invokes the given callback for each URL-decoded name/value pair.
117119

118120
url_params_each($octets, $callback);
119121

122+
=head2 url_params_build
123+
124+
$octets = url_params_build($params);
125+
$octets = url_params_build($params, $utf8);
126+
$octets = url_params_build($params, $utf8, $delim);
127+
128+
Builds a URL-encoded string from the given ARRAY or HASH reference containing
129+
URL-decoded name/value pairs. Multiple occurrences of a parameter may be
130+
specified as an ARRAY reference of values in order. Keys of a HASH reference
131+
will be sorted for consistency.
132+
133+
$octets = url_params_build({ foo => [ 'A', 'B' ], bar => 'C' });
134+
$octets; # bar=C&foo=A&foo=B
135+
136+
$octets = url_params_build([ foo => 'A', foo => 'B', bar => 'C' ]);
137+
$octets; # foo=A&foo=B&bar=C
138+
120139
=head1 EXPORTS
121140

122141
None by default. All functions can be exported using the C<:all> tag or individually.

Diff for: lib/URL/Encode/PP.pm

+27-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ BEGIN {
1414
url_params_each
1515
url_params_flat
1616
url_params_mixed
17-
url_params_multi ];
17+
url_params_multi
18+
url_params_build ];
1819
require Exporter;
1920
*import = \&Exporter::import;
2021
}
@@ -130,5 +131,30 @@ sub url_params_multi {
130131
return \%p;
131132
}
132133

134+
sub url_params_build {
135+
@_ == 1 || @_ == 2 || Carp::croak(q/Usage: url_params_build(params [, utf8 [, delim] ])/);
136+
my ($p, $utf8, $delim) = @_;
137+
$delim = '&' unless defined $delim;
138+
utf8::encode($delim) if $utf8;
139+
140+
my @p = ref $p eq 'HASH' ? (map { ($_ => $p->{$_}) } sort keys %$p) : @$p;
141+
142+
my $s = '';
143+
while (my ($k, $v) = splice @p, 0, 2) {
144+
my @v = ref $v eq 'ARRAY' ? @$v : $v;
145+
for ($k, @v) {
146+
$_ = '' unless defined $_;
147+
utf8::encode($_) if $utf8;
148+
s/([^0-9A-Za-z_.~-])/$EncodeMap{$1}/gs;
149+
}
150+
for (@v) {
151+
$s .= $delim if length $s;
152+
$s .= "$k=$_";
153+
}
154+
}
155+
156+
return $s;
157+
}
158+
133159
1;
134160

Diff for: t/020_params.t

+42-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ use strict;
22
use warnings;
33

44
use Test::More;
5+
use Data::Dumper;
56

67
BEGIN {
78
use_ok('URL::Encode::PP', qw[ url_params_each
89
url_params_flat
910
url_params_mixed
10-
url_params_multi ]);
11+
url_params_multi
12+
url_params_build ]);
1113
}
1214

1315
{
@@ -123,5 +125,44 @@ BEGIN {
123125
is($cnt, 3, 'url_params_each(): callback invoked three times');
124126
}
125127

128+
{
129+
my @tests = (
130+
[ 'b=&a=', => [ 'b' => undef, 'a' => undef ] ],
131+
[ 'a=&a=&b=', => [ 'a' => [ undef, undef ], 'b' => undef ] ],
132+
[ 'a=&a=&b=&b=', => [ 'a' => [ undef, undef ], 'b' => [ undef, undef ] ] ],
133+
[ 'a+=&+b=', => [ 'a ' => undef, ' b' => undef ] ],
134+
[ 'a=%3D1&b=%3D2', => [ 'a' => '=1', 'b' => '=2' ] ],
135+
[ 'Fo%252=', => [ 'Fo%2' => '' ] ],
136+
[ '+a+=+1+' => [ ' a ' => ' 1 ' ] ],
137+
[ '=&=' => [ '' => [ undef, undef ], ] ],
138+
[ '=&=' => [ '' => [ undef, '' ] ] ],
139+
[ '=&=' => [ '' => [ '', undef ] ] ],
140+
[ '=&=' => [ '' => [ '', '' ] ] ],
141+
[ '=', => [ '' => '', ] ],
142+
[ '', => [ ] ],
143+
[ 'a=&b=', => { 'b' => undef, 'a' => undef } ],
144+
[ 'a=&a=&b=', => { 'a' => [ undef, undef ], 'b' => undef } ],
145+
[ 'a=&a=&b=&b=', => { 'a' => [ undef, undef ], 'b' => [ undef, undef ] } ],
146+
[ '+b=&a+=', => { 'a ' => undef, ' b' => undef } ],
147+
[ 'a=%3D1&b=%3D2', => { 'a' => '=1', 'b' => '=2' } ],
148+
[ 'Fo%252=', => { 'Fo%2' => '' } ],
149+
[ '+a+=+1+' => { ' a ' => ' 1 ' } ],
150+
[ '=&=' => { '' => [ undef, undef ], } ],
151+
[ '=&=' => { '' => [ undef, '' ] } ],
152+
[ '=&=' => { '' => [ '', undef ] } ],
153+
[ '=&=' => { '' => [ '', '' ] } ],
154+
[ '=', => { '' => '', } ],
155+
[ '', => { } ],
156+
);
157+
158+
foreach my $test (@tests) {
159+
my ($expected, $params) = @$test;
160+
local $Data::Dumper::Indent = 0;
161+
local $Data::Dumper::Terse = 1;
162+
my $params_str = Dumper($params);
163+
is_deeply(url_params_build($params), $expected, qq[url_params_build($params_str)]);
164+
}
165+
}
166+
126167
done_testing();
127168

0 commit comments

Comments
 (0)