In my object constructor i had statement to initialize two attributes same time:
($self->{token}, $self->{token_start}) = $self->_get_authorized_token();
So i got token and it's starting time together in one statement.
Now i try to port my module to use Moo(se) and here i don't know how should i set those two bound attributes at same time?. Some pseudo code would be like that:
has qw/token token_start/ => (
is => 'rw',
default => shift->_get_authorized_token();
);
But how to declare 2 bound attributes in Moo(se)ish way?
EDIT. I show the code of the method _get_authorized_token
, maybe it will brings some ideas:
sub _get_authorized_token {
my $self = shift;
my $postData = { 'apikey' => $self->{key} };
my $url = $self->{base_url} . '/seller';
my $xml = $self->_post(url => $url,
postdata => $postData,
);
my $ref = XMLin($xml, SuppressEmpty => '' );
my $time = $ref->{Notification_Datetime};
my $token = $ref->{Notification_Data}{body}{token};
return ($token, $time);
}
Once you end up with two attributes that are basically linked to the point where you always set them simultaneously ... the answer is usually to create a value object with two attributes for the purpose and then delegate the relevant methods to it. So, something like -
package MyApp::TokenInfo;
use Moo;
has token => (is => 'ro', required => 1);
has token_start => (is => 'ro', required => 1);
...
package MyApp::ThingWithAToken;
use Module::Runtime qw(use_module);
use Moo;
...
has token_info => (is => 'lazy', handles => [ qw(token token_start) ]);
sub _build_token_info {
my ($self) = @_;
my ($token, $token_start) = $self->_get_authorized_token;
# this is equivalent to:
#
# require MyApp::TokenInfo;
# return MyApp::TokenInfo->new(...);
#
# but more concise
return use_module('MyApp::TokenInfo')->new(
token => $token,
token_start => $token_start
);
}
...
my $thing = MyApp::ThingWithAToken->new(...);
$thing->token; # calls $thing->token_info->token;
$thing->token_start; # calls $thing->token_info->token_start
so the presence of the value object isn't required knowlede from externally but internally you've still got the two attributes tied together in a way that lets your implementation handle them as a single "thing".
-- mst