use MooseX::Declare; ## Door behaviour: # - you cannot lock an Open door # - you cannot open a Locked door class Door { use MyApp::Bundle; has name => ( is => 'ro', isa => 'Str', required => 1 ); # Default State at construction: Closed and Unlocked method BUILD (@_) { apply_all_roles($self, 'Closed', 'Unlocked') } # THESE WON'T WORK right now, because the Role must be un-applied! method is_opened { $->DOES('Opened') } method is_closed { $->DOES('Closed') } method is_locked { $->DOES('Locked') } method is_unlocked { $->DOES('Unlocked') } method current_roles_names { return [ split('\|', $->meta->roles->[0]->name) ]; } method current_state { my $openness = $->is_opened ? 'OPENED' : 'CLOSED'; my $lockness = $->is_locked ? 'LOCKED' : 'UNLOCKED'; warn 'DEFECT: a Door should never be opened and locked !!!' if $->is_opened && $->is_locked; return [ $openness, $lockness ]; } method to_str { return $->name . ': ' . join(', ', @{$->current_state}) } } # END CLASS Door role Opened { use MyApp::Bundle; method knock { say "don't knock: it's opened" } method open { carp 'already opened' } method close { switch_role($self, 'Door', 'Opened', 'Closed') } } # END ROLE Opened role Closed { use MyApp::Bundle; method close { carp 'already closed' } method open { # Cannot lock an open door if ($->is_locked) { say 'you cannot open a locked door'; return; } switch_role($self, 'Door', 'Closed', 'Opened'); } } # END ROLE Opened role Locked { use MyApp::Bundle; method lock { carp 'already locked' } method unlock { switch_role($self, 'Door', 'Locked', 'Unlocked') } } # END ROLE Locked role Unlocked { use MyApp::Bundle; method lock { if ($->is_opened) { carp 'you cannot lock an open door'; return; } switch_role($self, 'Door', 'Unlocked', 'Locked') } method unlock { carp 'already unlocked' } } # END ROLE Unlocked