File Coverage

blib/lib/OptArgs2/Opt.pm
Criterion Covered Total %
statement 97 121 80.1
branch 28 58 48.2
condition 18 40 45.0
subroutine 13 15 86.6
pod 0 8 0.0
total 156 242 64.4


line stmt bran cond sub pod time code
1             package OptArgs2::Opt;
2 6     6   36 use strict;
  6         12  
  6         234  
3 6     6   31 use warnings;
  6         10  
  6         291  
4 6     6   28 use parent 'OptArgs2::OptArgBase';
  6         9  
  6         36  
5              
6             my %isa2name = (
7             'ArrayRef' => 'Str',
8             'Bool' => '',
9             'Counter' => '',
10             'Flag' => '',
11             'HashRef' => 'Str',
12             'Int' => 'Int',
13             'Input' => 'Str',
14             'Num' => 'Num',
15             'Str' => 'Str',
16             );
17              
18             my %isa2getopt = (
19             'ArrayRef' => '=s@',
20             'Bool' => '!',
21             'Counter' => '+',
22             'Flag' => '!',
23             'HashRef' => '=s%',
24             'Int' => '=i',
25             'Input' => '=s',
26             'Num' => '=f',
27             'Str' => '=s',
28             );
29              
30             ### START Class::Inline ### v0.0.1 Wed Dec 3 10:44:52 2025
31             require Carp;
32             our ( @_CLASS, $_FIELDS, %_NEW );
33              
34             sub new {
35 14     14 0 36 my $class = shift;
36 14   33     73 my $CLASS = ref $class || $class;
37 14   66     47 $_NEW{$CLASS} //= do {
38 5         11 my ( %seen, @new, @build );
39 5         16 my @possible = ($CLASS);
40 5         13 while (@possible) {
41 10         54 my $c = shift @possible;
42 6     6   1400 no strict 'refs';
  6         12  
  6         11376  
43 10 50       19 push @new, $c . '::_NEW' if exists &{ $c . '::_NEW' };
  10         55  
44 10 50       34 push @build, $c . '::BUILD' if exists &{ $c . '::BUILD' };
  10         46  
45 10         20 $seen{$c}++;
46 10 50       14 if ( exists &{ $c . '::DOES' } ) {
  10         34  
47 0         0 push @possible, grep { not $seen{$_}++ } $c->DOES('*');
  0         0  
48             }
49 10         14 push @possible, grep { not $seen{$_}++ } @{ $c . '::ISA' };
  5         26  
  10         47  
50             }
51 5         54 [ [ reverse(@new) ], [ reverse(@build) ] ];
52             };
53 14 50       134 my $self = { @_ ? @_ > 1 ? @_ : %{ $_[0] } : () };
  0 50       0  
54 14         33 bless $self, $CLASS;
55 14         67 my $attrs = { map { ( $_ => 1 ) } keys %$self };
  94         245  
56 14         35 map { $self->$_($attrs) } @{ $_NEW{$CLASS}->[0] };
  28         149  
  14         39  
57             {
58 14         22 local $Carp::CarpLevel = 3;
  14         47  
59 14         58 Carp::carp("OptArgs2::Opt: unexpected argument '$_'") for keys %$attrs
60             }
61 14         20 map { $self->$_ } @{ $_NEW{$CLASS}->[1] };
  0         0  
  14         36  
62 14         67 $self;
63             }
64              
65             sub _NEW {
66 14     14   27 CORE::state $fix_FIELDS = do {
67 5 50       38 $_FIELDS = { @_CLASS > 1 ? @_CLASS : %{ $_CLASS[0] } };
  0         0  
68 5 50       25 $_FIELDS = $_FIELDS->{'FIELDS'} if exists $_FIELDS->{'FIELDS'};
69             };
70 14 50       26 if ( my @missing = grep { not exists $_[0]->{$_} } 'isa' ) {
  14         49  
71 0         0 Carp::croak( 'OptArgs2::Opt required initial argument(s): '
72             . join( ', ', @missing ) );
73             }
74 14         27 $_[0]{'isa'} = eval { $_FIELDS->{'isa'}->{'isa'}->( $_[0]{'isa'} ) };
  14         57  
75 14 50       84 Carp::confess( 'OptArgs2::Opt isa: ' . $@ ) if $@;
76 14         27 map { delete $_[1]->{$_} } 'alias', 'hidden', 'isa', 'isa_name', 'trigger';
  70         126  
77             }
78              
79             sub __RO {
80 0     0   0 my ( undef, undef, undef, $sub ) = caller(1);
81 0         0 Carp::confess("attribute $sub is read-only");
82             }
83 6 50 100 6 0 40 sub alias { __RO() if @_ > 1; $_[0]{'alias'} // undef }
  6         29  
84 6 50 50 6 0 15 sub hidden { __RO() if @_ > 1; $_[0]{'hidden'} // undef }
  6         47  
85 15 50 50 15 0 36 sub isa { __RO() if @_ > 1; $_[0]{'isa'} // undef }
  15         68  
86              
87             sub isa_name {
88 1 50   1 0 15 __RO() if @_ > 1;
89 1   33     9 $_[0]{'isa_name'} //= $_FIELDS->{'isa_name'}->{'default'}->( $_[0] );
90             }
91 1 50 50 1 0 4 sub trigger { __RO() if @_ > 1; $_[0]{'trigger'} // undef }
  1         6  
92             @_CLASS = grep 1, ### END Class::Inline ###
93             alias => {},
94             hidden => {},
95             trigger => {},
96             isa => {
97             required => 1,
98             isa => sub {
99             $isa2name{ $_[0] }
100             // OptArgs2::croak( 'InvalidIsa', 'invalid isa type: ' . $_[0] );
101             $_[0];
102             },
103             },
104             isa_name => {
105             default => sub {
106             '(' . $isa2name{ $_[0]->isa } . ')';
107             },
108             },
109             ;
110              
111             our @CARP_NOT = @OptArgs2::CARP_NOT;
112              
113             sub new_from {
114 14     14 0 22 my $proto = shift;
115 14         53 my $ref = {@_};
116              
117             # legacy interface
118 14 50       82 if ( exists $ref->{ishelp} ) {
119 0         0 delete $ref->{ishelp};
120 0   0     0 $ref->{isa} //= OptArgs2::USAGE_HELP();
121             }
122              
123 14 100       64 if ( $ref->{isa} =~ m/^Help/ ) { # one of the USAGE_HELPs
124 9         22 my $style = $ref->{isa};
125 9         17 my $name = $style;
126 9         42 $name =~ s/([a-z])([A-Z])/$1-$2/g;
127 9         18 $ref->{isa} = 'Counter';
128 9   33     53 $ref->{name} //= lc $name;
129 9   33     71 $ref->{alias} //= lc substr $ref->{name}, 0, 1;
130 9   33     54 $ref->{comment} //= "print a $style message and exit";
131             $ref->{trigger} //= sub {
132 0     0   0 my $cmd = shift;
133 0         0 my $val = shift;
134              
135 0 0       0 if ( $val == 1 ) {
    0          
136 0         0 $cmd->throw( OptArgs2::USAGE_HELP() );
137             }
138             elsif ( $val == 2 ) {
139 0         0 $cmd->throw( OptArgs2::USAGE_HELPTREE() );
140             }
141             else {
142 0         0 $cmd->throw( OptArgs2::USAGE_USAGE(), 'UnexpectedOptArg',
143             qq{"--$ref->{name}" used too many times} );
144             }
145 9   33     105 };
146             }
147              
148 14 50       52 if ( !exists $isa2getopt{ $ref->{isa} } ) {
149             return OptArgs2::croak( 'InvalidIsa', 'invalid isa "%s" for opt "%s"',
150 0         0 $ref->{isa}, $ref->{name} );
151             }
152              
153 14         39 $ref->{getopt} = $ref->{name};
154 14 50       47 if ( $ref->{name} =~ m/_/ ) {
155 0         0 ( my $x = $ref->{name} ) =~ s/_/-/g;
156 0         0 $ref->{getopt} .= '|' . $x;
157             }
158 14 100       52 $ref->{getopt} .= '|' . $ref->{alias} if $ref->{alias};
159 14         69 $ref->{getopt} .= $isa2getopt{ $ref->{isa} };
160              
161 14         94 return $proto->new(%$ref);
162             }
163              
164             sub name_alias_type_comment {
165 6     6 0 27 my $self = shift;
166 6         10 my $value = shift;
167              
168 6         17 ( my $opt = $self->name ) =~ s/_/-/g;
169 6 50       16 if ( $self->isa eq 'Bool' ) {
170 0 0       0 if ($value) {
    0          
171 0         0 $opt = 'no-' . $opt;
172             }
173             elsif ( not defined $value ) {
174 0         0 $opt = '[no-]' . $opt;
175             }
176             }
177 6         12 $opt = '--' . $opt;
178              
179 6   100     38 my $alias = $self->alias // '';
180 6 100       14 if ( length $alias ) {
181 5         8 $opt .= ',';
182 5         9 $alias = '-' . $alias;
183             }
184              
185 6         12 my $isa = $self->isa;
186 6         9 my $deftype = '';
187 6 100 33     83 if ( $isa ne 'Flag' and $isa ne 'Bool' and $isa ne 'Counter' ) {
      66        
188 1 50       5 $deftype = defined $value ? '[' . $value . ']' : $self->isa_name;
189             }
190              
191 6         26 my $comment = $self->comment;
192 6 50       17 if ( $self->required ) {
193 0 0       0 $comment .= ' ' if length $comment;
194 0         0 $comment .= '*required*';
195             }
196              
197 6         29 return $opt, $alias, $deftype, $comment;
198             }
199              
200             1;
201              
202             __END__