[PATCH] MooseX::Getopt - options shouldn't be required if loaded from config
[email protected] (Ryan D Johnson)
| Newsgroups | perl.moose |
|---|---|
| Message-ID | <[email protected]> |
A command-line option shouldn't be required in the case that the given "required" attribute has been loaded from a config file (using MooseX::ConfigFromFile). My solution involves running Getopt::Long twice -- once merely to look for the configfile flag, then again with a full spec to parse the rest of the options. I'm not thrilled with this, so please chime in with better ideas. :-) I'm attaching a patch with tests. If it's more convenient for you, the changes are also at http://git.innerfence.com/?p=MooseX-Getopt.git;a=summary. I've subscribed to this list, and I'm rdj on #moose. /rdj
MooseX-Getopt-AttributesFromConfigNotRequired.diff
(text/x-diff, 7.5 KB)
diff --git a/ChangeLog b/ChangeLog
index 8e14e30..444fca5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
Revision history for Perl extension MooseX-Getopt
+0.13 Unreleased
+ * MooseX::Getopt
+ - Commandline option shouldn't be required in the
+ case that the given "required" attribute has
+ been loaded from config (MooseX::ConfigFromFile)
+
0.12 Fri. March 14, 2008
~~ updated copyright dates ~~
diff --git a/lib/MooseX/Getopt.pm b/lib/MooseX/Getopt.pm
index a8ce4a3..8c6385f 100644
--- a/lib/MooseX/Getopt.pm
+++ b/lib/MooseX/Getopt.pm
@@ -9,7 +9,7 @@ use MooseX::Getopt::Meta::Attribute::NoGetopt;
use Getopt::Long (); # GLD uses it anyway, doesn't hurt
use constant HAVE_GLD => not not eval { require Getopt::Long::Descriptive };
-our $VERSION = '0.12';
+our $VERSION = '0.12_01';
our $AUTHORITY = 'cpan:STEVAN';
has ARGV => (is => 'rw', isa => 'ArrayRef', metaclass => "NoGetopt");
@@ -18,33 +18,32 @@ has extra_argv => (is => 'rw', isa => 'ArrayRef', metaclass => "NoGetopt");
sub new_with_options {
my ($class, @params) = @_;
- my %processed = $class->_parse_argv(
- options => [
- $class->_attrs_to_options( @params )
- ]
- );
-
- my $params = $processed{params};
-
+ my $config_from_file;
if($class->meta->does_role('MooseX::ConfigFromFile')) {
+ local @ARGV = @ARGV;
+
my $configfile;
+ my $opt_parser = Getopt::Long::Parser->new( config => [ qw( pass_through ) ] );
+ $opt_parser->getoptions( "configfile=s" => \$configfile );
- if(defined $params->{configfile}) {
- $configfile = $params->{configfile}
- }
- else {
+ if(!defined $configfile) {
my $cfmeta = $class->meta->get_attribute('configfile');
$configfile = $cfmeta->default if $cfmeta->has_default;
}
if(defined $configfile) {
- %$params = (
- %{$class->get_config_from_file($configfile)},
- %$params,
- );
+ $config_from_file = $class->get_config_from_file($configfile);
}
}
+ my %processed = $class->_parse_argv(
+ options => [
+ $class->_attrs_to_options( $config_from_file )
+ ]
+ );
+
+ my $params = $config_from_file ? { %$config_from_file, %{$processed{params}} } : $processed{params};
+
$class->new(
ARGV => $processed{argv_copy},
extra_argv => $processed{argv},
@@ -169,6 +168,7 @@ sub _get_cmd_flags_for_attr {
sub _attrs_to_options {
my $class = shift;
+ my $config_from_file = shift || {};
my @options;
@@ -188,7 +188,7 @@ sub _attrs_to_options {
name => $flag,
init_arg => $attr->init_arg,
opt_string => $opt_string,
- required => $attr->is_required && !$attr->has_default && !$attr->has_builder,
+ required => $attr->is_required && !$attr->has_default && !$attr->has_builder && !exists $config_from_file->{$attr->name},
( ( $attr->has_default && ( $attr->is_default_a_coderef xor $attr->is_lazy ) ) ? ( default => $attr->default({}) ) : () ),
( $attr->has_documentation ? ( doc => $attr->documentation ) : () ),
}
@@ -423,6 +423,10 @@ Stevan Little E<lt>[email protected]<gt>
Brandon L. Black, E<lt>[email protected]<gt>
+=head1 CONTRIBUTORS
+
+Ryan D Johnson, E<lt>[email protected]<gt>
+
=head1 COPYRIGHT AND LICENSE
Copyright 2007-2008 by Infinity Interactive, Inc.
diff --git a/t/008_configfromfile.t b/t/008_configfromfile.t
new file mode 100644
index 0000000..affcd7e
--- /dev/null
+++ b/t/008_configfromfile.t
@@ -0,0 +1,164 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::Exception;
+use Test::More;
+
+if ( !eval { require MooseX::ConfigFromFile } )
+{
+ plan skip_all => 'Test requires MooseX::ConfigFromFile';
+}
+else
+{
+ plan tests => 24;
+}
+
+{
+ package App;
+
+ use Moose;
+ with 'MooseX::Getopt';
+ with 'MooseX::ConfigFromFile';
+
+ has 'config_from_override' => (
+ is => 'ro',
+ isa => 'Bool',
+ default => 0,
+ );
+
+ has 'optional_from_config' => (
+ is => 'ro',
+ isa => 'Str',
+ required => 0,
+ );
+
+ has 'required_from_config' => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+ );
+
+ has 'required_from_argv' => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+ );
+
+ sub get_config_from_file
+ {
+ my ( $class, $file ) = @_;
+
+ my %config = (
+ required_from_config => 'from_config_1',
+ optional_from_config => 'from_config_2',
+ );
+
+ if ( $file ne '/notused/default' ) {
+ $config{config_from_override} = 1;
+ }
+
+ return \%config;
+ }
+}
+
+{
+ package App::DefaultConfigFile;
+
+ use Moose;
+ extends 'App';
+
+ has '+configfile' => (
+ default => '/notused/default',
+ );
+}
+
+# No config specified
+{
+ local @ARGV = qw( --required_from_argv 1 );
+
+ throws_ok { App->new_with_options } qr/Required option missing: required_from_config/;
+
+ {
+ my $app = App::DefaultConfigFile->new_with_options;
+ isa_ok( $app, 'App::DefaultConfigFile' );
+ app_ok( $app );
+
+ ok( !$app->config_from_override,
+ '... config_from_override false as expected' );
+
+ is( $app->configfile, '/notused/default',
+ '... configfile is /notused/default as expected' );
+ }
+}
+
+# Config specified
+{
+ local @ARGV = qw( --configfile /notused --required_from_argv 1 );
+
+ {
+ my $app = App->new_with_options;
+ isa_ok( $app, 'App' );
+ app_ok( $app );
+ }
+
+ {
+ my $app = App::DefaultConfigFile->new_with_options;
+ isa_ok( $app, 'App::DefaultConfigFile' );
+ app_ok( $app );
+
+ ok( $app->config_from_override,
+ '... config_from_override true as expected' );
+
+ is( $app->configfile, '/notused',
+ '... configfile is /notused as expected' );
+ }
+}
+
+# Required arg not supplied from cmdline
+{
+ local @ARGV = qw( --configfile /notused );
+ throws_ok { App->new_with_options } qr/Required option missing: required_from_argv/;
+}
+
+# Config file value overriden from cmdline
+{
+ local @ARGV = qw( --configfile /notused --required_from_argv 1 --required_from_config override );
+
+ my $app = App->new_with_options;
+ isa_ok( $app, 'App' );
+
+ is( $app->required_from_config, 'override',
+ '... required_from_config is override as expected' );
+
+ is( $app->optional_from_config, 'from_config_2',
+ '... optional_from_config is from_config_2 as expected' );
+}
+
+# No config file
+{
+ local @ARGV = qw( --required_from_argv 1 --required_from_config noconfig );
+
+ my $app = App->new_with_options;
+ isa_ok( $app, 'App' );
+
+ is( $app->required_from_config, 'noconfig',
+ '... required_from_config is noconfig as expected' );
+
+ ok( !defined $app->optional_from_config,
+ '... optional_from_config is undef as expected' );
+}
+
+sub app_ok {
+ my $app = shift;
+
+ is( $app->required_from_config, 'from_config_1',
+ '... required_from_config is from_config_1 as expected' );
+
+ is( $app->optional_from_config, 'from_config_2',
+ '... optional_from_config is from_config_2 as expected' );
+
+ is( $app->required_from_argv, '1',
+ '... required_from_argv is 1 as expected' );
+}