Skip to content

Commit 85c5a5c

Browse files
Jacques Deguestoalders
authored andcommitted
Using Scalar::Util::reftype instead of just ref(), but mindful this time about definedness to avoid warnings
Added tests for array objects Ensuring array objects do not stringifies before using them as array Created a function to check if value is an array with no stringification Added tests as requested for stringifyable arrays
1 parent d586568 commit 85c5a5c

File tree

5 files changed

+122
-8
lines changed

5 files changed

+122
-8
lines changed

Changes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
Revision history for URI
22

33
{{$NEXT}}
4+
- Using Scalar::Util::reftype instead of just ref(), but mindful this time
5+
about definedness to avoid warnings (GH#140) (Jacques Deguest)
46

57
5.27 2024-02-09 15:01:24Z
68
- Add missing NAME section to POD of URI::geo (GH#142) (gregor herrmann)

lib/URI/_query.pm

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use warnings;
55

66
use URI ();
77
use URI::Escape qw(uri_unescape);
8+
use Scalar::Util ();
89

910
our $VERSION = '5.28';
1011

@@ -34,7 +35,7 @@ sub query_form {
3435
# Try to set query string
3536
my $delim;
3637
my $r = $_[0];
37-
if (ref($r) eq "ARRAY") {
38+
if (_is_array($r)) {
3839
$delim = $_[1];
3940
@_ = @$r;
4041
}
@@ -49,7 +50,7 @@ sub query_form {
4950
$key = '' unless defined $key;
5051
$key =~ s/([;\/?:@&=+,\$\[\]%])/ URI::Escape::escape_char($1)/eg;
5152
$key =~ s/ /+/g;
52-
$vals = [ref($vals) eq "ARRAY" ? @$vals : $vals];
53+
$vals = [_is_array($vals) ? @$vals : $vals];
5354
for my $val (@$vals) {
5455
if (defined $val) {
5556
$val =~ s/([;\/?:@&=+,\$\[\]%])/ URI::Escape::escape_char($1)/eg;
@@ -86,7 +87,7 @@ sub query_keywords
8687
if (@_) {
8788
# Try to set query string
8889
my @copy = @_;
89-
@copy = @{$copy[0]} if @copy == 1 && ref($copy[0]) eq "ARRAY";
90+
@copy = @{$copy[0]} if @copy == 1 && _is_array($copy[0]);
9091
for (@copy) { s/([;\/?:@&=+,\$\[\]%])/ URI::Escape::escape_char($1)/eg; }
9192
$self->query(@copy ? join('+', @copy) : undef);
9293
}
@@ -114,7 +115,7 @@ sub query_param {
114115
if (@_) {
115116
my @new = @old;
116117
my @new_i = @i;
117-
my @vals = map { ref($_) eq 'ARRAY' ? @$_ : $_ } @_;
118+
my @vals = map { _is_array($_) ? @$_ : $_ } @_;
118119

119120
while (@new_i > @vals) {
120121
splice @new, pop @new_i, 2;
@@ -139,7 +140,7 @@ sub query_param {
139140
sub query_param_append {
140141
my $self = shift;
141142
my $key = shift;
142-
my @vals = map { ref $_ eq 'ARRAY' ? @$_ : $_ } @_;
143+
my @vals = map { _is_array($_) ? @$_ : $_ } @_;
143144
$self->query_form($self->query_form, $key => \@vals); # XXX
144145
return;
145146
}
@@ -168,7 +169,7 @@ sub query_form_hash {
168169
while (my($k, $v) = splice(@old, 0, 2)) {
169170
if (exists $hash{$k}) {
170171
for ($hash{$k}) {
171-
$_ = [$_] unless ref($_) eq "ARRAY";
172+
$_ = [$_] unless _is_array($_);
172173
push(@$_, $v);
173174
}
174175
}
@@ -179,4 +180,15 @@ sub query_form_hash {
179180
return \%hash;
180181
}
181182

183+
sub _is_array {
184+
return(
185+
defined($_[0]) &&
186+
( Scalar::Util::reftype($_[0]) || '' ) eq "ARRAY" &&
187+
!(
188+
Scalar::Util::blessed( $_[0] ) &&
189+
overload::Method( $_[0], '""' )
190+
)
191+
);
192+
}
193+
182194
1;

t/old-base.t

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,19 @@ sub parts_test {
348348
$url->query_form(a => ['foo', 'bar'], b => 'foo', c => ['bar', 'foo']);
349349
is($url->as_string, 'http://web?a=foo&a=bar&b=foo&c=bar&c=foo', ref($url) . '->as_string');
350350

351+
# Same, but using array object
352+
{
353+
package
354+
Foo::Bar::Array;
355+
sub new
356+
{
357+
my $this = shift( @_ );
358+
return( bless( ( @_ == 1 && ref( $_[0] || '' ) eq 'ARRAY' ) ? shift( @_ ) : [@_] => ( ref( $this ) || $this ) ) );
359+
}
360+
}
361+
$url->query_form(a => Foo::Bar::Array->new(['foo', 'bar']), b => 'foo', c => Foo::Bar::Array->new(['bar', 'foo']));
362+
is($url->as_string, 'http://web?a=foo&a=bar&b=foo&c=bar&c=foo', ref($url) . '->as_string');
363+
351364
subtest 'netloc_test' => \&netloc_test;
352365
subtest 'port_test' => \&port_test;
353366

t/query-param.t

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use strict;
22
use warnings;
33

4-
use Test::More tests => 19;
4+
use Test::More tests => 20;
55

66
use URI ();
77
use URI::QueryParam;
@@ -68,4 +68,19 @@ $u->query_param('b' => []);
6868

6969
ok ! $u->query;
7070

71+
# Same, but using array object
72+
{
73+
package
74+
Foo::Bar::Array;
75+
sub new
76+
{
77+
my $this = shift( @_ );
78+
return( bless( ( @_ == 1 && ref( $_[0] || '' ) eq 'ARRAY' ) ? shift( @_ ) : [@_] => ( ref( $this ) || $this ) ) );
79+
}
80+
}
81+
$u->query_param('a' => Foo::Bar::Array->new);
82+
$u->query_param('b' => Foo::Bar::Array->new);
83+
84+
ok ! $u->query;
85+
7186
is $u->as_string, 'http://www.sol.no';

t/query.t

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,36 @@
11
use strict;
22
use warnings;
33

4-
use Test::More tests => 26;
4+
use Test::More tests => 37;
55

66
use URI ();
77
my $u = URI->new("", "http");
88
my @q;
99

10+
# For tests using array object
11+
{
12+
package
13+
Foo::Bar::Array;
14+
sub new
15+
{
16+
my $this = shift( @_ );
17+
return( bless( ( @_ == 1 && ref( $_[0] || '' ) eq 'ARRAY' ) ? shift( @_ ) : [@_] => ( ref( $this ) || $this ) ) );
18+
}
19+
20+
package
21+
Foo::Bar::Stringy;
22+
push( @Foo::Bar::Stringy::ISA, 'Foo::Bar::Array' );
23+
use overload (
24+
'""' => '_as_string',
25+
);
26+
sub _as_string
27+
{
28+
my $self = shift;
29+
local $" = '_hello_';
30+
return( "@$self" );
31+
}
32+
}
33+
1034
$u->query_form(a => 3, b => 4);
1135
is $u, "?a=3&b=4";
1236

@@ -40,24 +64,56 @@ is $u, "?%20+?=%23";
4064
$u->query_keywords([qw(a b)]);
4165
is $u, "?a+b";
4266

67+
# Same, but using array object
68+
$u->query_keywords(Foo::Bar::Array->new([qw(a b)]));
69+
is $u, "?a+b";
70+
71+
# Same, but using a stringifyable array object
72+
$u->query_keywords(Foo::Bar::Stringy->new([qw(a b)]));
73+
is $u, "?a_hello_b";
74+
4375
$u->query_keywords([]);
4476
is $u, "";
4577

78+
# Same, but using array object
79+
$u->query_keywords(Foo::Bar::Array->new([]));
80+
is $u, "";
81+
82+
# Same, but using a stringifyable array object
83+
$u->query_keywords(Foo::Bar::Stringy->new([]));
84+
is $u, "?";
85+
4686
$u->query_form({ a => 1, b => 2 });
4787
ok $u eq "?a=1&b=2" || $u eq "?b=2&a=1";
4888

4989
$u->query_form([ a => 1, b => 2 ]);
5090
is $u, "?a=1&b=2";
5191

92+
# Same, but using array object
93+
$u->query_form(Foo::Bar::Array->new([ a => 1, b => 2 ]));
94+
is $u, "?a=1&b=2";
95+
5296
$u->query_form({});
5397
is $u, "";
5498

5599
$u->query_form([a => [1..4]]);
56100
is $u, "?a=1&a=2&a=3&a=4";
57101

102+
# Same, but using array object
103+
$u->query_form(Foo::Bar::Array->new([a => [1..4]]));
104+
is $u, "?a=1&a=2&a=3&a=4";
105+
58106
$u->query_form([]);
59107
is $u, "";
60108

109+
# Same, but using array object
110+
$u->query_form(Foo::Bar::Array->new([]));
111+
is $u, "";
112+
113+
# Same, but using a strngifyable array object
114+
$u->query_form(Foo::Bar::Stringy->new([]));
115+
is $u, "";
116+
61117
$u->query_form(a => { foo => 1 });
62118
ok "$u" =~ /^\?a=HASH\(/;
63119

@@ -73,13 +129,29 @@ is $u, "?a=1&c=2";
73129
$u->query_form([a => 1, b => 2], ';');
74130
is $u, "?a=1;b=2";
75131

132+
# Same, but using array object
133+
$u->query_form(Foo::Bar::Array->new([a => 1, b => 2]), ';');
134+
is $u, "?a=1;b=2";
135+
136+
# Same, but using a stringifyable array object
137+
$u->query_form("c" => Foo::Bar::Stringy->new([a => 1, b => 2]), "d" => "e", ';');
138+
is $u, "?c=a_hello_1_hello_b_hello_2;d=e";
139+
76140
$u->query_form([]);
77141
{
78142
local $URI::DEFAULT_QUERY_FORM_DELIMITER = ';';
79143
$u->query_form(a => 1, b => 2);
80144
}
81145
is $u, "?a=1;b=2";
82146

147+
# Same, but using array object
148+
$u->query_form(Foo::Bar::Array->new([]));
149+
{
150+
local $URI::DEFAULT_QUERY_FORM_DELIMITER = ';';
151+
$u->query_form(a => 1, b => 2);
152+
}
153+
is $u, "?a=1;b=2";
154+
83155
$u->query('a&b=2');
84156
@q = $u->query_form;
85157
is join(":", map { defined($_) ? $_ : '' } @q), "a::b:2";

0 commit comments

Comments
 (0)