Skip to content

Commit 0d65761

Browse files
authored
Allow can method to respond to delegated methods (#159)
* Allow `can` method to respond with delegated methods * Make `AUTOLOAD` method use `can` method * Apply pertidy to `AUTOLOAD`, `can`, and `DESTROY` * Update changes
1 parent 453467f commit 0d65761

File tree

3 files changed

+53
-11
lines changed

3 files changed

+53
-11
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 HTTP-Message
22

33
{{$NEXT}}
4+
- Allow `can` method to respond to delegated methods (GH#159) (nanto_vi,
5+
TOYAMA Nao)
46

57
6.32 2021-05-18 18:54:27Z
68
- Use File::Spec for MSWin32 on Content-Disposition filename (GH#157)

lib/HTTP/Message.pm

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -640,23 +640,42 @@ sub _stale_content {
640640
}
641641
}
642642

643-
644643
# delegate all other method calls to the headers object.
645644
our $AUTOLOAD;
646-
sub AUTOLOAD
647-
{
648-
my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::')+2);
649645

650-
# We create the function here so that it will not need to be
651-
# autoloaded the next time.
652-
no strict 'refs';
653-
*$method = sub { local $Carp::Internal{+__PACKAGE__} = 1; shift->headers->$method(@_) };
654-
goto &$method;
646+
sub AUTOLOAD {
647+
my ( $package, $method ) = $AUTOLOAD =~ m/\A(.+)::([^:]*)\z/;
648+
my $code = $_[0]->can($method);
649+
Carp::croak(
650+
qq(Can't locate object method "$method" via package "$package"))
651+
unless $code;
652+
goto &$code;
655653
}
656654

655+
sub can {
656+
my ( $self, $method ) = @_;
657+
658+
if ( my $own_method = $self->SUPER::can($method) ) {
659+
return $own_method;
660+
}
661+
662+
my $headers = ref($self) ? $self->headers : 'HTTP::Headers';
663+
if ( $headers->can($method) ) {
664+
665+
# We create the function here so that it will not need to be
666+
# autoloaded or recreated the next time.
667+
no strict 'refs';
668+
*$method = sub {
669+
local $Carp::Internal{ +__PACKAGE__ } = 1;
670+
shift->headers->$method(@_);
671+
};
672+
return \&$method;
673+
}
657674

658-
sub DESTROY {} # avoid AUTOLOADing it
675+
return undef;
676+
}
659677

678+
sub DESTROY { } # avoid AUTOLOADing it
660679

661680
# Private method to access members in %$self
662681
sub _elem

t/message.t

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use warnings;
55

66
use Test::More;
77

8-
plan tests => 195;
8+
plan tests => 208;
99

1010
require HTTP::Message;
1111
use Config qw(%Config);
@@ -604,3 +604,24 @@ is($m->content_charset, "UTF-16BE");
604604
is($@, 'pre-existing error', 'decodable() does not overwrite $@');
605605
}
606606

607+
$m = HTTP::Message->new(["User-Agent" => "Mozilla/5.0", "Referer" => "https://example.com/"]);
608+
ok($m->can('content'));
609+
my $method = $m->can('user_agent');
610+
is(ref($method), 'CODE');
611+
is(HTTP::Message->can('user_agent'), $method);
612+
is($m->$method, "Mozilla/5.0");
613+
614+
ok(HTTP::Message->can('content'));
615+
$method = HTTP::Message->can('referrer');
616+
is(ref($method), 'CODE');
617+
is($m->can('referrer'), $method);
618+
is($m->$method, "https://example.com/");
619+
620+
eval { $m->unknown_method; };
621+
like $@, qr/Can't locate object method "unknown_method" via package "HTTP::Message"/;
622+
is($m->can('unknown_method'), undef);
623+
eval { HTTP::Message->unknown_method; };
624+
like $@, qr/Can't locate object method "unknown_method" via package "HTTP::Message"/;
625+
is(HTTP::Message->can('unknown_method'), undef);
626+
eval { my $empty = ""; $m->$empty; };
627+
like $@, qr/Can't locate object method "" via package "HTTP::Message"/;

0 commit comments

Comments
 (0)