开发者

Perl Classes :: Can not write output

开发者 https://www.devze.com 2023-04-02 16:54 出处:网络
I am new to Object oriented programming in perl. So, I have a silly question. What -- I am writing a script which will do something and write result to stream ( STDOUT or NETWORK ).

I am new to Object oriented programming in perl. So, I have a silly question.

What -- I am writing a script which will do something and write result to stream ( STDOUT or NETWORK ).

How --

[main.pl]

#!/usr/bin/perl
use strict;

require const::StreamTypes;
require output;

my $out = output->new("output");


$out->writeLine("Sample output");

[output.pm]

#!/usr/bin/perl
use strict;

require const::StreamTypes;

package output;

my $OUTSTR;

sub new{

    my $class   = shift();
    my $stream  = shift();

    if($stream eq const::StreamTypes->STDNET){

    }elsif($stream eq const::StreamTypes->STDWEB){

    }else{
        *OUTSTR = *STDOUT;
    }   

    my $self    = {
        "_outStream"    => $stream,
        "_outStreamPtr"开发者_StackOverflow社区 => $OUTSTR
    };

    bless($self, $class);
}

sub writeLine{
    my $msg = shift();
    print(OUTSTR "$msg\n");
}

return 1;

So, can anyone help me understand what is going wrong here? 'cas program runs without error but with no output.

Thanks!


I changed a couple of things here:
the first parameter of a methd is the invocant (instance or class) itself
indirect file handles are globals!
the autodie module comes in handy, if using open
consider using strict in your modules, too

I would not recommend the use of package global variable ( my $OUTSTR; ), because that's going to be messy with multiple instances, which want to have different streams.

And I definitely got into the habit of using accessors for all attributes. You can use a lightweight system like Class::Accessor or perhaps you are even lucky enough to use Moose our Mouse. Of course there are a couple of other modules also providing accessors in different ways.

package output;

use strict;
use warnings;
use autodie;

use Class::Accessor "moose-like";

has "outStream" => ( is => 'rw' );

sub new{

    my ( $class, $stream ) = @_;

    my $self = bless( {}, $class );

    if ( 0 ) {
        # ...

    } else {
        open( my $outStream, '>&', \*STDOUT );
        $self->outStream( $outStream );
    }

    return $self;
}

sub writeLine{
    my ( $self, $msg ) = @_;
    print { $self->outStream } "$msg\n";
}

return 1;

Moose would create a constructor for you, but you can insert your parameter processing as easy as follows:

use Moose;

has "outStream" => ( is => 'rw' );

sub BUILDARGS {
    my ( $class, $stream ) = @_;

    open( my $outStream, '>&', \*STDOUT );

    return {
        outStream => $outStream,
    };
}


$OUTSTR and *OUTSTR are very different things -- you should clear up your misunderstanding about this before you worry about object oriented programming.

That said, you can probably fix this script by getting everything to refer to $OUTSTR:

...

}else{
    $OUTSTR = *STDOUT;
}

...

print $OUTSTR "$msg\n";


How about just passing a file handle directly into the object's constructor?

package output;

sub new {
  my ($class, $fh) = @_;
  bless { file_handle => $fh }, $class;
}

sub writeLine {
  my $self = shift;
  my $line = shift;
  print {$self->{file_handle}} $line;
}

1;

Example usage:

my $output = output->new(\*STDOUT); # write to stdout

my $socket = IO::Socket::INET->new('www.perl.org', PeerPort => 'http(80)', Proto => 'tcp');
my $output = output->new($socket); # write to a socket


Please don't use barenames for file handles. Use lexical file handles.

The following lines assume that there is a hash %type_handlers somewhere that looks something like this:

{ const::StreamTypes->STDNET => \&constructor_for_stdnet_handles
, const::StreamTypes->STDWEB => \&constructor_for_stdweb_handles
}

Then you can replace the bottom of your constructor with:

my $handler = $type_handlers{ $stream };
my $outstr  
    = $handler ? $handler->() 
    :            do { my $h; open( $h, '>&', \*::STDOUT ) and $h; }
    ;
return bless( {
      _outStream    => $stream
    , _outStreamPtr => $outstr 
    }
    , $class
    );

Then writeLine becomes:

sub writeLine { 
    my ( $self, $msg ) = @_;
   ( $self->{_outStreamPtr} || *::STDOUT{IO} )->say( $msg );
}
  • The method is a little more robust in cases where somebody just blessed themselves into your class.

    my $q_and_d = bless {}, 'output';
    

If you don't want to allow "quick & dirty" instances, and want more precise messages from possible failures, you could do this:

Carp::croak( 'No outstream!' ) 
    unless my $h = Params::Util::_HANDLE( $self->{_outStreamPtr} )
    ;
0

精彩评论

暂无评论...
验证码 换一张
取 消