File Coverage

lib/Date/Holidays/Adapter.pm
Criterion Covered Total %
statement 45 108 41.6
branch 4 40 10.0
condition 3 18 16.6
subroutine 12 15 80.0
pod 3 3 100.0
total 67 184 36.4


line stmt bran cond sub pod time code
1              
2             use strict;
3 1     1   8 use warnings;
  1         3  
  1         27  
4 1     1   14 use Carp; # croak
  1         1  
  1         22  
5 1     1   4 use Try::Tiny;
  1         1  
  1         43  
6 1     1   6 use Module::Load qw(load);
  1         8  
  1         39  
7 1     1   5 use Locale::Country;
  1         2  
  1         6  
8 1     1   71 use Scalar::Util qw(blessed);
  1         2  
  1         64  
9 1     1   5  
  1         1  
  1         48  
10             use vars qw($VERSION);
11 1     1   6  
  1         1  
  1         980  
12             $VERSION = '1.34';
13              
14             my ($class, %params) = @_;
15              
16 2     2 1 6 my $self = bless {
17             _countrycode => $params{countrycode},
18             _adaptee => undef,
19             }, $class || ref $class;
20 2   33     8  
21             my $adaptee = $self->_fetch(\%params);
22              
23 2         8 if ($adaptee) {
24             $self->{_adaptee} = $adaptee;
25 2 50       5 } else {
26 2         3 die 'Unable to initialize adaptee class';
27             }
28 0         0  
29             return $self;
30             }
31 2         6  
32             my ($self, %params) = @_;
33              
34             my $r;
35 0     0 1 0 my $adaptee;
36              
37 0         0 # Adaptee has a constructor
38             if ( $self->{_adaptee}->can('new')
39             and $self->isa('Date::Holidays::Adapter')) {
40              
41 0 0 0     0 $adaptee = $self->{_adaptee}->new();
42              
43             # Adaptee has no constructor
44 0         0 } else {
45             $adaptee = $self->{'_adaptee'};
46             }
47              
48 0         0 if (blessed $adaptee) {
49              
50             # Adapting non-polymorphic interface
51 0 0       0 my $method = "$self->{'_countrycode'}_holidays";
52             my $sub = $adaptee->can($method);
53              
54 0         0 # Adapting polymorphic interface
55 0         0 if (! $sub) {
56             $method = 'holidays';
57             $sub = $adaptee->can($method);
58 0 0       0 }
59 0         0  
60 0         0 if ($sub) {
61             $r = $adaptee->$method($params{'year'});
62             }
63 0 0       0  
64 0         0 return $r;
65              
66             } else {
67 0         0  
68             # Adapting non-polymorphic interface
69             my $method = "$self->{'_countrycode'}_holidays";
70             my $sub = $adaptee->can($method);
71              
72 0         0 # Adapting polymorphic interface
73 0         0 if (! $sub) {
74             $sub = $adaptee->can('holidays');
75             }
76 0 0       0  
77 0         0 if ($sub) {
78             $r = &{$sub}($params{'year'});
79             }
80 0 0       0  
81 0         0 return $r;
  0         0  
82             }
83             }
84 0         0  
85             my ($self, %params) = @_;
86              
87             my $r;
88             my $adaptee;
89 0     0 1 0  
90             if ( $self->{'_adaptee'}->can('new')
91 0         0 and $self->isa('Date::Holidays::Adapter')) {
92              
93             $adaptee = $self->{'_adaptee'}->new();
94 0 0 0     0  
95             } else {
96             $adaptee = $self->{'_adaptee'};
97 0         0 }
98              
99             if (blessed $adaptee) {
100 0         0  
101             # Adapting non-polymorphic interface
102             my $method = "is_$self->{'_countrycode'}_holiday";
103 0 0       0  
104             if ($adaptee->can($method)) {
105              
106 0         0 $r = $adaptee->$method(
107             $params{'year'},
108 0 0       0 $params{'month'},
109             $params{'day'}
110             );
111              
112             return $r;
113 0         0  
114             # Adapting polymorphic interface
115             } else {
116 0         0  
117             if ($adaptee->can('is_holiday')) {
118             $r = $adaptee->is_holiday(
119             $params{'year'},
120             $params{'month'},
121 0 0       0 $params{'day'}
122             );
123             }
124              
125 0         0 return $r;
126             }
127              
128             } else {
129 0         0 # Adapting non-polymorphic interface
130             my $method = "is_$self->{_countrycode}_holiday";
131             my $sub = $adaptee->can($method);
132              
133             # We have an interface
134 0         0 if ($sub) {
135 0         0  
136             $r = &{$sub}(
137             $params{'year'},
138 0 0       0 $params{'month'},
139             $params{'day'}
140 0         0 );
141              
142             return $r;
143 0         0 }
144              
145             # Adapting polymorphic interface
146 0         0 $sub = $adaptee->can('is_holiday');
147              
148             if ($sub) {
149             $r = &{$sub}(
150 0         0 $params{'year'},
151             $params{'month'},
152 0 0       0 $params{'day'}
153 0         0 );
154              
155             return $r;
156 0         0 }
157             }
158              
159 0         0 return $r;
160             }
161              
162             my ( $self, $module ) = @_;
163 0         0  
164             # Trying to load module
165             eval { load $module; }; # From Module::Load
166              
167 5     5   10 # Asserting success of load
168             if ($@) {
169             die "Unable to load: $module - $@\n";
170 5         6 }
  5         12  
171              
172             # Returning name of loaded module upon success
173 5 50       2142 return $module;
174 0         0 }
175              
176             my ( $self, $params ) = @_;
177              
178 5         14 # Do we have a country code?
179             if ( not $self->{'_countrycode'} and not $params->{countrycode} ) {
180             croak 'No country code specified';
181             }
182 2     2   4  
183             my $countrycode = $params->{countrycode} || $self->{'_countrycode'};
184              
185 2 0 33     11 # Do we do country code assertion?
186 0         0 if ( !$params->{'nocheck'} ) {
187              
188             # Is our country code valid or local?
189 2   33     5 if ( $countrycode !~ m/local/i and !code2country( $countrycode ) ) { #from Locale::Country
190             die "$countrycode is not a valid country code";
191             }
192 2 50       3 }
193              
194             # Trying to load adapter module for country code
195 0 0 0     0 my $module;
196 0         0  
197             try {
198             # We load an adapter implementation
199             if ( code2country( $countrycode ) ) {
200             $module = 'Date::Holidays::' . uc $countrycode;
201 2         4 } else {
202             $module = 'Date::Holidays::' . $countrycode;
203             }
204              
205 2 50   2   63 $module = $self->_load($module);
206 0         0  
207             } catch {
208 2         61 warn "Unable to load module: $module - $_";
209              
210             try {
211 2         7 #$countrycode = uc $countrycode;
212              
213             if ($countrycode =~ m/local/i) {
214 0     0   0 $module = 'Date::Holidays::Local';
215             } else {
216             $module = 'Date::Holidays::' . $countrycode;
217             }
218              
219 0 0       0 # We load an adapter implementation
220 0         0  
221             if ($module = $self->_load($module)) {
222 0         0 warn "we got a module and we return\n";
223             }
224              
225             } catch {
226             warn "Unable to load module: $module - $_";
227 0 0       0  
228 0         0 $module = 'Date::Holidays::Adapter';
229             $module = $self->_load($module);
230             };
231             };
232 0         0  
233             # Returning name of loaded module upon success
234 0         0 return $module;
235 0         0 }
236 0         0  
237 2         8 1;
238              
239              
240 2         26 =pod
241              
242             =encoding UTF-8
243              
244             =head1 NAME
245              
246             Date::Holidays::Adapter - an adapter class for Date::Holidays::* modules
247              
248             =head1 VERSION
249              
250             This POD describes version 1.34 of Date::Holidays::Adapter
251              
252             =head1 SYNOPSIS
253              
254             my $adapter = Date::Holidays::Adapter->new(countrycode => 'NO');
255              
256             my ($year, $month, $day) = (localtime)[ 5, 4, 3 ];
257             $year += 1900;
258             $month += 1;
259              
260             print "Woohoo" if $adapter->is_holiday( year => $year, month => $month, day => $day );
261              
262             my $hashref = $adapter->holidays(year => $year);
263             printf "Dec. 24th is named '%s'\n", $hashref->{'1224'}; #christmas I hope
264              
265             =head1 DESCRIPTION
266              
267             The is the SUPER adapter class. All of the adapters in the distribution of
268             Date::Holidays are subclasses of this class. (SEE also L<Date::Holidays>).
269              
270             The SUPER adapter class is at the same time a generic adapter. It attempts to
271             adapt to the most used API for modules in the Date::Holidays::* namespace. So
272             it should only be necessary to implement adapters to the exceptions to modules
273             not following the the defacto standard or suffering from other local
274             implementations.
275              
276             =head1 SUBROUTINES/METHODS
277              
278             The public methods in this class are all expected from the adapter, so it
279             actually corresponds with the abstract is outlined in L<Date::Holidays::Abstract>.
280              
281             Not all methods/subroutines may be implemented in the adaptee classes, the
282             adapters attempt to make the adaptee APIs adaptable where possible. This is
283             afterall the whole idea of the Adapter Pattern, but apart from making the
284             single Date::Holidays::* modules uniform towards the clients and
285             L<Date::Holidays> it is attempted to make the multitude of modules uniform in
286             the extent possible.
287              
288             =head2 new
289              
290             The constructor, takes a single named argument, B<countrycode>
291              
292             =head2 is_holiday
293              
294             The B<holidays> method, takes 3 named arguments, B<year>, B<month> and B<day>
295              
296             returns an indication of whether the day is a holiday in the calendar of the
297             country referenced by B<countrycode> in the call to the constructor B<new>.
298              
299             =head2 holidays
300              
301             The B<holidays> method, takes a single named argument, B<year>
302              
303             returns a reference to a hash holding the calendar of the country referenced by
304             B<countrycode> in the call to the constructor B<new>.
305              
306             The calendar will spand for a year and the keys consist of B<month> and B<day>
307             concatenated.
308              
309             =head1 DEVELOPING A DATE::HOLIDAYS::* ADAPTER
310              
311             If you want to develop an adapter compatible with interface specified in this
312             class. You have to implement the following 3 methods:
313              
314             =over
315              
316             =item new
317              
318             A constructor, taking a single argument a two-letter countrycode
319             (SEE: L<Locale::Country>)
320              
321             You can also inherit the one implemented and offered by this class
322              
323             B<NB>If inheritance is used, please remember to overwrite the two following
324             methods, if applicable.
325              
326             =item holidays
327              
328             This has to follow the API outlined in SUBROUTINES/METHODS.
329              
330             For the adaptee class anything goes, hence the use of an adapter.
331              
332             Please refer to the DEVELOPER section in L<Date::Holidays> about contributing to
333             the Date::Holidays::* namespace or attempting for adaptability with
334             L<Date::Holidays>.
335              
336             =item is_holiday
337              
338             This has to follow the API outlined in SUBROUTINES/METHODS.
339              
340             For the adaptee class anything goes, hence the use of an adapter.
341              
342             Please refer to the DEVELOPER section in L<Date::Holidays> about contributing to
343             the Date::Holidays::* namespace or attempting for adaptability with
344             L<Date::Holidays>.
345              
346             =back
347              
348             Apart from the methods described above you can also overwrite the _fetch method
349             in this class, This is used if your module is not a part of the
350             Date::Holidays::* namespace or the module bears a name which is not ISO3166
351             compliant.
352              
353             See also:
354              
355             =over
356              
357             =item * L<Date::Holidays::UK>
358              
359             =item * L<Date::Japanese::Holiday>
360              
361             =back
362              
363             =head1 DIAGNOSTICS
364              
365             =over
366              
367             =item * L<Date::Holidays::Exception::AdapterLoad>
368              
369             Exception thrown in the case where the B<_load> method is unable to load a
370             requested adapter module.
371              
372             The exception is however handled internally.
373              
374             =item * L<Date::Holidays::Exception::AdapterInitialization>
375              
376             Exception thrown in the case where the B<_new> method is unable to
377             initialize a requested adapter module.
378              
379             =item * L<Date::Holidays::Exception::UnsupportedMethod>
380              
381             Exception thrown in the case where the loaded and initialized module does not
382             support the called method. (SEE: METHODS/SUBROUTINES).
383              
384             =back
385              
386             =head1 DEPENDENCIES
387              
388             =over
389              
390             =item * L<Carp>
391              
392             =item * L<Module::Load>
393              
394             =item * L<TryCatch>
395              
396             =item * L<Locale::Country>
397              
398             =item * L<Scalar::Util>
399              
400             =back
401              
402             =head1 INCOMPATIBILITIES
403              
404             Please refer to INCOMPATIBILITIES in L<Date::Holidays>
405              
406             =head1 BUGS AND LIMITATIONS
407              
408             Please refer to BUGS AND LIMITATIONS in L<Date::Holidays>
409              
410             =head1 BUG REPORTING
411              
412             Please refer to BUG REPORTING in L<Date::Holidays>
413              
414             =head1 AUTHOR
415              
416             Jonas Brømsø, (jonasbn) - C<< <jonasbn@cpan.org> >>
417              
418             =head1 LICENSE AND COPYRIGHT
419              
420             L<Date::Holidays> and related modules are (C) by Jonas Brømsø, (jonasbn)
421             2004-2022
422              
423             Date-Holidays and related modules are released under the Artistic License 2.0
424              
425              
426             =cut