perlmoose

How to determine, in a Moose constructor, what context it was called in?


Let's say we have a Moose class like so:

package My::Test ;
use Moose ;
$\="\n";

sub BUILDARGS {
    my ($pkg,%args) = @_ ;
    print defined wantarray ? 'BUILDARGS: SCALAR':'BUILDARGS: VOID' ;
    return \%args ;
}

sub BUILD {
    print defined wantarray ? 'BUILD: SCALAR':'BUILD: VOID' ;
    my ( $self, $args ) = @_ ;
    print '---' ;
}
1;

Instantiating the class in both SCALAR and VOID context I get always the same output:

#!/usr/bin/perl
use Moose ;
use My::Test ;
# Scalar ctx
my $instance = My::Test->new ;
# Void ctx
My::Test->new ;

Output:

BUILDARGS: SCALAR
BUILD: VOID
---
BUILDARGS: SCALAR
BUILD: VOID

I was able to get the context wrapping the Moose class instance creation in a trivial package and passing the context as constructor attribute as follows:

package My::Wrapper ;
use My::Test ;
sub new {
    my ( $class , %args ) = @_ ;
    return My::Test->new(%args , ctx => defined wantarray ? 'scalar':'void') ;
} 
1 ;    

but I would like to know if there is a cleaner way for doing that.


Solution

  • Moose creates the constructor for you (see here). The context isn't propagated to either BUILDARGS or BUILD.

    You can wrap new in the Moose way, though:

    around new => sub {
        my ($orig, $self) = splice @_, 0, 2;
        warn defined wantarray ? 'other' : 'void';
        $self->$orig(@_)
    };