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.05';
our $AUTHORITY = 'cpan:STEVAN';
+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);
foreach my $attr ($class->meta->compute_all_applicable_attributes) {
my $name = $attr->name;
-
- if ($attr->isa('MooseX::Getopt::Meta::Attribute') && $attr->has_cmd_flag) {
- $name = $attr->cmd_flag;
- }
+
+ my $aliases;
+
+ if ($attr->isa('MooseX::Getopt::Meta::Attribute')) {
+ $name = $attr->cmd_flag if $attr->has_cmd_flag;
+ $aliases = $attr->cmd_aliases if $attr->has_cmd_aliases;
+ }
+ else {
+ next if $name =~ /^_/;
+ }
$name_to_init_arg{$name} = $attr->init_arg;
+ my $opt_string = $aliases
+ ? join(q{|}, $name, @$aliases)
+ : $name;
+
if ($attr->has_type_constraint) {
my $type_name = $attr->type_constraint->name;
if (MooseX::Getopt::OptionTypeMap->has_option_type($type_name)) {
- $name .= MooseX::Getopt::OptionTypeMap->get_option_type($type_name);
+ $opt_string .= MooseX::Getopt::OptionTypeMap->get_option_type($type_name);
}
}
- push @options => $name;
+ push @options => $opt_string;
}
my %options;
-
- GetOptions(\%options, @options);
+
+ # 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 ];
+
+ # Restore the original @ARGV;
+ @ARGV = @$argv_copy;
#use Data::Dumper;
#warn Dumper \@options;
#warn Dumper \%options;
$class->new(
+ ARGV => $argv_copy,
+ extra_argv => $argv_mangled,
%params,
map {
$name_to_init_arg{$_} => $options{$_}
- } keys %options
+ } keys %options,
);
}
params by introspecting your class's attributes. It will use the name
of your attribute as the command line option, and if there is a type
constraint defined, it will configure Getopt::Long to handle the option
-accordingly.
+accordingly.
+
+You can use the attribute metaclass L<MooseX::Getopt::Meta::Attribute>
+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<MooseX::Getopt::Meta::Attribute>. 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<foo> method.
=head2 Supported Type Constraints
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</Supported Type Constraints> above, and do not explicitly
+provide custom support as in L</Custom Type Constraints> above,
+MooseX::Getopt will treat it like the parent type for Getopt
+purposes.
+
+For example, if you had the same custom C<ArrayOfInts> subtype
+from the examples above, but did not add a new custom option
+type for it to the C<OptionTypeMap>, it would be treated just
+like a normal C<ArrayRef> type for Getopt purposes (that is,
+C<=s@>).
+
=head1 METHODS
=over 4
params from the command line (possibly overriding those in C<%params>)
and then return a newly constructed object.
+If L<Getopt::Long/GetOptions> fails (due to invalid arguments),
+C<new_with_options> will throw an exception.
+
+=item B<ARGV>
+
+This accessor contains a reference to a copy of the C<@ARGV> array
+as it originally existed at the time of C<new_with_options>.
+
+=item B<extra_argv>
+
+This accessor contains an arrayref of leftover C<@ARGV> elements that
+L<Getopt::Long> did not parse. Note that the real C<@ARGV> is left
+un-mangled.
+
=item B<meta>
This returns the role meta object.
Stevan Little E<lt>stevan@iinteractive.comE<gt>
+Brandon L. Black, E<lt>blblack@gmail.comE<gt>
+
=head1 COPYRIGHT AND LICENSE
Copyright 2007 by Infinity Interactive, Inc.