tags:

views:

220

answers:

2

I need a class attribute in Moose. Right now I am saying:

#!/usr/bin/perl

use 5.010;
use strict;
use warnings;
use MooseX::Declare;

class User {
    has id      => (isa => "Str", is => 'ro', builder => '_get_id');
    has name    => (isa => "Str", is => 'ro');
    has balance => (isa => "Num", is => 'rw', default => 0);

    #FIXME: this should use a database 
    method _get_id {
     state $id = 0; #I would like this to be a class attribute
     return $id++;
    }
}

my @users;
for my $name (qw/alice bob charlie/) {
    push @users, User->new(name => $name);
};

for my $user (@users) {
    print $user->name, " has an id of ", $user->id, "\n";
}
+2  A: 

I found MooseX::ClassAttribute, but it looks ugly. Is this the cleanest way?

#!/usr/bin/perl

use 5.010;
use strict;
use warnings;
use MooseX::Declare;

class User {
    use MooseX::ClassAttribute;

    class_has id_pool => (isa => "Int", is => 'rw', default => 0);

    has id      => (isa => "Str", is => 'ro', builder => '_get_id');
    has name    => (isa => "Str", is => 'ro');
    has balance => (isa => "Num", is => 'rw', default => 0);

    #FIXME: this should use a database 
    method _get_id {
     return __PACKAGE__->id_pool(__PACKAGE__->id_pool+1);
    }
}

my @users;
for my $name (qw/alice bob charlie/) {
    push @users, User->new(name => $name);
};

for my $user (@users) {
    print $user->name, " has an id of ", $user->id, "\n";
}
Chas. Owens
That is the correct way. You can also create a class class (as it were) if you prefer them in a separate package, look what ClassAttribute does under the hood
castaway
Isn't `use strict` and `use warnings` redundant with `use MooseX::Declare` ?
Robert P
@Robert P Probably, I was just starting to use MooseX::Declare when I wrote this.
Chas. Owens
Note that as of 0.11, MooseX::ClassAttribute now plays well with roles. Thanks David Rolsky!!
Ether
A: 

Honestly, I don't think it's necessary to all that trouble for class attributes. For read-only class attributes, I just use a sub that returns a constant. For read-write attributes, a simple state variable in the package usually does the trick (I haven't yet run into any scenarios where I needed something more complicated.)

state $count = 0;
method _get_id { 
    return ++$count;
}

A private block with a lexical can be used if you need pre-5.10 compatibility.

friedo
ah, but id_pool is not necessarily read only, I want a true class attribute that has an accessor. I don't want to have to rewrite the code when I decide to move the ID pool to a database. If it were an accessor, I would just need to change change how the accessor worked, with a state variable I would need to either change all of the references to it or make it a tied scalar.
Chas. Owens