File Coverage

blib/lib/Astro/App/Satpass2/ParseTime.pm
Criterion Covered Total %
statement 97 128 75.7
branch 32 64 50.0
condition 3 8 37.5
subroutine 15 21 71.4
pod 11 11 100.0
total 158 232 68.1


line stmt bran cond sub pod time code
1             package Astro::App::Satpass2::ParseTime;
2              
3 20     20   1553 use 5.008;
  20         84  
4              
5 20     20   127 use strict;
  20         42  
  20         467  
6 20     20   116 use warnings;
  20         41  
  20         618  
7              
8 20     20   108 use parent qw{ Astro::App::Satpass2::Copier };
  20         35  
  20         100  
9              
10 20     20   9569 use Astro::App::Satpass2::FormatTime;
  20         63  
  20         641  
11 20         2189 use Astro::App::Satpass2::Utils qw{
12             load_package
13             ARRAY_REF CODE_REF SCALAR_REF
14             @CARP_NOT
15 20     20   128 };
  20         69  
16 20     20   11742 use Astro::Coord::ECI::Utils 0.059 qw{ looks_like_number };
  20         205114  
  20         12522  
17              
18             our $VERSION = '0.051_01';
19              
20             my %static = (
21             perltime => 0,
22             );
23              
24             sub new {
25 15     15 1 2166 my ( $class, %args ) = @_;
26 15 50       59 ref $class and $class = ref $class;
27              
28             # Workaround for bug (well, _I_ think it's a bug) introduced into
29             # Date::Manip with 6.34, while fixing RT #78566. My bug report is RT
30             # #80435.
31 15         63 my $path = $ENV{PATH};
32 15         104 local $ENV{PATH} = $path;
33              
34 15 50       62 if ( __PACKAGE__ eq $class ) {
35              
36 15   100     89 $args{class} ||= [ qw{ Date::Manip ISO8601 } ];
37              
38 8         33 my @classes = ARRAY_REF eq ref $args{class} ? @{ $args{class} } :
39 15 100       121 split qr{ \s* , \s* }smx, $args{class};
40              
41 15 50       73 $class = _try ( @classes )
42             or return;
43              
44             } else {
45 0 0       0 $class = _try( $class )
46             or return;
47             }
48 15         57 delete $args{class};
49              
50             defined $args{base}
51 15 50       75 or $args{base} = time;
52              
53 15         66 my $self = { %static };
54 15         44 bless $self, $class;
55 15         157 $self->warner( delete $args{warner} );
56 15         122 $self->base( delete $args{base} );
57 15         88 $self->init( %args );
58 15         121 return $self;
59             }
60              
61             sub attribute_names {
62 35     35 1 111 my ( $self ) = @_;
63 35         186 return ( $self->SUPER::attribute_names(), qw{
64             base perltime tz } );
65             }
66              
67             sub base {
68 440     440 1 909 my ( $self, @args ) = @_;
69 440 100       1094 if ( @args > 0 ) {
70 125         276 $self->{base} = $self->{absolute} = $args[0];
71 125         251 return $self;
72             }
73 315         803 return $self->{base};
74             }
75              
76             sub class_name_of_record {
77 0     0 1 0 my ( $self ) = @_;
78 0         0 my $rslt = substr $self->__class_name(), 2 + length __PACKAGE__;
79 0         0 foreach my $attr ( qw{ tz } ) {
80 0 0       0 my $value = $self->$attr()
81             or next;
82 0         0 $rslt .= ",$attr=$value";
83             }
84 0         0 return $rslt;
85             }
86              
87             # For the use of class_name_of_record(). It exists so that
88             # Astro::App::Satpass2::ParseTime::Date::Manip can override it, so that
89             # we do not get the trailing '::v5' or '::v6';
90             sub __class_name {
91 0     0   0 my ( $self ) = @_;
92 0         0 return ref $self;
93             }
94              
95             {
96              
97             my %skip = map { $_ => 1 } qw{ base warner };
98              
99             sub config {
100 0     0 1 0 my ( $self, %args ) = @_;
101 0         0 my @data;
102              
103 0         0 foreach my $name ( $self->attribute_names() ) {
104 0 0       0 $skip{$name} and next;
105 0         0 my $val = $self->$name();
106 20     20   196 no warnings qw{ uninitialized };
  20         57  
  20         23694  
107 0 0 0     0 next if $args{changes} && $val eq $static{$name};
108 0 0       0 push @data, [ $name, $args{decode} ? $self->decode( $name )
109             : $val ];
110             }
111              
112 0 0       0 return wantarray ? @data : \@data;
113             }
114              
115             }
116              
117             sub delegate { ## no critic (RequireFinalReturn)
118 0     0 1 0 my ( $self ) = @_;
119 0         0 $self->weep( 'The delegate() method must be overridden' );
120             # Weep throws an exception, but there is no way to tell perlcritic
121             # this.
122             }
123              
124             {
125              
126             my %decoder = (
127             base => sub {
128             my ( $self, $method, @args ) = @_;
129             my $rslt = $self->$method( @args );
130             @args
131             and return $rslt;
132             $rslt
133             or return $rslt;
134             $self->{_time_formatter} ||=
135             Astro::App::Satpass2::FormatTime->new();
136             return $self->{_time_formatter}->format_datetime(
137             $self->{_time_formatter}->ISO_8601_FORMAT(),
138             $rslt, 1 );
139             },
140             );
141              
142             sub decode {
143 0     0 1 0 my ( $self, $method, @args ) = @_;
144 0 0       0 my $dcdr = $decoder{$method}
145             or return $self->$method( @args );
146 0 0       0 my $type = ref $dcdr
147             or $self->weep( "Decoder for $method is scalar" );
148 0 0       0 CODE_REF eq $type
149             or $self->weep(
150             "Decoder for $method is $type reference" );
151 0         0 return $dcdr->( $self, $method, @args );
152             }
153             }
154              
155             {
156              
157             my @scale = ( 24, 60, 60, 1 );
158              
159             sub parse {
160 147     147 1 366 my ( $self, $string, $default ) = @_;
161              
162 147 100       487 if ( SCALAR_REF eq ref $string ) {
163 1         5 my $time = ${ $string };
  1         3  
164 1         6 $self->base( $self->{absolute} = $time );
165 1         3 return $time;
166             }
167              
168 146 50 33     713 if ( ! defined $string || '' eq $string ) {
169             defined $default
170 0 0       0 and $self->base( $self->{absolute} = $default );
171 0         0 return $default;
172             }
173              
174 146 100       875 if ( $string =~ m/ \A \s* [+-] /smx ) {
    100          
175 39 50       204 defined $self->{base} or return;
176             defined $self->{absolute}
177 39 50       152 or $self->{absolute} = $self->base();
178 39         125 $string =~ s/ \A \s+ //smx;
179 39         119 $string =~ s/ \s+ \z //smx;
180 39         105 my $sign = substr $string, 0, 1;
181 39         118 substr( $string, 0, 1, '' );
182 39         356 my @delta = split qr{ \s* : \s* | \s+ }smx, $string;
183 39 50       184 @delta > 4 and return;
184 39         130 push @delta, ( 0 ) x ( 4 - @delta );
185 39         86 my $dt = 0;
186 39         119 foreach my $inx ( 0 .. 3 ) {
187 156 50       456 looks_like_number( $delta[$inx] ) or return;
188 156         269 $dt += $delta[$inx];
189 156         344 $dt *= $scale[$inx];
190             }
191 39 100       180 '-' eq $sign and $dt = - $dt;
192 39         201 return ( $self->{absolute} = $dt + $self->{absolute} );
193              
194             } elsif ( $string =~
195             m/ \A epoch \s* ( [0-9]+ (?: [.] [0-9]* )? ) \z /smx ) {
196              
197 1         5 my $time = $1 + 0;
198 1         7 $self->base( $self->{absolute} = $time );
199 1         4 return $time;
200              
201             } else {
202              
203 106 50       441 defined( my $time = $self->parse_time_absolute( $string ) )
204             or return;
205 106         6439 $self->base( $self->{absolute} = $time );
206 106         368 return $time;
207              
208             }
209              
210             }
211              
212             }
213              
214             sub parse_time_absolute { ## no critic (RequireFinalReturn)
215             ## my ( $self, $string ) = @_;
216 0     0 1 0 my ( $self ) = @_; # $string unused
217 0         0 $self->weep(
218             'parse_time_absolute() must be overridden' );
219             # Weep throws an exception, but there is no way to tell perlcritic
220             # this.
221             }
222              
223             sub reset : method { ## no critic (ProhibitBuiltinHomonyms)
224 315     315 1 599 my ( $self ) = @_;
225 315         834 $self->{absolute} = $self->base();
226 315         670 return $self;
227             }
228              
229             sub use_perltime {
230 1     1 1 5 return 0;
231             }
232              
233             {
234              
235             # %trial is indexed by class name. The value is the class to
236             # delegate to (which can be the same as the class itself), or undef
237             # if the class can not be loaded, or has no delegate.
238              
239             my %trial;
240              
241             sub _try {
242 15     15   88 my ( @args ) = @_;
243              
244 15         33 my @flatten;
245              
246 15         63 while ( @args ) {
247              
248 31         74 my $try = shift @args;
249              
250 31 100       108 $trial{$try} and return $trial{$try};
251              
252 27 100       90 exists $trial{$try} and next;
253              
254 25 50       185 $try =~ m/ \A \w+ (?: :: \w+ )* \z /smx or do {
255 0         0 $trial{$try} = undef;
256 0         0 next;
257             };
258              
259 25 50       99 my $pkg = $trial{$try} = load_package(
260             $try, 'Astro::App::Satpass2::ParseTime' )
261             or next;
262              
263 25 100       58 my $delegate = $trial{$try} = eval { $pkg->delegate() }
  25         194  
264             or next;
265              
266 17 100       72 if ( $trial{$delegate} ) {
267 11         41 foreach ( @flatten ) {
268 6         19 $trial{$_} = $delegate;
269             }
270 11         62 return $delegate;
271             }
272              
273 6         20 push @flatten, $try;
274 6         36 unshift @args, $delegate;
275             }
276              
277 0           return;
278             }
279             }
280              
281             __PACKAGE__->create_attribute_methods();
282              
283             1;
284              
285             __END__