Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

track parent command's attributes with local override #17

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpanfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ requires 'Path::Tiny';
on 'test' => sub {
requires 'Test::More' => 1;
requires 'Test::Lib';
requires 'Test::Fatal';
requires 'Capture::Tiny';
};
57 changes: 56 additions & 1 deletion lib/CLI/Osprey.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use warnings;

use Carp 'croak';
use Module::Runtime 'use_module';
use Scalar::Util qw(reftype);
use Scalar::Util qw(reftype blessed);

use Moo::Role qw(); # only want class methods, not setting up a role

Expand Down Expand Up @@ -84,6 +84,16 @@ sub import {
my $option = sub {
my ($name, %attributes) = @_;


if ( $attributes{inherit}
&& !defined $attributes{default}
&& !defined $attributes{builder}
&& $attributes{is} ne 'lazy' )
{
$attributes{builder} = _inherited_option_builder( $target, $name );
$attributes{lazy} = 1;
}

$has->($name => _non_option_attributes(%attributes));
$options_data->{$name} = _option_attributes($name, %attributes);
$options_data->{$name}{added_order} = ++$added_order;
Expand Down Expand Up @@ -148,6 +158,40 @@ sub _option_attributes {
return $ret;
}

sub _inherited_option_builder {
my ($target, $name) = @_;

sub {
my $parent = $_[0]->{parent_command};
return unless defined $parent;

my $mth = $parent->can($name);
if (!defined $mth) {
my @path;

# we can get the class of the parent (sub)command,
# but we want the actual command name. For that
# we need $parent->parent->_osprey_subcommands.
while (defined $parent) {
unshift @path, { reverse $parent->_osprey_subcommands }->{$target};
$target = blessed $parent;
last if !defined $parent->{parent_command};
$parent = $parent->{parent_command};
}
unshift @path, $parent->invoked_as;

my $subcommand = pop @path;
my $command = join(' / ', @path);

require Carp;
Carp::croak(
qq[parent '$command' of '$subcommand' does not have a '--$name' option\n],
);
}
$mth->($parent);
}
}

1;
__END__

Expand Down Expand Up @@ -419,6 +463,17 @@ Default: B<false>.
A C<hidden> option will be recognized, but not listed in automatically generated
documentation.

=head2 inherit

Default: B<false>.

An inherited option's default value is the value of the parent
command's or sub-command's option of the same name. This attribute is
ignored if the C<default> or C<builder> attributes are set (either
explicitly or implicitly). If the option has not been set and the
parent command or sub-command does not have a similarly named option,
an exception will be thrown when the option's value is first accessed.

=head2 negatable

Default: B<false>.
Expand Down
Loading