123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- # ------------------------------------------------------------------------------
- # (C) Crown copyright Met Office. All rights reserved.
- # For further details please refer to the file COPYRIGHT.txt
- # which you should have received as part of this distribution.
- # ------------------------------------------------------------------------------
- use strict;
- use warnings;
- package Fcm::CLI::Subcommand;
- use Carp qw{croak};
- use Fcm::CLI::Exception;
- use Fcm::Util::ClassLoader;
- ################################################################################
- # Constructor
- sub new {
- my ($class, $args_ref) = @_;
- return bless({%{$args_ref}}, $class);
- }
- ################################################################################
- # Methods: get_*
- for my $key (
- # Returns the long description of this subcommand
- 'description',
- # Returns the class of the invoker of this subcommand
- 'invoker_class',
- # Returns the extra config to be given to the invoker of this subcommand
- 'invoker_config',
- # Returns the names of this subcommand
- 'names',
- # Returns the options of this subcommand
- 'options',
- # Returns the synopsis of this subcommand
- 'synopsis',
- # Returns the usage of this subcommand
- 'usage',
- ) {
- no strict qw{refs};
- my $getter = "get_$key";
- *$getter = sub {
- my ($self) = @_;
- if (defined($self->{$key})) {
- if (ref($self->{$key}) eq 'ARRAY') {
- return (wantarray() ? @{$self->{$key}} : $self->{$key});
- }
- else {
- return $self->{$key};
- }
- }
- else {
- return;
- }
- }
- }
- ################################################################################
- # Returns true if this subcommand represents a command in the CM sub-system
- sub is_vc {
- my ($self) = @_;
- return $self->{is_vc};
- }
- ################################################################################
- # Returns true if $string matches a name of this subcommand
- sub has_a_name {
- my ($self, $string) = @_;
- if ($self->get_names() && ref($self->get_names()) eq 'ARRAY') {
- my %name_of = map {$_, 1} @{$self->get_names()};
- return exists($name_of{$string});
- }
- else {
- return;
- }
- }
- ################################################################################
- # Invokes this subcommand based on current @ARGV
- sub get_invoker {
- my ($self, $command) = @_;
- my %options = ();
- if (($self->get_options())) {
- my $problem = q{};
- local($SIG{__WARN__}) = sub {
- ($problem) = @_;
- };
- my $success = GetOptions(
- \%options,
- (map {$_->get_arg_for_getopt_long()} ($self->get_options())),
- );
- if (!$success) {
- croak(Fcm::CLI::Exception->new({message => sprintf(
- "%s: option parse failed: %s", $command, $problem,
- )}));
- }
- }
- my $invoker_class
- = $self->get_invoker_class() ? $self->get_invoker_class()
- : 'Fcm::CLI::Invoker'
- ;
- Fcm::Util::ClassLoader::load($invoker_class);
- my $invoker = $invoker_class->new({
- command => $command,
- options => \%options,
- arguments => [@ARGV],
- });
- return $invoker;
- }
- ################################################################################
- # Returns a simple string representation of this subcommand
- sub as_string {
- my ($self) = @_;
- # FIXME: can do with using Text::Template or Perl6::Form
- if (
- $self->get_names()
- && ref($self->get_names()) eq 'ARRAY'
- && @{$self->get_names()}
- ) {
- my @names = $self->get_names();
- my $return = $names[0];
- for my $i (1 .. $#names) {
- if ($names[$i]) {
- $return
- .= $i == 1 ? q{ (} . $names[$i]
- : q{, } . $names[$i]
- ;
- }
- if ($i == $#names) {
- $return .= q{)};
- }
- }
- return $return;
- }
- else {
- return q{};
- }
- }
- 1;
- __END__
- =head1 NAME
- Fcm::CLI::Subcommand
- =head1 SYNOPSIS
- use Fcm::CLI::Subcommand;
- $subcommand = Fcm::CLI::Subcommand->new({
- names => ['build', 'bld'],
- options => [
- Fcm::CLI::Option->new(
- # ... some arguments ...
- ),
- # ... more options
- ],
- synopsis => 'invokes the build system',
- description => $description,
- usage => '[OPTIONS] [CONFIG]',
- invoker_class => $invoker_class,
- invoker_config => {
- option1 => $option1,
- # ... more options
- },
- });
- $boolean = $subcommand->has_a_name($string);
- $invoker_class = $subcommand->get_invoker_class();
- =head1 DESCRIPTION
- An object of this class is used to store the configuration of a subcommand of
- the FCM CLI.
- =head1 METHODS
- =over 4
- =item new($args_ref)
- Constructor.
- =item get_description()
- Returns the long description of this subcommand.
- =item get_invoker_class()
- Returns the invoker class of this subcommand, which should be a sub-class of
- L<Fcm::CLI::Invoker|Fcm::CLI::Invoker>.
- =item get_invoker_cconfig()
- Returns a reference to a hash containing the extra configuration to be given to
- the constructor of the invoker of this subcommand.
- =item get_names()
- Returns an array containing the names of this subcommand.
- =item get_options()
- Returns an array containing the options of this subcommand. Each element of
- the array should be a L<Fcm::CLI::Option|Fcm::CLI::Option> object.
- =item get_synopsis()
- Returns a short synopsis of this subcommand.
- =item get_usage()
- Returns a short usage statement of this subcommand.
- =item is_vc()
- Returns true if this subcommand represents commands in the underlying VC system.
- =item has_a_name($string)
- Returns true if a name in C<$self-E<gt>get_names()> matches $string.
- =back
- =head1 DIAGNOSTICS
- =over 4
- =item L<Fcm::CLI::Exception|Fcm::CLI::Exception>
- The invoke() method may croak() with this exception.
- =back
- =head1 SEE ALSO
- L<Fcm::CLI::Exception|Fcm::CLI::Exception>,
- L<Fcm::CLI::Invoker|Fcm::CLI::Invoker>,
- L<Fcm::CLI::Option|Fcm::CLI::Option>
- =head1 COPYRIGHT
- E<169> Crown copyright Met Office. All rights reserved.
- =cut
|