File Coverage

blib/lib/CLI/Osprey.pm
Criterion Covered Total %
statement 84 87 96.5
branch 14 18 77.7
condition 2 3 66.6
subroutine 15 15 100.0
pod n/a
total 115 123 93.5


line stmt bran cond sub pod time code
1             package CLI::Osprey;
2 4     4   498145 use strict;
  4         6  
  4         155  
3 4     4   29 use warnings;
  4         6  
  4         246  
4              
5             # ABSTRACT: MooX::Options + MooX::Cmd + Sanity
6             our $VERSION = '0.09'; # VERSION
7             our $AUTHORITY = 'cpan:ARODLAND'; # AUTHORITY
8              
9 4     4   25 use Carp 'croak';
  4         8  
  4         243  
10 4     4   1940 use Module::Runtime 'use_module';
  4         7237  
  4         20  
11 4     4   263 use Scalar::Util qw(reftype);
  4         7  
  4         193  
12              
13 4     4   1869 use Moo::Role qw(); # only want class methods, not setting up a role
  4         37504  
  4         145  
14              
15 4     4   2236 use CLI::Osprey::InlineSubcommand ();
  4         20  
  4         2906  
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   4875 my (undef, @import_options) = @_;
23 8         27 my $target = caller;
24              
25 8         49 for my $method (qw(with around has)) {
26 24 50       181 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         32 my $with = $target->can('with');
31 8         26 my $around = $target->can('around');
32 8         27 my $has = $target->can('has');
33              
34 8 50       61 if ( ! Moo::Role->is_role( $target ) ) { # not in a role
35 8 50       2090 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         54 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 80     80   1689 my ($orig, $self) = (shift, shift);
63 80         1305 return $self->$orig(@_), %$osprey_config;
64 8         85 });
65              
66 8         14407 my $options_data = { };
67 8         26 my $subcommands = { };
68              
69             my $apply_modifiers = sub {
70 20 100   20   190 return if $target->can('new_with_options');
71 8         37 $with->('CLI::Osprey::Role');
72             $around->(_osprey_options => sub {
73 44         13456 my ($orig, $self) = (shift, shift);
74 44         700 return $self->$orig(@_), %$options_data;
75 8         13851 });
76             $around->(_osprey_subcommands => sub {
77 80         1872 my ($orig, $self) = (shift, shift);
78 80         1211 return $self->$orig(@_), %$subcommands;
79 8         3997 });
80 8         49 };
81              
82 8         15 my $added_order = 0;
83              
84             my $option = sub {
85 6     6   40 my ($name, %attributes) = @_;
86              
87 6         22 $has->($name => _non_option_attributes(%attributes));
88 6         1653 $options_data->{$name} = _option_attributes($name, %attributes);
89 6         15 $options_data->{$name}{added_order} = ++$added_order;
90 6         14 $apply_modifiers->();
91 8         33 };
92              
93             my $subcommand = sub {
94 6     6   52 my ($name, $subobject) = @_;
95              
96 6 100 66     53 if (ref($subobject) && reftype($subobject) eq 'CODE') {
97 1         5 my @args = @_[2 .. $#_];
98 1         11 $subobject = CLI::Osprey::InlineSubcommand->new(
99             name => $name,
100             method => $subobject,
101             @args,
102             );
103             }
104             else {
105 5 100       28 use_module($subobject) unless $osprey_config->{on_demand};
106             }
107              
108 6         1907 $subcommands->{$name} = $subobject;
109 6         17 $apply_modifiers->();
110 8         36 };
111              
112 8 50       33 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   69 no strict 'refs';
  4         85  
  4         1572  
  8         16  
119 8         14 *{"${target}::option"} = $option;
  8         62  
120 8         13 *{"${target}::subcommand"} = $subcommand;
  8         35  
121             }
122              
123 8         27 $apply_modifiers->();
124              
125 8         4372 return;
126             }
127              
128             sub _non_option_attributes {
129 6     6   18 my (%attributes) = @_;
130 6         37 my %filter_out;
131 6         46 @filter_out{@OPTIONS_ATTRIBUTES} = ();
132             return map {
133 12         50 $_ => $attributes{$_}
134             } grep {
135 6         19 !exists $filter_out{$_}
  28         53  
136             } keys %attributes;
137             }
138              
139             sub _option_attributes {
140 6     6   24 my ($name, %attributes) = @_;
141              
142 6 100       19 unless (defined $attributes{option}) {
143 5         16 ($attributes{option} = $name) =~ tr/_/-/;
144             }
145 6         12 my $ret = {};
146 6         12 for (@OPTIONS_ATTRIBUTES) {
147 78 100       1300 $ret->{$_} = $attributes{$_} if exists $attributes{$_};
148             }
149 6         19 return $ret;
150             }
151              
152             1;
153              
154             __END__