Reputation: 35
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
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
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