X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMooseX%2FGetopt.pm;h=1417d08e2ba214c142ad2011ae01f8a58b7330a5;hb=26be7f7ed5cd799ab80bf512505ca3474626236e;hp=572be0437cf34d850e94ccc57ca48264a21ef542;hpb=bae0043998f6af157ea8a7dcd885fc032fe748d4;p=gitmo%2FMooseX-Getopt.git diff --git a/lib/MooseX/Getopt.pm b/lib/MooseX/Getopt.pm index 572be04..1417d08 100644 --- a/lib/MooseX/Getopt.pm +++ b/lib/MooseX/Getopt.pm @@ -2,20 +2,73 @@ package MooseX::Getopt; use Moose::Role; -use Getopt::Long; +use Getopt::Long (); use MooseX::Getopt::OptionTypeMap; use MooseX::Getopt::Meta::Attribute; -our $VERSION = '0.01'; +our $VERSION = '0.06'; our $AUTHORITY = 'cpan:STEVAN'; -has ARGV => (is => 'rw', isa => 'ArrayRef'); +has ARGV => (is => 'rw', isa => 'ArrayRef'); +has extra_argv => (is => 'rw', isa => 'ArrayRef'); sub new_with_options { my ($class, %params) = @_; - my (@options, %name_to_init_arg); + my %processed = $class->_parse_argv( + options => [ + $class->_attrs_to_options( %params ) + ] + ); + + $class->new( + ARGV => $processed{argv_copy}, + extra_argv => $processed{argv}, + %params, # explicit params to ->new + %{ $processed{params} }, # params from CLI + ); +} + +sub _parse_argv { + my ( $class, %params ) = @_; + + local @ARGV = @{ $params{argv} || \@ARGV }; + + my ( @options, %name_to_init_arg, %options ); + + foreach my $opt ( @{ $params{options} } ) { + push @options, $opt->{opt_string}; + $name_to_init_arg{ $opt->{name} } = $opt->{init_arg}; + } + + # Get a clean copy of the original @ARGV + my $argv_copy = [ @ARGV ]; + + { + local $SIG{__WARN__} = sub { die $_[0] }; + Getopt::Long::GetOptions(\%options, @options); + } + + # Get a copy of the Getopt::Long-mangled @ARGV + my $argv_mangled = [ @ARGV ]; + + return ( + argv_copy => $argv_copy, + argv => $argv_mangled, + params => { + map { + $name_to_init_arg{$_} => $options{$_} + } keys %options, + } + ); +} + +sub _attrs_to_options { + my $class = shift; + + my @options; + foreach my $attr ($class->meta->compute_all_applicable_attributes) { my $name = $attr->name; @@ -28,9 +81,7 @@ sub new_with_options { else { next if $name =~ /^_/; } - - $name_to_init_arg{$name} = $attr->init_arg; - + my $opt_string = $aliases ? join(q{|}, $name, @$aliases) : $name; @@ -41,27 +92,17 @@ sub new_with_options { $opt_string .= MooseX::Getopt::OptionTypeMap->get_option_type($type_name); } } - - push @options => $opt_string; + + push @options, { + name => $name, + init_arg => $attr->init_arg, + opt_string => $opt_string, + required => $attr->is_required, + ( $attr->has_documentation ? ( doc => $attr->documentation ) : () ), + } } - my $saved_argv = [ @ARGV ]; - my %options; - - GetOptions(\%options, @options); - - #use Data::Dumper; - #warn Dumper \@options; - #warn Dumper \%name_to_init_arg; - #warn Dumper \%options; - - $class->new( - ARGV => $saved_argv, - %params, - map { - $name_to_init_arg{$_} => $options{$_} - } keys %options, - ); + return @options; } no Moose::Role; 1; @@ -114,7 +155,17 @@ to get non-default commandline option names and aliases. By default, attributes which start with an underscore are not given commandline argument support, unless the attribute's metaclass is set -to L. +to L. If you don't want you accessors +to have the leading underscore in thier name, you can do this: + + # for read/write attributes + has '_foo' => (accessor => 'foo', ...); + + # or for read-only attributes + has '_bar' => (reader => 'bar', ...); + +This will mean that Getopt will not handle a --foo param, but your +code can still call the C method. =head2 Supported Type Constraints @@ -208,6 +259,20 @@ the type constraint validations with the Getopt::Long validations. Better examples are certainly welcome :) +=head2 Inferred Type Constraints + +If you define a custom subtype which is a subtype of one of the +standard L above, and do not explicitly +provide custom support as in L above, +MooseX::Getopt will treat it like the parent type for Getopt +purposes. + +For example, if you had the same custom C subtype +from the examples above, but did not add a new custom option +type for it to the C, it would be treated just +like a normal C type for Getopt purposes (that is, +C<=s@>). + =head1 METHODS =over 4 @@ -218,11 +283,19 @@ This method will take a set of default C<%params> and then collect params from the command line (possibly overriding those in C<%params>) and then return a newly constructed object. +If L fails (due to invalid arguments), +C will throw an exception. + =item B This accessor contains a reference to a copy of the C<@ARGV> array -which was copied before L mangled it, in case you want -to see your original options. +as it originally existed at the time of C. + +=item B + +This accessor contains an arrayref of leftover C<@ARGV> elements that +L did not parse. Note that the real C<@ARGV> is left +un-mangled. =item B @@ -240,6 +313,8 @@ to cpan-RT. Stevan Little Estevan@iinteractive.comE +Brandon L. Black, Eblblack@gmail.comE + =head1 COPYRIGHT AND LICENSE Copyright 2007 by Infinity Interactive, Inc.