package MyObj 0.001; use 5.012; use Moose; use namespace::autoclean; has 'length' => ( is => 'ro', isa => 'Int', required => 1, ); has 'is_circular' => ( is => 'ro', isa => 'Bool', required => 1, ); has '_offset_sub' => ( is => 'ro', isa => 'CodeRef', lazy => 1, builder => '_build_offset_sub', init_arg => undef, ); sub offset () { my ( $self, $current_coord, $offset ) = @_; return $self->_offset_sub()->( $self, $current_coord, $offset ); } sub _build_offset_sub { my ($self) = @_; if ( $self->is_circular() ) { # circular return sub { my ( $self, $current_coord, $offset ) = @_; return ( $current_coord - 1 + $self->length() + $offset ) % $self->length() + 1; }; } else { # linear return sub { my ( $self, $current_coord, $offset ) = @_; return $current_coord + $offset; }; } } __PACKAGE__->meta->make_immutable; 1;