URIとURI::fileの挙動
URIモジュールですが、良く使われるモジュールではあるのですが、
schemeを指定しないでURIモジュールでインスタンス化してから、改めてschemeを指定すると酷い結果になります。
use strict; use warnings; use Data::Dump qw(dump); use URI; local $\ = "\n"; my $u = URI->new("/usr/bin/perl"); print dump($u->scheme); print dump($u->as_string); $u->scheme("file"); print dump($u->scheme); print dump($u->as_string);
で結果ですけど、
() "/usr/bin/perl" "file" "file:/usr/bin/perl"
最後のas_stringが酷すぎる。。。
ちなみに最初からURI::fileでインスタンス化すると、
use strict; use warnings; use URI::file; print URI::file->new("/usr/bin/perl")->as_string;
とやると結果は、
file:///usr/bin/perl
となります。まぁ、これはいいとして、、、URIモジュールのschemeの変更処理がまずいみたいですね。
sub scheme { my $scheme = shift->_scheme(@_); return unless defined $scheme; lc($scheme); }
とあるので、_schemeの実装を見ると、
sub _scheme { my $self = shift; unless (@_) { return unless $$self =~ /^($scheme_re):/o; return $1; } my $old; my $new = shift; if (defined($new) && length($new)) { Carp::croak("Bad scheme '$new'") unless $new =~ /^$scheme_re$/o; $old = $1 if $$self =~ s/^($scheme_re)://o; my $newself = URI->new("$new:$$self"); $$self = $$newself; bless $self, ref($newself); } else { if ($self->_no_scheme_ok) { $old = $1 if $$self =~ s/^($scheme_re)://o; Carp::carp("Oops, opaque part now look like scheme") if $^W && $$self =~ m/^$scheme_re:/o } else { $old = $1 if $$self =~ m/^($scheme_re):/o; } } return $old; }
にある、
my $newself = URI->new("$new:$$self");
この部分。。。結果的に、
my $newself = URI->new("file:/usr/bin/perl");
って投げてるだけだし。。。
他のschemeについては保証出来ないけど、
my $newself = "URI::$new"->new($$self);
とすればいいんじゃないかなーと思う訳です。