Question

In Perl/Tk, one can define textvariables for widgets. It's a reference to some scalar that holds the value. Someone showed me how to use Moose attribute coercion to use Moose attributes as textvariable (cool!). This is how it works:

subtype 'TkRef' => as 'ScalarRef';
coerce 'TkRef', from 'Str', via { my $r = $_; return \$r };
has 'some_val' => (is => 'rw', isa => 'TkRef', coerce => 1, default => 'default value');

$mw->Entry(-textvariable => $self->some_val);
$mw->Label(-textvariable => $self->some_val); # will always Show what we type into the entry

However, when I want to set a new value for the attribute, I have to dereference it like this:

${$self->some_val} = 'blarg'; # dereference

Simply setting the attribute won't work, as the reference needs to remain the same over the life of the object (that is, the attribute value itself cannot change).

Is there a way to use the nice Moose attribute coerce feature without losing the possibility to set the attribute with $self->some_val('blarg'); ? Some sort of reverse-coercion?

Was it helpful?

Solution

Make the accessors private, and then provide a wrapper for the accessor. Something like this:

subtype 'TkRef', as 'ScalarRef';
coerce 'TkRef', from 'Str', via { my $r = $_; return \$r };

has _some_val => (
   is       => 'rw',
   isa      => 'TkRef',
   coerce   => 1,
   init_arg => 'some_val',
   default  => 'default value',
);

sub some_val {
   my $self = shift;
   if (@_ and not ref $_[0]) {
      ${$self->_some_val} = shift;
   }
   elsif (@_ and ref $_[0]) {
      ${$self->_some_val} = ${+shift};
   }
   $self->_some_val(@_);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top