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   375258 use strict;
  4         19  
  4         117  
3 4     4   20 use warnings;
  4         19  
  4         179  
4              
5             # ABSTRACT: MooX::Options + MooX::Cmd + Sanity
6             our $VERSION = '0.07'; # VERSION
7             our $AUTHORITY = 'cpan:ARODLAND'; # AUTHORITY
8              
9 4     4   26 use Carp 'croak';
  4         8  
  4         197  
10 4     4   25 use Module::Runtime 'use_module';
  4         9  
  4         22  
11 4     4   215 use Scalar::Util qw(reftype);
  4         10  
  4         214  
12              
13 4     4   2044 use Moo::Role qw(); # only want class methods, not setting up a role
  4         35356  
  4         117  
14              
15 4     4   1817 use CLI::Osprey::InlineSubcommand ();
  4         33  
  4         2713  
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   3009 my (undef, @import_options) = @_;
23 8         27 my $target = caller;
24              
25 8         25 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         33 my $with = $target->can('with');
31 8         26 my $around = $target->can('around');
32 8         23 my $has = $target->can('has');
33              
34 8 50       75 if ( ! Moo::Role->is_role( $target ) ) { # not in a role
35 8 50       1574 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         44 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 28     28   659 my ($orig, $self) = (shift, shift);
63 28         456 return $self->$orig(@_), %$osprey_config;
64 8         108 });
65              
66 8         11529 my $options_data = { };
67 8         22 my $subcommands = { };
68              
69             my $apply_modifiers = sub {
70 15 100   15   133 return if $target->can('new_with_options');
71 8         35 $with->('CLI::Osprey::Role');
72             $around->(_osprey_options => sub {
73 17         414 my ($orig, $self) = (shift, shift);
74 17         281 return $self->$orig(@_), %$options_data;
75 8         10178 });
76             $around->(_osprey_subcommands => sub {
77 28         663 my ($orig, $self) = (shift, shift);
78 28         479 return $self->$orig(@_), %$subcommands;
79 8         3026 });
80 8         44 };
81              
82 8         19 my $added_order = 0;
83              
84             my $option = sub {
85 1     1   11 my ($name, %attributes) = @_;
86              
87 1         9 $has->($name => _non_option_attributes(%attributes));
88 1         323 $options_data->{$name} = _option_attributes($name, %attributes);
89 1         7 $options_data->{$name}{added_order} = ++$added_order;
90 1         11 $apply_modifiers->();
91 8         61 };
92              
93             my $subcommand = sub {
94 6     6   44 my ($name, $subobject) = @_;
95              
96 6 100 66     46 if (ref($subobject) && reftype($subobject) eq 'CODE') {
97 1         4 my @args = @_[2 .. $#_];
98 1         10 $subobject = CLI::Osprey::InlineSubcommand->new(
99             name => $name,
100             method => $subobject,
101             @args,
102             );
103             }
104             else {
105 5 100       25 use_module($subobject) unless $osprey_config->{on_demand};
106             }
107              
108 6         1666 $subcommands->{$name} = $subobject;
109 6         17 $apply_modifiers->();
110 8         48 };
111              
112 8 50       31 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         12  
  4         1717  
  8         14  
119 8         16 *{"${target}::option"} = $option;
  8         40  
120 8         16 *{"${target}::subcommand"} = $subcommand;
  8         38  
121             }
122              
123 8         28 $apply_modifiers->();
124              
125 8         3087 return;
126             }
127              
128             sub _non_option_attributes {
129 1     1   5 my (%attributes) = @_;
130 1         3 my %filter_out;
131 1         11 @filter_out{@OPTIONS_ATTRIBUTES} = ();
132             return map {
133 2         11 $_ => $attributes{$_}
134             } grep {
135 1         5 !exists $filter_out{$_}
  4         13  
136             } keys %attributes;
137             }
138              
139             sub _option_attributes {
140 1     1   4 my ($name, %attributes) = @_;
141              
142 1 50       6 unless (defined $attributes{option}) {
143 1         5 ($attributes{option} = $name) =~ tr/_/-/;
144             }
145 1         2 my $ret = {};
146 1         3 for (@OPTIONS_ATTRIBUTES) {
147 13 100       29 $ret->{$_} = $attributes{$_} if exists $attributes{$_};
148             }
149 1         5 return $ret;
150             }
151              
152             1;
153              
154             __END__