MooseX-Getopt-Defanged

 view release on metacpan or  search on metacpan

lib/MooseX/Getopt/Defanged.pm  view on Meta::CPAN


    return;
} # end parse_command_line()


sub _getopt_get_option_attributes {
    my ($self) = @_;

    my $metadata = $self->meta();
    my @option_attributes =
        grep {
            $_->does('MooseX::Getopt::Defanged::Meta::Attribute::Trait::_Getopt')
        }
        $metadata->get_all_attributes();

    return \@option_attributes;
} # end _getopt_get_option_attributes()


sub _getopt_invoke_getopt_long {
    my ($self, $argv_ref) = @_;

    my $stderr;

    my $parser = Getopt::Long::Parser->new(
        config => [
            # Unfortunately, bundling is incompatible with allowing multiple
            # values for a given option (why I don't know, but Getopt::Long
            # complains if gnu_getopt, and thus bundling, is turned on).
            qw<
                no_auto_abbrev
                no_auto_help
                no_auto_version
                no_bundling
                no_getopt_compat
                   gnu_compat
                no_ignore_case
                   permute
            >
        ],
    );

    my @option_attributes =
        @{ $self->_getopt_get_option_attributes() };
    my $type_metadata = $self->get_option_type_metadata();
    my %option_values =
        map { ## no critic (Lax::ProhibitComplexMappings::LinesNotStatements)
                $_->get_actual_option_name()
            =>  $_->get_stringified_value_or_default($self, $type_metadata)
        }
        grep {
            defined $_->get_stringified_value_or_default($self, $type_metadata)
        }
            @option_attributes;
    my @specification_strings =
        map { $_->get_full_specification($type_metadata) } @option_attributes;

    my $parse_worked;

    {
        local @ARGV = @{$argv_ref};

        open my $stderr_handle, '>', \$stderr;
        $parse_worked = _getopt_invoke_getopt_long_while_handling_exceptions(
            $parser, $stderr_handle, \%option_values, \@specification_strings,
        );
        close $stderr_handle;

        $self->_set_remaining_argv( [ @ARGV ] );
    } # end scoping block

    throw_user $stderr // 'Could not parse command-line.'
        if not $parse_worked;

    return \%option_values;
} # end _getopt_invoke_getopt_long()


# If an exception is unhandled while STDERR is localized, STDERR never gets
# un-localized, meaning that the error never gets emitted to the real STDERR.
# So we run Getopt::Long::Parser::getoptions() inside of an eval and rethrow
# any exception after STDERR is no longer localized.
sub _getopt_invoke_getopt_long_while_handling_exceptions {
    my ($parser, $stderr_handle, $option_values_ref, $specification_strings_ref)
        = @_;

    my $getopt_error;
    my $parse_worked;
    {
        local *STDERR = $stderr_handle;

        eval {
            $parse_worked =
                $parser->getoptions(
                    $option_values_ref, @{$specification_strings_ref},
                );
            1;
        }
            or do {
                $getopt_error =
                        $EVAL_ERROR
                    //  'Getopt::Long::Parser::getoptions() failed for an unknown reason.';
            };
    } # end scoping block

    if (defined $getopt_error) {
        throw_generic $getopt_error;
    } # end if

    return $parse_worked;
} # end _getopt_invoke_getopt_long_while_handling_exceptions()


sub _getopt_assign_option_values {
    my ($self, $option_values_ref) = @_;

    my $type_metadata = $self->get_option_type_metadata();

    my $error_message;
    foreach my $option_attribute (
        @{ $self->_getopt_get_option_attributes() }



( run in 0.865 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )