Question

Again once have a problem with the Moose object model. I'm not sure about the posting here or better to "codereview" - trying here first... ;)

  • Have one Region.
  • The Region has some Spot(s).
  • Each Spot has name and some Entries.
  • Each entry has: id, content, flag.

The API should work as next:

my $region = Region->new;    #create a Region
my $sx = $region->spot('x'); #return the Spot with a name 'x'
                             #if the spot with a name 'x' doesn't exists, create it

$sx->add(id => 'id1', content => 'content1', flag => 'f1');   #add a new Entry to Spot 'x'
$sx->add(id => 'id2', content => sub { return "string" }, flag => 'f2');#add another Entry

$sx->render; # render the "spot" - do some operations on array of Entries

What I already have - sorry for the long sources - i shortened them to smallest working packages.

First - have a simple class for the "Entries".

package Region::Entry;
use namespace::sweep;
use Modern::Perl;
use Moose;

has 'id'      => (is => 'rw', isa => 'Str');
has 'content' => (is => 'rw', isa => 'Str|CodeRef');
has 'flag'    => (is => 'rw', isa => 'Str');

__PACKAGE__->meta->make_immutable;
1;

class for the Region - has only one HashRef for storing Spots by spotname (as keys)

package Region;
use namespace::sweep;
use Modern::Perl;
use Moose;
use Method::Signatures::Simple;
use Region::Spot;

has 'spots' => (
    traits    => ['Hash'],
    is        => 'rw',
    isa       => 'HashRef[Region::Spot]',
    default   => sub { {} },
    handles   => {
        set_spot     => 'set',
        get_spot     => 'get',
        spot_exists  => 'exists',
    },
);

method spot {
    my $name = shift;
    return undef unless $name;
    $self->set_spot($name => Region::Spot->new()) unless $self->spot_exists($name);
    return $self->get_spot($name);
}
__PACKAGE__->meta->make_immutable;
1;

finally class for the Spots

package Region::Spot;
use Modern::Perl;
use namespace::sweep;
use Moose;
use Method::Signatures::Simple;
use Region::Entry;

has 'entries' => (
    traits  => ['Array'],
    is => 'rw',
    isa => 'ArrayRef[Region::Entry]',
    default => sub { [] },
    handles => {
        add_entry => 'push',
    },
);

#PROBLEM HERE - HOW TO IMPLEMENT THIS for allow attributes as in the above API
#so add(id=>'id', content => 'xxxx', flag => 'f');
#with correct attribute checking????
method add {
    #$self->add_entry....
}

method render {
    #...
    return "rendered entries";
}
__PACKAGE__->meta->make_immutable;
1;

So, having problem with implementing the add API. See the comments above...

$sx->add(id => 'id1', content => 'content1', flag => 'f1');   #add a new Entry to Spot 'x'

My object model or it's implementation is probably wrong, because the i have the add method on class where haven't defined the types ... or don't know ...

This is my problem everytime, when creating anything new. I know "how to use Moose" (i'm not an expert, but knowing the basics) - but have problem define the right classes... :(

I hope the above make sense... and sry for the long post.

Était-ce utile?

La solution

I might be missing some subtle detail of your question, but why not just unpack the arguments in your add method and create a new Entry?

method add {
    $self->add_entry( Entry->new( @_ ) );
}

Autres conseils

Warning: untested code

If you are intent on the API being set that way, you can pass the attributes through to new when creating your Region::Entry

method add {
    my %params = @_;
    $self->add_entry( Region::Entry->new(\%params) );
}

Additionally, you could

$sx->add( Region::Entry->new( { id => ..., } );

.
.
.

method add {
    my $self = shift;
    $self->add_entry( shift );
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top