Calendar-DatesRoles-DataUser-CalendarVar

 view release on metacpan or  search on metacpan

lib/Calendar/DatesRoles/DataUser/CalendarVar.pm  view on Meta::CPAN

package Calendar::DatesRoles::DataUser::CalendarVar;

our $DATE = '2019-07-08'; # DATE
our $VERSION = '0.005'; # VERSION

use 5.010001;
use strict;
use warnings;

use Role::Tiny;
use Role::Tiny::With;
no strict 'refs'; # Role::Tiny imports strict for us

with 'Calendar::DatesRoles::PublicInterface::Basic';
requires 'prepare_data';

sub _calc_min_max_year {
    my $mod = shift;

    return if defined ${"$mod\::_CD_DATAUSER_CALENDARVAR_CACHE_MIN_YEAR"};
    $mod->prepare_data;

    my $cal = ${"$mod\::CALENDAR"};
    my ($min, $max);
    my ($min_anniv, $max_anniv);
    for my $e (@{ $cal->{entries} }) {
        my $year;
        if ($e->{date} =~ /\A([0-9]{4})-([0-9]{2})-([0-9]{2})(?:T|\z)/) {
            $e->{year}  //= $1;
            $e->{month} //= $2 + 0;
            $e->{day}   //= $3 + 0;
            # XXX hour, minute, second?
            if ($e->{tags} && (grep {$_ eq 'anniversary'} @{$e->{tags}})) {
                $min_anniv = $e->{year} if !defined($min_anniv) || $min_anniv > $e->{year};
                $max_anniv = 9999 if !defined($max_anniv) || $max_anniv < 9999;
            } else {
                $min = $e->{year} if !defined($min) || $min > $e->{year};
                $max = $e->{year} if !defined($max) || $max < $e->{year};
            }
        } elsif ($e->{date} =~ /\A(?:--)([0-9]{2})-([0-9]{2})\z/) {
            # anniversary without starting year
            $min_anniv = 1582 if !defined($min_anniv) || $min_anniv > 1582; # start of gregorian calendar :-)
            $max_anniv = 9999 if !defined($max_anniv) || $max_anniv < 9999;
            $e->{month} //= $1 + 0;
            $e->{day}   //= $2 + 0;
        } elsif ($e->{date} =~ m!\AR/([0-9]{4})-([0-9]{2})-([0-9]{2})/P1Y\z!) {
            # anniversary with starting year
            $min_anniv = $1   if !defined($min_anniv) || $min_anniv > $1;
            $max_anniv = 9999 if !defined($max_anniv) || $max_anniv < 9999;
            $e->{month} //= $2 + 0;
            $e->{day}   //= $3 + 0;
        } else {
            die "BUG: $mod has an entry that doesn't have valid date: ".
                ($e->{date} // 'undef');
        }
    }

    #use DD; dd {min=>$min, max=>$max, min_anniv=>$min_anniv, max_anniv=>$max_anniv};

    $min //= $min_anniv;
    $max //= $max_anniv;

    ${"$mod\::_CD_DATAUSER_CALENDARVAR_CACHE_MIN_YEAR"} = $min;
    ${"$mod\::_CD_DATAUSER_CALENDARVAR_CACHE_MAX_YEAR"} = $max;
}

sub get_min_year {
    my $mod = shift;

    $mod->_calc_min_max_year();
    return ${"$mod\::_CD_DATAUSER_CALENDARVAR_CACHE_MIN_YEAR"};
}

sub get_max_year {
    my $mod = shift;

    $mod->_calc_min_max_year();
    return ${"$mod\::_CD_DATAUSER_CALENDARVAR_CACHE_MAX_YEAR"};
}

sub get_entries {
    my $mod = shift;
    my $params = ref $_[0] eq 'HASH' ? shift : {};
    my ($year, $month, $day) = @_;

    die "Please specify year" unless defined $year;
    my $min = $mod->get_min_year;
    die "Year is less than earliest supported year $min" if $year < $min;
    my $max = $mod->get_max_year;
    die "Year is greater than latest supported year $max" if $year > $max;

    my $cal = ${"$mod\::CALENDAR"};
    my @res;

  ENTRY:
    for my $e0 (@{ $cal->{entries} }) {
        my $e = {%$e0}; # shallow copy

        # filter by year
        if ($e->{date} =~ /\A(?:--)([0-9]{2})-([0-9]{2})/a) {
            # anniversary without starting year
            $e->{date} = sprintf "%04d-%02d-%02d", $year, $1, $2;

lib/Calendar/DatesRoles/DataUser/CalendarVar.pm  view on Meta::CPAN


=head1 NAME

Calendar::DatesRoles::DataUser::CalendarVar - Provide Calendar::Dates interface from consumer's $CALENDAR

=head1 VERSION

This document describes version 0.005 of Calendar::DatesRoles::DataUser::CalendarVar (from Perl distribution Calendar-DatesRoles-DataUser-CalendarVar), released on 2019-07-08.

=head1 DESCRIPTION

This role provides L<Calendar::Dates> interface to consumer that has
C<$CALENDAR> package variable. The variable should contain a L<DefHash>.
Relevant keys include: C<default_lang>, C<entries>.

C<entries> is an array of entries, where each entry is a DefHash. Required keys
include: C<date>. C<year>, C<month>, C<day> keys required by Calendar::Dates
will be taken from C<date> to let you be DRY.

Aside from ISO8601 date in the form of C<< YYYY-MM-DD >> or C<<
YYYY-MM-DD"T"HH:MM >>, or date interval in the form of C<<
YYYY-MM-DD"T"HH:MM/HH:MM >>, the C<date> can also be a date-without-year in the
form of C<< --MM-DD >> or C<< MM-DD >>, or repeating date interval in the form
of C<<R/YYYY-MM-DD/P1Y>>. These are to let you specify anniversaries

Example anniversary without starting year:

 {
     summary => "Christmas day",
     date => "12-25", # or "--12-25"
 }

(When returned from C<get_entries>, the date will be converted to C<YYYY-MM-DD>
format.)

Example anniversary with starting year:

 {
     summary => "Larry Wall's birthday",
     date => "R/1954-09-27/P1Y",
 }

(When returned from C<get_entries>, the date will be converted to C<YYYY-MM-DD>
format. Summary will become e.g. for 2019 "Larry Wall's birthday (65th
anniversary)".)

=head2 Anniversaries

To mark an entry as an anniversary without starting year, you can set date to
C<MM-DD> or C<--MM-DD> as previously explained.

To mark an entry as an anniversary with starting year, you can either: 1) set
date to C<R/YYYY-MM-DD/P1Y>; or 2) include "anniversary" tag.

=head1 METHODS

=head2 get_min_year

Only years from non-anniversary dates are accounted for when determining
min_year and max_year. But if there are no non-anniversary dates in the
calendar, then the years from anniversaries will also be used.

=head2 get_max_year

Only years from non-anniversary dates are accounted for when determining
min_year and max_year. But if there are no non-anniversary dates in the
calendar, then the years from anniversaries will also be used.

=head2 get_entries

Usage:

 $entries = $caldate->get_entries([ \%params , ] $year [ , $month [ , $day ] ]);

Only entries from matching year will be used, unless for anniversary entries.

By default, low-priority entries will not be included unless the parameter
C<all> is set to true.

B<Recognized parameters>.

=over

=item * all

Boolean. Specified in Calendar::Dates.

=item * include_tags

Array. Specified in Calendar::Dates.

=item * exclude_tags

Array. Specified in Calendar::Dates.

=back

=head1 HOMEPAGE

Please visit the project's homepage at L<https://metacpan.org/release/Calendar-DatesRoles-DataUser-CalendarVar>.

=head1 SOURCE

Source repository is at L<https://github.com/perlancar/perl-Calendar-DatesRoles-DataUser-CalendarVar>.

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Calendar-DatesRoles-DataUser-CalendarVar>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 SEE ALSO

L<Calendar::Dates>

L<Calendar::DatesRoles::DataProvider::CalendarVar::FromDATA::Simple>

L<Calendar::DatesRoles::DataProvider::CalendarVar::FromDATA::CSVJF>

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE



( run in 0.636 second using v1.01-cache-2.11-cpan-5a3173703d6 )