Martin
Martin

Reputation: 35

Dereferencing an in-memory file held in a Moose attribute

The following is an excerpt from some code that I'm experimenting with:

has buffer     => ( is => 'rw', isa => 'ScalarRef' );
has old_stdout => ( is => 'rw', isa => 'FileHandle' );

sub capture {
    my $self = shift;
    my $old_stdout;
    my $buffer;

    open $old_stdout, '>&', STDOUT
        or croak 'Cannot duplicate filehandle';

    close STDOUT;

    open STDOUT, '>', \$buffer
        or croak 'Cannot open filehandle';

    $self->old_stdout( $old_stdout );
    $self->buffer( \$buffer );
}

sub reset {
    my $self = shift;

    open STDOUT, '>&', $self->old_stdout
        or croak 'Cannot reset STDOUT';
}

Elsewhere:

my $stdout = Capture->new();
print "Some output\n";
$stdout->reset();

print $stdout->buffer();
# SCALAR(0x#######)

print ${$stdout->buffer()};
# Some output

I have tried cheating by setting the attribute hashref directly -- it works, but I don't like doing it:

    open STDOUT, '>', \$self->{buffer}
        or croak 'Cannot open filehandle';

I think I am missing something fundamental here. How should I go about storing $buffer (an in-memory file) as a Moose attribute, so that I can retrieve it later without the caller having to dereference it?

Update

I've added an around method modifier, which does the trick:

around 'buffer' => sub {
    my $orig = shift;
    my $self = shift;
    return ${$self->$orig} unless @_;
    $self->$orig( @_ );
};

...but it still feels messy. Is there a better way?

Upvotes: 2

Views: 230

Answers (2)

ikegami
ikegami

Reputation: 385887

Don't change the meaning of buffer (as you did with around), create a new accessor.

has buffer_ref => (
   ...
   handles => {
      buffer => sub {
         my $self = shift;
         if (@_) {
            ${ $self->buffer_ref }  = $_[0];
         } else {
            return ${ $self->buffer_ref };
         }
      },
   },
);

Upvotes: 1

bvr
bvr

Reputation: 9697

An option is to make both attributes (buffer and old_stdout) private by prepending underscore and then add simple method to access buffer from the outside:

sub buffer {
    my $self = shift;
    return ${$self->_buffer}
}

It also look that you are trying to implement duplicate for Capture::Tiny or similar module.

Upvotes: 1

Related Questions