package Date::Holidays::Adapter; # $Id: Adapter.pm 1742 2007-02-22 19:47:55Z jonasbn $ use strict; use warnings; use Carp; use Error qw(:try); use Module::Load; use Locale::Country; use Date::Holidays::Exception::AdapterLoad; use Date::Holidays::Exception::AdapterInitialization; use Date::Holidays::Exception::UnsupportedMethod; use vars qw($VERSION); $VERSION = '0.02'; sub new { my ($class, %params) = @_; my $self = bless { _countrycode => lc $params{countrycode}, _adaptee => undef, }, $class || ref $class; try { my $adaptee = $self->_fetch(\%params); if ($adaptee) { $self->{_adaptee} = $adaptee; } else { throw Date::Holidays::Exception::AdapterInitialization('Unable to initialize adaptee class'); } } catch Date::Holidays::Exception::AdapterLoad with { my $E = shift; throw Date::Holidays::Exception::AdapterInitialization($E->{-text}); } otherwise { my $E = shift; $E->throw; }; return $self; } sub holidays { my ($self, %params) = @_; my $r; try { my $method = 'holidays'; my $sub = $self->{_adaptee}->can('holidays'); if (! $sub) { $method = "$self->{_countrycode}_holidays"; $sub = $self->{_adaptee}->can($method); } if ($sub) { $r = &{$sub}($params{'year'}); } } catch Date::Holidays::Exception::UnsupportedMethod with { my $E = shift; $E->throw(); }; return $r; } sub is_holiday { my ($self, %params) = @_; my $r; try { my $method = 'is_holiday'; my $sub = $self->{_adaptee}->can('is_holiday'); if (! $sub) { $method = "is_$self->{_countrycode}_holiday"; $sub = $self->{_adaptee}->can($method); } if ($sub) { $r = &{$sub}($params{'year'}, $params{'month'}, $params{'day'}); } } catch Date::Holidays::Exception::UnsupportedMethod with { my $E = shift; $E->throw(); }; return $r; } sub _load { my ($self, $module) = @_; eval { load $module; }; #From Module::Load if ($@) { throw Date::Holidays::Exception::AdapterLoad("Unable to load: $module"); } return $module; } sub _fetch { my ( $self, $params ) = @_; if ( !$self->{_countrycode} ) { croak "No country code specified"; } if ( !$params->{nocheck} ) { if ( !code2country($self->{_countrycode}) ) { #from Locale::Country carp "$self->{_countrycode} is not a valid country code"; return; } } my $module; try { $module = 'Date::Holidays::' . uc $self->{_countrycode}; $self->_load($module); } catch Date::Holidays::Exception::AdapterLoad with { my $E = shift; $E->throw; } otherwise { my $E = shift; $E->throw; }; return $module; } 1; __END__ =head1 NAME Date::Holidays::Adapter - an adapter class for Date::Holidays::* modules =head1 SYNOPSIS my $adapter = Date::Holidays::Adapter->new(countrycode => 'NO'); my ($year, $month, $day) = (localtime)[ 5, 4, 3 ]; $year += 1900; $month += 1; print "Woohoo" if $adapter->is_holiday( year => $year, month => $month, day => $day ); my $hashref = $adapter->holidays(year => $year); printf "Dec. 24th is named '%s'\n", $hashref->{'1224'}; #christmas I hope =head1 VERSION This POD describes version 0.02 of Date::Holidays::Adapter =head1 DESCRIPTION The is the SUPER adapter class. All of the adapters in the distribution of Date::Holidays are subclasses of this class. (SEE also L<Date::Holidays>). The SUPER adapter class is at the same time a generic adapter. It attempts to adapt to the most used API for modules in the Date::Holidays::* namespace. So it should only be necessary to implement adapters to the exceptions to modules not following the the defacto standard or suffering from other local implementations. =head1 SUBROUTINES/METHODS The public methods in this class are all expected from the adapter, so it actually corresponds with the abstract is outlined in L<Date::Holidays::Abstract>. Not all methods/subroutines may be implemented in the adaptee classes, the adapters attempt to make the adaptee APIs adaptable where possible. This is afterall the whole idea of the Adapter Pattern, but apart from making the single Date::Holidays::* modules uniform towards the clients and L<Date::Holidays> it is attempted to make the multitude of modules uniform in the extent possible. =head2 new The constructor, takes a single named argument, B<countrycode> =head2 is_holiday The B<holidays> method, takes 3 named arguments, B<year>, B<month> and B<day> returns an indication of whether the day is a holiday in the calendar of the country referenced by B<countrycode> in the call to the constructor B<new>. =head2 holidays The B<holidays> method, takes a single named argument, B<year> returns a reference to a hash holding the calendar of the country referenced by B<countrycode> in the call to the constructor B<new>. The calendar will spand for a year and the keys consist of B<month> and B<day> concatenated. =head1 DEVELOPING A DATE::HOLIDAYS::* ADAPTER If you want to develop an adapter compatible with interface specified in this class. You have to implement the following 3 methods: =over =item new A constructor, taking a single argument a two-letter countrycode (SEE: L<Locale::Country>) You can also inherit the one implemented and offered by this class B<NB>If inheritance is used, please remember to overwrite the two following methods, if applicable. =item * holidays This has to follow the API outlined in SUBROUTINES/METHODS. For the adaptee class anything goes, hence the use of an adapter. Please refer to the DEVELOPER section in L<Date::Holidays> about contributing to the Date::Holidays::* namespace or attempting for adaptability with L<Date::Holidays>. =item * is_holiday This has to follow the API outlined in SUBROUTINES/METHODS. For the adaptee class anything goes, hence the use of an adapter. Please refer to the DEVELOPER section in L<Date::Holidays> about contributing to the Date::Holidays::* namespace or attempting for adaptability with L<Date::Holidays>. =back Apart from the methods described above you can also overwrite the _fetch method in this class, This is used if your module is not a part of the Date::Holidays::* namespace or the module bears a name which is not ISO3166 compliant. See also: =over =item * L<Date::Holidays::UK> =item * L<Date::Japanese::Holiday> =back =head1 DIAGNOSTICS =over =item * L<Date::Holidays::Exception::AdapterLoad> Exception thrown in the case where the B<_load> method is unable to load a requested adapter module. The exception is however handled internally. =item * L<Date::Holidays::Exception::AdapterInitialization> Exception thrown in the case where the B<_new> method is unable to initialize a requested adapter module. =item * L<Date::Holidays::Exception::UnsupportedMethod> Exception thrown in the case where the loaded and initialized module does not support the called method. (SEE: METHODS/SUBROUTINES). =back =head1 DEPENDENCIES =over =item * L<Carp> =item * L<Error> =item * L<Module::Load> =item * L<UNIVERSAL> =back =head1 INCOMPATIBILITIES Please refer to INCOMPATIBILITIES in L<Date::Holidays> =head1 BUGS AND LIMITATIONS Please refer to BUGS AND LIMITATIONS in L<Date::Holidays> =head1 BUG REPORTING Please refer to BUG REPORTING in L<Date::Holidays> =head1 AUTHOR Jonas B. Nielsen, (jonasbn) - C<< <jonasbn@cpan.org> >> =head1 LICENSE AND COPYRIGHT L<Date::Holidays> and related modules are (C) by Jonas B. Nielsen, (jonasbn) 2004-2007 L<Date::Holidays> and related modules are released under the artistic license The distribution is licensed under the Artistic License, as specified by the Artistic file in the standard perl distribution (http://www.perl.com/language/misc/Artistic.html). =cut