File Coverage

blib/lib/Getopt/EX/Numbers.pm
Criterion Covered Total %
statement 77 82 93.9
branch 27 34 79.4
condition 14 20 70.0
subroutine 14 14 100.0
pod 4 4 100.0
total 136 154 88.3


line stmt bran cond sub pod time code
1             package Getopt::EX::Numbers;
2 1     1   80246 use version; our $VERSION = version->declare("2.1.2");
  1         2169  
  1         6  
3              
4 1     1   115 use v5.14;
  1         7  
5 1     1   6 use warnings;
  1         1  
  1         31  
6              
7 1     1   5 use Carp;
  1         2  
  1         95  
8 1     1   8 use List::Util qw();
  1         2  
  1         34  
9 1     1   658 use Hash::Util qw(lock_keys);
  1         4094  
  1         11  
10 1     1   100 use Data::Dumper;
  1         3  
  1         54  
11             $Data::Dumper::Sortkeys = 1;
12              
13 1     1   8 use Exporter qw(import);
  1         2  
  1         311  
14             our @EXPORT_OK = qw();
15              
16             sub _default {
17             return {
18 6     6   36 min => 0,
19             max => undef,
20             start => '',
21             end => '',
22             step => '',
23             length => '',
24             _spec => undef,
25             };
26             }
27              
28             sub new {
29 6     6 1 1140 my $class = shift;
30 6         19 my $obj = bless _default(), $class;
31 6         11 lock_keys %{$obj};
  6         28  
32 6 50       95 @_ % 2 and croak "invalid number of parameters";
33 6         37 while (my($key, $value) = splice(@_, 0, 2)) {
34 15 50       30 croak "$key: invalid parameter" if not exists $obj->{$key};
35 15         42 $obj->{$key} = $value;
36             }
37 6         23 $obj;
38             }
39              
40             sub parse {
41 31     31 1 19775 my $obj = shift;
42 31         58 local $_ = shift;
43 31 50       236 if (m{
44             ^
45             (? -\d+ | \d* )
46             (?:
47             (?: \.\. | : ) (? [-+]\d+ | \d* )
48             (?:
49             : (? \d* )
50             (?:
51             : (? \d* )
52             )?
53             )?
54             )?
55             $
56             }x) {
57 1     1   516 $obj->{start} = $+{start};
  1         397  
  1         675  
  31         197  
58 31         126 $obj->{end} = $+{end};
59 31         103 $obj->{step} = $+{step};
60 31         94 $obj->{length} = $+{length};
61             }
62             else {
63 0         0 carp "$_: format error";
64 0         0 return undef;
65             }
66 31         62 $obj->{_spec} = $_;
67 31         116 $obj;
68             }
69              
70             sub range {
71 32     32 1 44 my $obj = shift;
72 32         51 my $max = $obj->{max};
73 32         43 my $min = $obj->{min};
74              
75 32         50 my $start = $obj->{start};
76 32         52 my $end = $obj->{end};
77 32         50 my $step = $obj->{step};
78 32         42 my $length = $obj->{length};
79              
80 32 100       76 if (not defined $max) {
81 2 50 33     37 if ($start =~ /^-\d+$/ or
      33        
82             (defined $end and $end =~ /^-\d+$/)) {
83 0         0 carp "$_: max required";
84 0         0 return ();
85             }
86             }
87              
88 32 50 100     152 if ($start =~ /\d/ and defined $max and $start > $max) {
      66        
89 0         0 return ();
90             }
91 32 100       84 if ($start eq '') {
    100          
92 17         24 $start = $min;
93             }
94             elsif ($start =~ /^-\d+$/) {
95 2         9 $start = List::Util::max($min, $start + $max);
96             }
97              
98 32 100       116 if (not defined $end) {
    100          
    100          
    100          
99 3         6 $end = $start;
100             }
101             elsif ($end eq '') {
102 7 50       15 $end = defined $max ? $max : $start;
103             }
104             elsif ($end =~ /^-/) {
105 2         7 $end = List::Util::max(0, $end + $max);
106             }
107             elsif ($end =~ s/^\+//) {
108 1         3 $end += $start;
109             }
110 32 100 100     120 $end = $max if defined $max and $end > $max;
111              
112 32   100     92 $length ||= 1;
113 32   66     88 $step ||= $length;
114              
115 32         58 my @l;
116 32 100       65 if ($step == 1) {
117 15         41 @l = ( [$start, $end] );
118             } else {
119 17         41 for (my $from = $start; $from <= $end; $from += $step) {
120 75         102 my $to = $from + $length - 1;
121 75 100       149 $to = List::Util::min($max, $to) if defined $max;
122 75         181 push @l, [$from, $to];
123             }
124             }
125              
126 32         98 return @l;
127             }
128              
129             sub sequence {
130 17     17 1 27 my $obj = shift;
131 17 50       33 map { ref $_ eq 'ARRAY' ? ($_->[0] .. $_->[1]) : $_ } $obj->range;
  57         193  
132             }
133              
134             1;
135              
136             __END__