The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package MooseX::App::Plugin::MutexGroup;

use Moose::Role;
use namespace::autoclean;

sub plugin_metaroles {
    my ($self, $class) = @_;

    return {
        attribute => ['MooseX::App::Plugin::MutexGroup::Meta::Attribute'],
        class     => ['MooseX::App::Plugin::MutexGroup::Meta::Class'],
    }
}

1;

__END__

=encoding utf8

=head1 NAME

MooseX::App::Plugin::MutexGroup - Adds mutually exclusive options

=head1 SYNOPSIS

In your base class:

 package MyApp;
 use MooseX::App qw(MutexGroup);
 
 option 'UseAmmonia' => (
   is         => 'ro',
   isa        => 'Bool',
   mutexgroup => 'NonMixableCleaningChemicals',
 );
 
 option 'UseChlorine' => (
   is         => 'ro',
   isa        => 'Bool',
   mutexgroup => 'NonMixableCleaningChemicals'
 );

In your script:

 #!/usr/bin/env perl
 
 use strict;
 use warnings;
 
 use MyApp;
 
 MyApp->new_with_options( UseAmmonia => 1, UseChlorine => 1 );
 # generates Error
 # More than one attribute from mutexgroup NonMixableCleaningChemicals('UseAmmonia','UseChlorine') *cannot* be specified
 
 MyApp->new_with_options();
 # generates Error
 # One attribute from mutexgroup NonMixableCleaningChemicals('UseAmmonia','UseChlorine') *must* be specified
 
 MyApp->new_with_options( UseAmmonia => 1 );
 # generates no errors
 
 MyApp->new_with_options( UseChlorine => 1 );
 # generates no errors

=head1 DESCRIPTION

This plugin adds mutually exclusive options to your application. In the current implementation, all defined
MutexGroups *must* have exactly one initialized option. This means that there is an implicit requiredness
of one option from each MutexGroup.

=cut