Skip to content

Commit

Permalink
Implemented Plack::Util::is_real_fh and use it everywhere.
Browse files Browse the repository at this point in the history
Added docs and tests for Plack::Util.
  • Loading branch information
miyagawa committed Sep 16, 2009
1 parent b35ad27 commit b620a10
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 11 deletions.
2 changes: 1 addition & 1 deletion lib/Plack/Impl/AnyEvent.pm
Expand Up @@ -142,7 +142,7 @@ sub _response_handler {
my $body = $res->[2];
my $disconnect_cb = sub { $handle->on_drain(sub { $handle->destroy }) };

if ( ref $body eq 'GLOB' && $HasAIO ) {
if ( $HasAIO && Plack::Util::is_real_fh($body) ) {
my $offset = 0;
my $length = -s $body;

Expand Down
2 changes: 1 addition & 1 deletion lib/Plack/Impl/Coro.pm
Expand Up @@ -85,7 +85,7 @@ sub process_request {

$fh->syswrite(join '', @lines);

if ($HasAIO && Scalar::Util::reftype $res->[2] eq 'GLOB' && fileno $res->[2] > 0) {
if ($HasAIO && Plack::Util::is_real_fh($res->[2])) {
my $length = -s $res->[2];
my $offset = 0;
while (1) {
Expand Down
5 changes: 1 addition & 4 deletions lib/Plack/Impl/Standalone.pm
Expand Up @@ -132,10 +132,7 @@ sub handle_connection {
$self->write_all($conn, join('', @lines), $self->{timeout})
or return;

if ($HasSendFile && do {
my $fileno = eval { fileno $res->[2] };
defined($fileno) && $fileno >= 0;
}) {
if ($HasSendFile && Plack::Util::is_real_fh($res->[2])) {
$self->sendfile_all($conn, $res->[2], $self->{timeout});
} else {
my $err;
Expand Down
86 changes: 81 additions & 5 deletions lib/Plack/Util.pm
@@ -1,14 +1,10 @@
package Plack::Util;
use strict;
use Scalar::Util;

sub TRUE() { 1==1 }
sub FALSE() { !TRUE }

# Is it safe to use Scalar::Util everywhere?
sub _blessed {
ref $_[0] && ref($_[0]) !~ /^(?:SCALAR|ARRAY|HASH|CODE|GLOB|Regexp)$/;
}

sub load_class {
my($class, $prefix) = @_;

Expand All @@ -23,6 +19,17 @@ sub load_class {
return $class;
}

sub is_real_fh {
my $fh = shift;

if ( Scalar::Util::reftype($fh) eq 'GLOB' &&
do { my $fileno = fileno $fh; defined($fileno) && $fileno >= 0 } ) {
return TRUE
} else {
return FALSE;
}
}

sub foreach {
my($body, $cb) = @_;

Expand Down Expand Up @@ -60,3 +67,72 @@ sub write { $_[0]->[0]->(@_[1..$#_]) }
sub close { $_[0]->[1]->(@_[1..$#_]) }

1;

__END__
=head1 NAME
Plack::Util - Utility subroutines for Plack server and framework developers
=head1 FUNCTIONS
=over 4
=item TRUE, FALSE
my $true = Plack::Util::TRUE;
my $false = Plack::Util::FALSE;
Utility constants to include when you specify boolean variables in C<$env> hash (e.g. C<psgi.multithread>).
=item load_class
my $class = Plack::Util::load_class($class [, $prefix ]);
Constructs a class name and C<require> the class. Throws an exception
if the .pm file for the class is not found, just with the build-in
C<require>.
If C<$prefix> is set, the class name is prepended to the C<$class>
unless C<$class> begins with C<+> sign, which means the class name is
alrwady fully qualified.
my $class = Plack::Util::load_class("Foo"); # Foo
my $class = Plack::Util::load_class("Baz", "Foo::Bar"); # Foo::Bar::Baz
my $class = Plack::Util::load_class("+XYZ::ZZZ", "Foo::Bar"); # XYZ::ZZZ
=item is_real_fh
if ( Plack::Util::is_real_fh($fh) ) { }
returns true if a given C<$fh> is a real file handle that has a file
descriptor. It returns false if C<$fh> is PerlIO handle that is not
really related to the underlying file etc.
=item foreach
Plack::Util::foreach($body, $cb);
Iterate through I<$body> which is an array reference or
IO::Handle-like object and pass each line (which is NOT really
guaranteed to be a I<line>) to the callback function.
It internally sets the buffer length C<$/> to 4096 in case it reads
the binary file (TODO: should this be configurable).
=item response_handle
my $handle = Plack::Util::response_handle(
write => sub { },
close => sub { },
);
Helper function to create a ResponseHandler object that is useful to
return in C<$start_response> when C<psgi.async> is enabled.
=back
=cut
37 changes: 37 additions & 0 deletions t/Plack-Util/is_real_fh.t
@@ -0,0 +1,37 @@
use Test::Base;
use Plack::Util;

plan tests => 2 * blocks;

run {
my $block = shift;
my $res = Plack::Util::is_real_fh(eval $block->input);

ok !$@;
ok $res == $block->ret;
};


__END__
===
--- input
open my $fh, "<", "/dev/null";
$fh;
--- ret
1
===
--- input
open my $fh, "<", \"foo"; $fh
--- ret
0
===
--- input
use IO::File;
IO::File->new("/dev/null");
--- ret
1

0 comments on commit b620a10

Please sign in to comment.