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   76349 use version; our $VERSION = version->declare("2.1.3");
  1         1953  
  1         6  
3              
4 1     1   99 use v5.14;
  1         6  
5 1     1   5 use warnings;
  1         2  
  1         23  
6              
7 1     1   5 use Carp;
  1         2  
  1         68  
8 1     1   6 use List::Util qw();
  1         2  
  1         31  
9 1     1   572 use Hash::Util qw(lock_keys);
  1         2759  
  1         6  
10 1     1   86 use Data::Dumper;
  1         2  
  1         52  
11             $Data::Dumper::Sortkeys = 1;
12              
13 1     1   5 use Exporter qw(import);
  1         2  
  1         274  
14             our @EXPORT_OK = qw();
15              
16             sub _default {
17             return {
18 6     6   31 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 1155 my $class = shift;
30 6         15 my $obj = bless _default(), $class;
31 6         10 lock_keys %{$obj};
  6         26  
32 6 50       84 @_ % 2 and croak "invalid number of parameters";
33 6         34 while (my($key, $value) = splice(@_, 0, 2)) {
34 15 50       30 croak "$key: invalid parameter" if not exists $obj->{$key};
35 15         40 $obj->{$key} = $value;
36             }
37 6         24 $obj;
38             }
39              
40             sub parse {
41 31     31 1 20141 my $obj = shift;
42 31         85 local $_ = shift;
43 31 50       222 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   451 $obj->{start} = $+{start};
  1         367  
  1         544  
  31         198  
58 31         127 $obj->{end} = $+{end};
59 31         108 $obj->{step} = $+{step};
60 31         99 $obj->{length} = $+{length};
61             }
62             else {
63 0         0 carp "$_: format error";
64 0         0 return undef;
65             }
66 31         61 $obj->{_spec} = $_;
67 31         94 $obj;
68             }
69              
70             sub range {
71 32     32 1 39 my $obj = shift;
72 32         45 my $max = $obj->{max};
73 32         49 my $min = $obj->{min};
74              
75 32         39 my $start = $obj->{start};
76 32         55 my $end = $obj->{end};
77 32         38 my $step = $obj->{step};
78 32         46 my $length = $obj->{length};
79              
80 32 100       79 if (not defined $max) {
81 2 50 33     15 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     150 if ($start =~ /\d/ and defined $max and $start > $max) {
      66        
89 0         0 return ();
90             }
91 32 100       80 if ($start eq '') {
    100          
92 17         26 $start = $min;
93             }
94             elsif ($start =~ /^-\d+$/) {
95 2         9 $start = List::Util::max($min, $start + $max);
96             }
97              
98 32 100       106 if (not defined $end) {
    100          
    100          
    100          
99 3         5 $end = $start;
100             }
101             elsif ($end eq '') {
102 7 50       16 $end = defined $max ? $max : $start;
103             }
104             elsif ($end =~ /^-/) {
105 2         11 $end = List::Util::max(0, $end + $max);
106             }
107             elsif ($end =~ s/^\+//) {
108 1         4 $end += $start;
109             }
110 32 100 100     115 $end = $max if defined $max and $end > $max;
111              
112 32   100     96 $length ||= 1;
113 32   66     90 $step ||= $length;
114              
115 32         47 my @l;
116 32 100       58 if ($step == 1) {
117 15         39 @l = ( [$start, $end] );
118             } else {
119 17         42 for (my $from = $start; $from <= $end; $from += $step) {
120 75         107 my $to = $from + $length - 1;
121 75 100       147 $to = List::Util::min($max, $to) if defined $max;
122 75         176 push @l, [$from, $to];
123             }
124             }
125              
126 32         101 return @l;
127             }
128              
129             sub sequence {
130 17     17 1 32 my $obj = shift;
131 17 50       33 map { ref $_ eq 'ARRAY' ? ($_->[0] .. $_->[1]) : $_ } $obj->range;
  57         181  
132             }
133              
134             1;
135              
136             __END__