Question

Edit: Answer added below, question left here for historical purposes only.

Moose documentation states that:

If you want, you can also explicitly specify the method names to be used for reading and writing an attribute's value. This is particularly handy when you'd like an attribute to be publicly readable, but only privately settable. For example:

has 'weight' => (
  is     => 'ro',
  writer => '_set_weight',   
 );

This might be useful if weight is calculated based on other methods. For example, every time the eat method is called, we might adjust weight. This lets us hide the implementation details of weight changes, but still provide the weight value to users of the class.

Based on this example, I wrote the following code:

has '_current_url' => (
    is => 'ro',
    isa => 'URI',
    writer => '_write_URI_to_current_url',
);

# Thus we ensure only a URI object gets written to current_url always
sub _current_url
{
    my $self = shift;
    $self->_write_URI_to_current_url(URI->new_abs($_[0], $self->start_url));
}

My intention was to ensure that setting current_url always sets it to a URI object even if it was called with a simple string. However, when I try to run the code, I get:

Cannot assign a value to a read-only accessor of _current_url

at the place (within my class) where I'm trying to set the current_url (with $self->_current_url($str);).

This is my second day with Moose so I'm quite confused as to what's going on here. To my understanding the is => 'ro' only asks Moose not to create a default write accessor with the same name as the attribute, is that understanding correct? How can I achieve my goal here?

Was it helpful?

Solution

Ok, I believe I've found the issue.

The _current_url method I've pasted above got overridden by Moose's generated read-only accessor of the same name, so when I tried to call $self->_current_url with a value, it throws the above error to indicate that the read-only accessor cannot set values.

I guess the error message should ideally be Cannot assign a value **through** a read-only accessor of _current_url, not **to** a read-only accessor.

Changing the name of the sub to _set_current_url solved the problem. I guess another way to achieve the same would be to tell Moose that _current_url is => 'rw' and then create an around '_current_url'. I haven't tried this approach.

OTHER TIPS

Late to the game but just saw this post and ran into the same thing a while back. '_set_current_url' really seems like an attribute accessor instead of an attribute. Might want to consider:

has '_current_url' => {
  is => 'rw',
  isa => 'URI',
  writer => 'set_current_url',
  reader => 'get_current_url'
  }

A bit cleaner this way since the attribute is the original '_current_url' and you have accessors to get/set the attribute.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top