File Coverage

blib/lib/CLI/Osprey.pm
Criterion Covered Total %
statement 84 87 96.5
branch 13 18 72.2
condition 2 3 66.6
subroutine 15 15 100.0
pod n/a
total 114 123 92.6


line stmt bran cond sub pod time code
1             package CLI::Osprey;
2 4     4   372710 use strict;
  4         20  
  4         116  
3 4     4   23 use warnings;
  4         7  
  4         183  
4              
5             # ABSTRACT: MooX::Options + MooX::Cmd + Sanity
6             our $VERSION = '0.08'; # VERSION
7             our $AUTHORITY = 'cpan:ARODLAND'; # AUTHORITY
8              
9 4     4   22 use Carp 'croak';
  4         7  
  4         201  
10 4     4   25 use Module::Runtime 'use_module';
  4         8  
  4         21  
11 4     4   248 use Scalar::Util qw(reftype);
  4         10  
  4         206  
12              
13 4     4   1945 use Moo::Role qw(); # only want class methods, not setting up a role
  4         35025  
  4         108  
14              
15 4     4   1909 use CLI::Osprey::InlineSubcommand ();
  4         14  
  4         2654  
16              
17             my @OPTIONS_ATTRIBUTES = qw(
18             option option_name format short repeatable negatable spacer_before spacer_after doc long_doc format_doc order hidden
19             );
20              
21             sub import {
22 8     8   3015 my (undef, @import_options) = @_;
23 8         24 my $target = caller;
24              
25 8         23 for my $method (qw(with around has)) {
26 24 50       165 next if $target->can($method);
27 0         0 croak "Can't find the method '$method' in package '$target'. CLI::Osprey requires a Role::Tiny-compatible object system like Moo or Moose.";
28             }
29              
30 8         31 my $with = $target->can('with');
31 8         26 my $around = $target->can('around');
32 8         26 my $has = $target->can('has');
33              
34 8 50       44 if ( ! Moo::Role->is_role( $target ) ) { # not in a role
35 8 50       1603 eval "package $target;\n" . q{
36             sub _osprey_options {
37             my $class = shift;
38             return $class->maybe::next::method(@_);
39             }
40              
41             sub _osprey_config {
42             my $class = shift;
43             return $class->maybe::next::method(@_);
44             }
45              
46             sub _osprey_subcommands {
47             my $class = shift;
48             return $class->maybe::next::method(@_);
49             }
50             1;
51             } || croak($@);
52             }
53              
54 8         49 my $osprey_config = {
55             preserve_argv => 1,
56             abbreviate => 1,
57             prefer_commandline => 1,
58             @import_options,
59             };
60              
61             $around->(_osprey_config => sub {
62 32     32   785 my ($orig, $self) = (shift, shift);
63 32         535 return $self->$orig(@_), %$osprey_config;
64 8         65 });
65              
66 8         11376 my $options_data = { };
67 8         17 my $subcommands = { };
68              
69             my $apply_modifiers = sub {
70 16 100   16   124 return if $target->can('new_with_options');
71 8         35 $with->('CLI::Osprey::Role');
72             $around->(_osprey_options => sub {
73 19         530 my ($orig, $self) = (shift, shift);
74 19         318 return $self->$orig(@_), %$options_data;
75 8         10085 });
76             $around->(_osprey_subcommands => sub {
77 32         741 my ($orig, $self) = (shift, shift);
78 32         536 return $self->$orig(@_), %$subcommands;
79 8         3020 });
80 8         45 };
81              
82 8         16 my $added_order = 0;
83              
84             my $option = sub {
85 2     2   23 my ($name, %attributes) = @_;
86              
87 2         12 $has->($name => _non_option_attributes(%attributes));
88 2         577 $options_data->{$name} = _option_attributes($name, %attributes);
89 2         6 $options_data->{$name}{added_order} = ++$added_order;
90 2         10 $apply_modifiers->();
91 8         61 };
92              
93             my $subcommand = sub {
94 6     6   40 my ($name, $subobject) = @_;
95              
96 6 100 66     47 if (ref($subobject) && reftype($subobject) eq 'CODE') {
97 1         5 my @args = @_[2 .. $#_];
98 1         9 $subobject = CLI::Osprey::InlineSubcommand->new(
99             name => $name,
100             method => $subobject,
101             @args,
102             );
103             }
104             else {
105 5 100       27 use_module($subobject) unless $osprey_config->{on_demand};
106             }
107              
108 6         1703 $subcommands->{$name} = $subobject;
109 6         18 $apply_modifiers->();
110 8         59 };
111              
112 8 50       34 if (my $info = $Role::Tiny::INFO{$target}) {
113 0         0 $info->{not_methods}{$option} = $option;
114 0         0 $info->{not_methods}{$subcommand} = $subcommand;
115             }
116              
117             {
118 4     4   40 no strict 'refs';
  4         9  
  4         1428  
  8         18  
119 8         11 *{"${target}::option"} = $option;
  8         59  
120 8         18 *{"${target}::subcommand"} = $subcommand;
  8         35  
121             }
122              
123 8         28 $apply_modifiers->();
124              
125 8         3082 return;
126             }
127              
128             sub _non_option_attributes {
129 2     2   6 my (%attributes) = @_;
130 2         3 my %filter_out;
131 2         16 @filter_out{@OPTIONS_ATTRIBUTES} = ();
132             return map {
133 4         20 $_ => $attributes{$_}
134             } grep {
135 2         7 !exists $filter_out{$_}
  8         20  
136             } keys %attributes;
137             }
138              
139             sub _option_attributes {
140 2     2   9 my ($name, %attributes) = @_;
141              
142 2 50       9 unless (defined $attributes{option}) {
143 2         8 ($attributes{option} = $name) =~ tr/_/-/;
144             }
145 2         4 my $ret = {};
146 2         6 for (@OPTIONS_ATTRIBUTES) {
147 26 100       52 $ret->{$_} = $attributes{$_} if exists $attributes{$_};
148             }
149 2         7 return $ret;
150             }
151              
152             1;
153              
154             __END__