File Coverage

lib/CLI/Dispatch.pm
Criterion Covered Total %
statement 95 104 91.3
branch 27 36 75.0
condition 6 10 60.0
subroutine 19 21 90.4
pod 9 9 100.0
total 156 180 86.6


line stmt bran cond sub pod time code
1             package CLI::Dispatch;
2              
3 10     10   366765 use strict;
  10         27  
  10         342  
4 10     10   51 use warnings;
  10         21  
  10         243  
5 10     10   49 use Carp;
  10         23  
  10         748  
6 10     10   13744 use Getopt::Long ();
  10         133037  
  10         269  
7 10     10   10449 use String::CamelCase;
  10         5573  
  10         555  
8 10     10   7500 use Try::Tiny;
  10         13889  
  10         11304  
9              
10             our $VERSION = '0.19';
11              
12             # you may want to override these three methods.
13              
14 68     68 1 331 sub options {qw( help|h|? verbose|v debug logfilter=s )}
15              
16 7     7 1 38 sub default_command { 'help' }
17              
18             sub get_command {
19 54     54 1 106 my $self = shift;
20              
21 54   66     242 my $command = shift @ARGV || $self->default_command;
22 54         205 return $self->convert_command($command);
23             }
24              
25             sub convert_command {
26 74     74 1 211 my ($self, $command) = @_;
27              
28 74         1682 $command = String::CamelCase::camelize( $command );
29 74         1095 $command =~ tr/a-zA-Z0-9_//cd;
30 74         202 return $command;
31             }
32              
33             # you usually don't need to care below.
34              
35             sub new {
36 68     68 1 146 my ($class, %opts) = @_;
37 68         220 bless \%opts, $class;
38             }
39              
40             sub get_options {
41 133     133 1 362 my ($self, @specs) = @_;
42              
43 133         965 my $parser = Getopt::Long::Parser->new(
44             config => [qw( bundling ignore_case pass_through )]
45             );
46              
47 133         12431 $parser->getoptions( \my %hash => @specs );
48              
49 133         53716 return %hash;
50             }
51              
52             sub load_command {
53 59     59 1 171 my ($self, $namespaces, $help) = @_;
54              
55 59         207 my $command = $self->get_command;
56              
57 59 100       221 if ( $help ) {
58 7         18 unshift @ARGV, $command;
59 7         19 $command = 'Help';
60             }
61              
62 59         204 my $instance = $self->_load_command($namespaces, $command);
63 56 100       375 return $instance if $instance;
64              
65             # fallback to help (maybe the command is just a pod)
66 4         12 unshift @ARGV, $command;
67 4         20 $instance = $self->_load_command($namespaces, 'Help');
68 4 50       26 return $instance if $instance;
69              
70             # this shouldn't happen
71 0         0 print STDERR "Help command is missing or broken.\n";
72 0         0 print STDERR "Prerequisite modules may not be installed.\n";
73 0         0 print STDERR "Please check your installation.\n";
74 0         0 exit;
75             }
76              
77             sub _load_command {
78 63     63   132 my ($self, $namespaces, $command) = @_;
79              
80 63         144 foreach my $namespace (@$namespaces) {
81 67         164 my $package = $namespace.'::'.$command;
82 67 100       842 return $package->new if $package->can('new');
83              
84 36         51 my $error;
85 36 100   36   4174 try { eval "require $package" or die }
86 36   50 18   296 catch { $error = $_ || 'Obscure error' };
  18         844  
87 36 100       3953 return $package->new unless $error;
88              
89 18         63 my $file = _package_file($package);
90 18 100       556 next if $error =~ /Can't locate $file/;
91 3         644 croak $error;
92             }
93              
94 11 100       51 if ($command eq 'Help') {
95 7         2037 require CLI::Dispatch::Help;
96 7         80 return CLI::Dispatch::Help->new;
97             }
98 4         12 return;
99             }
100              
101             sub _package_file {
102 18     18   66 my $package = shift;
103              
104 18         96 $package =~ s{::}{/}g;
105 18         45 $package .= '\.(?:pm|pod)';
106 18         129 $package;
107             }
108              
109             sub run {
110 59     59 1 406716 my ($self, @namespaces) = @_;
111              
112 59         102 my $class;
113 59 50       224 unless ($class = ref $self) {
114 59         103 $class = $self;
115 59         205 $self = $self->new;
116             }
117              
118 59 100       170 if (!grep { $_ ne $class } @namespaces) {
  42         147  
119 29         51 push @namespaces, $class;
120             }
121              
122 59         233 my %global = $self->get_options( $self->options );
123 59         327 my $command = $self->load_command( \@namespaces, $global{help} );
124 56         408 my %local = $self->get_options( $command->options );
125              
126 56         519 $command->set_options( %$self, %global, %local, _namespaces => \@namespaces );
127              
128 56 100 100     643 if ( $command->isa('CLI::Dispatch::Help') and @ARGV ) {
129 20         94 $ARGV[0] = $self->convert_command($ARGV[0]);
130             }
131              
132 56 100       428 $command->check if $command->can('check');
133              
134 53         273 $command->run(@ARGV);
135             }
136              
137             sub run_directly {
138 9     9 1 15 my ($self, $package) = @_;
139              
140 9 50       85 unless ($package->can('new')) {
141 0         0 my $error;
142 0 0   0   0 try { eval "require $package" or die }
143 0   0 0   0 catch { $error = $_ || 'Obscure error' };
  0         0  
144 0 0       0 croak $error if $error;
145             }
146              
147 9         12 my $class;
148 9 50       31 unless ($class = ref $self) {
149 9         14 $class = $self;
150 9         25 $self = $self->new;
151             }
152              
153 9         24 my %global = $self->get_options( $self->options );
154 9         40 my $command = $package->new;
155 9 100       27 if ($global{help}) {
156 1         1014 require CLI::Dispatch::Help;
157 1         16 $command = CLI::Dispatch::Help->new;
158 1         7 unshift @ARGV, "+$package";
159             }
160 9         39 my %local = $self->get_options( $command->options );
161              
162 9         50 $command->set_options( %global, %local );
163              
164 9 50       52 $command->check if $command->can('check');
165              
166 9         35 $command->run(@ARGV);
167             }
168              
169             1;
170              
171             __END__