File Coverage

blib/lib/Data/Cleaner.pm
Criterion Covered Total %
statement 93 106 87.7
branch 16 26 61.5
condition 5 15 33.3
subroutine 25 34 73.5
pod 26 26 100.0
total 165 207 79.7


line stmt bran cond sub pod time code
1             package Data::Cleaner;
2              
3 2     2   82146 use 5.010000;
  2         7  
  2         82  
4 2     2   13 use strict;
  2         3  
  2         68  
5 2     2   12 use warnings;
  2         8  
  2         59  
6 2     2   3198 use Time::Local;
  2         5973  
  2         152  
7              
8 2     2   17 use constant ENCODING => 'UTF-8';
  2         5  
  2         118  
9 2     2   11 use constant DATE_FORMAT => '%d-%m-%Y';
  2         4  
  2         94  
10 2     2   10 use constant TIME_FORMAT => '%X %z';
  2         4  
  2         145  
11 2     2   12 use constant DATE_TIME_FORMAT => DATE_FORMAT.' '.TIME_FORMAT;
  2         5  
  2         2980  
12              
13             our $VERSION = 0.0.2;
14              
15             #
16             # Main methods
17             #
18              
19             sub new {
20              
21 12     12 1 6180 my ($class, %options) = @_;
22 12         27 my $self = {};
23 12         34 %{$self} = %options;
  12         34  
24              
25 12         42 my $typemodule = ucfirst(lc($self->{'type'}));
26 12         28 my $namespace = 'Data::Cleaner::'.$typemodule;
27 12         26 my $usemodule = 'Data/Cleaner/'.$typemodule.'.pm';
28 12         10519 require $usemodule;
29              
30 12 50       86 $self->{'encoding'} = ENCODING unless (defined $self->{'encoding'});
31 12 50       50 $self->{'dateFormat'} = DATE_FORMAT unless (defined $self->{'dateFormat'});
32 12 50       50 $self->{'timeFormat'} = TIME_FORMAT unless (defined $self->{'timeFormat'});
33 12 50       53 $self->{'dateTimeFormat'} = DATE_TIME_FORMAT unless (defined $self->{'dateTimeFormat'});
34 12 100       45 $self->{'enumOptions'} = [] unless (defined $self->{'enumOptions'});
35 12 50       37 unless (defined $self->{'tz'}) {
36 12         443 $self->{'tz'} = sprintf '%+05d', (100 * ((timegm(localtime) - timelocal(localtime)) / (3600)));
37             }
38              
39             #
40             # Each of the three main methods (validate, format and fix), is a
41             # reference to a subroutine in a datatype submodule. Each datatype
42             # module is a black box - they all have the same inputs and outputs.
43             #
44             # Submodules also have their own defaults which get loaded by the
45             # constructor (defaults can be overwritten using set_default).
46             #
47              
48 12         2021 eval('push @{$self->{\'_validate\'}}, \\\&'.$namespace.'::_validate');
49 12         671 eval('$self->{\'_fix\'} = \\\&'.$namespace.'::_fix');
50 12         664 eval('$self->{\'_format\'} = \\\&'.$namespace.'::_format');
51 12 100       65 unless (defined $self->{'default'}) {
52 11         539 eval('$self->{\'default\'} = $'.$namespace.'::DEFAULT');
53             }
54 12         40 $self->{'_ns'} = $namespace;
55              
56 12         28 bless $self, $class;
57 12         59 return $self;
58              
59             }
60              
61             sub load {
62              
63             #
64             # Loads an item of data into the object as 'raw' data without
65             # attempting validation. Useful if only fix and/or format will
66             # be used.
67             #
68            
69 0     0 1 0 my ($self, $value) = @_;
70 0         0 $self->{'_raw'} = $value;
71            
72             }
73              
74             sub validate {
75              
76             #
77             # A proxy for Data::Cleaner::::_validate
78             # Updates the '_pass', '_raw' and '_processTime' properties
79             #
80             # The '_validate' property is an array of subroutine references
81             # allowing the addition of further tests (with order preserved).
82             #
83            
84 28     28 1 303 my ($self, $value) = @_;
85 28 50 33     82 return undef unless (defined $value || defined $self->{'_raw'});
86              
87 28         49 my $start = time;
88            
89 28 50       87 $self->{'_raw'} = $value if (defined $value);
90 28         46 $self->{'_pass'} = undef;
91 28         38 $self->{'_processTime'} = undef;
92              
93 28         31 foreach my $test (@{$self->{'_validate'}}) {
  28         63  
94              
95 30         43 my $out = ${$test}->($self, $self->{'_raw'});
  30         86  
96            
97 30 100       1754 if (defined $out) {
98 15         26 $self->{'_pass'} = 1;
99 15         46 $self->{'_raw'} = $out;
100             } else {
101 15         22 $self->{'_pass'} = 0;
102 15   33     35 $self->{'_raw'} = $value || $self->{'_raw'};
103 15         30 last;
104             }
105            
106             }
107              
108 28         50 $self->{'_processTime'} = time - $start;
109 28         74 return $self->{'_pass'};
110              
111             }
112              
113             sub reset {
114              
115             #
116             # Definitive method of flushing previous data from the
117             # object before reuse (not usually required, since the validate
118             # function does the same thing whenever data is loaded as an
119             # argument)
120             #
121            
122 0     0 1 0 my $self = $_[0];
123 0         0 $self->{'_raw'} = undef;
124 0         0 $self->{'_pass'} = undef;
125 0         0 $self->{'_processTime'} = undef;
126              
127             }
128              
129             sub format {
130              
131             #
132             # A proxy for Data::Cleaner::::_format
133             # Updates the '_raw' and '_processTime' properties
134             #
135            
136 12     12 1 39 my $self = $_[0];
137 12         16 my $start = time;
138 12         17 $self->{'_raw'} = ${$self->{'_format'}}->($self, $self->{'_raw'});
  12         32  
139 12         329 $self->{'_processTime'} = time - $start;
140 12         34 return $self->{'_raw'};
141              
142             }
143              
144             sub fix {
145              
146             #
147             # A proxy for Data::Cleaner::::_fix
148             # Updates the '_raw' and '_processTime' properties
149             #
150            
151 13     13 1 58 my $self = $_[0];
152 13         19 my $start = time;
153 13         21 $self->{'_raw'} = ${$self->{'_fix'}}->($self, $self->{'_raw'});
  13         42  
154 13         52 $self->{'_processTime'} = time - $start;
155            
156             }
157              
158             sub add_test {
159              
160             #
161             # Appends a test subroutine reference to $self->{'_validate'}
162             #
163              
164 1 50 33 1 1 196 if (ref($_[1]) && ref($_[1]) eq 'REF') {
165 1         1 push @{$_[0]->{'_validate'}}, $_[1];
  1         3  
166             }
167              
168             }
169              
170             sub set_format {
171              
172             #
173             # Replaces the default format subroutine reference in
174             # $self->{'_format'}
175             #
176            
177 1 50 33 1 1 229 if (ref($_[1]) && ref($_[1]) eq 'REF') {
178 1         3 $_[0]->{'_format'} = $_[1];
179             }
180            
181             }
182              
183             sub set_fix {
184              
185             #
186             # Replaces the default fix subroutine reference in
187             # $self->{'_fix'}
188             #
189            
190 1 50 33 1 1 237 if (ref($_[1]) && ref($_[1]) eq 'REF') {
191 1         3 $_[0]->{'_fix'} = $_[1];
192             }
193            
194             }
195              
196             #
197             # Helper methods - get property value
198             #
199              
200             sub is_valid {
201              
202             #
203             # Reports whether or not the input data passed [all stages of] validation
204             #
205            
206 23     23 1 109 return $_[0]->{'_pass'};
207            
208             }
209              
210             sub get_raw {
211              
212             #
213             # Returns the data item in raw (pre-processed) form
214             #
215            
216 15     15 1 135 return $_[0]->{'_raw'};
217            
218             }
219              
220             sub get_default {
221              
222             #
223             # Returns the default value for the type
224             #
225            
226 8     8 1 31 return $_[0]->{'default'};
227            
228             }
229              
230             sub get_type {
231              
232             #
233             # Returns the type setting for the object
234             #
235            
236 1     1 1 14 return $_[0]->{'type'};
237              
238             }
239              
240             sub get_encoding {
241              
242             #
243             # Returns the encoding the module expects all input data to be encoded in
244             #
245            
246 2     2 1 10 return $_[0]->{'encoding'};
247            
248             }
249              
250             sub get_timezone {
251              
252             #
253             # Returns the timezone +/-nnnn
254             # By default this is calculated by the constructor as the difference
255             # between GMT (UTC) and localtime. Can be overridden
256             #
257            
258 1     1 1 6 return $_[0]->{'tz'};
259            
260             }
261              
262             sub get_datetime_format {
263              
264             #
265             # Returns the datetime formatting (uses time2str convention)
266             #
267            
268 1     1 1 7 return $_[0]->{'dateTimeFormat'};
269            
270             }
271              
272             sub get_date_format {
273              
274             #
275             # Returns the date formatting (uses time2str convention)
276             #
277            
278 0     0 1 0 return $_[0]->{'dateFormat'};
279            
280             }
281              
282             sub get_time_format {
283              
284             #
285             # Returns the time format (uses time2str convention)
286             #
287            
288 0     0 1 0 return $_[0]->{'timeFormat'};
289            
290             }
291              
292             sub get_enum_options {
293              
294             #
295             # Returns the defined enum options in an array
296             #
297            
298 9     9 1 235 return $_[0]->{'enumOptions'};
299            
300             }
301              
302             #
303             # Helper methods - set property value
304             #
305              
306             sub set_default {
307              
308             #
309             # Sets a new default value for the type
310             #
311            
312 1     1 1 17 $_[0]->{'default'} = $_[1];
313            
314             }
315              
316             sub set_encoding {
317              
318             #
319             # Sets the encoding to be used for processing all text input
320             #
321            
322 0     0 1 0 $_[0]->{'encoding'} = $_[1];
323            
324             }
325              
326             sub set_timezone {
327              
328             #
329             # Sets a timezone to override the default for formatting of date and time values
330             # Can be +/-nnnn or a 3-letter code
331             #
332            
333 0     0 1 0 $_[0]->{'tz'} = $_[1];
334            
335             }
336              
337             sub set_datetime_format {
338              
339             #
340             # Set datetime formatting (uses time2str convention)
341             #
342            
343 0     0 1 0 $_[0]->{'dateTimeFormat'} = $_[1];
344            
345             }
346              
347             sub set_date_format {
348              
349             #
350             # Set date formatting (uses time2str convention)
351             #
352            
353 0     0 1 0 $_[0]->{'dateFormat'} = $_[1];
354            
355             }
356              
357             sub set_time_format {
358              
359             #
360             # Set time formatting (uses time2str convention)
361             #
362            
363 0     0 1 0 $_[0]->{'timeFormat'} = $_[1];
364            
365             }
366              
367             sub set_enum_options {
368              
369             #
370             # Sets the defined enum options
371             #
372            
373 1     1 1 203 $_[0]->{'enumOptions'} = $_[1];
374            
375             }
376              
377             1;
378              
379             __END__