NAME
OP::Recur
DESCRIPTION
Objects to represent a recurring point in time.
SYNOPSIS
use OP;
my $recur = OP::Recur->new();
#
# every:
#
# Every X UNITS ie "every 3 minutes"
#
$recur->every(3, MIN); # Time::Consts constant
$recur->every(180); # Implicit UNITS is Seconds (1)
#
# at, exceptAt:
#
# At [Year]/[Month]/[Day] [Hour]:[Minute]:Seconds
#
# Except At [Year]/[Month]/[Day] [Hour]:[Minute]:Seconds
#
$recur->at(*YYYY,*MM,*DD,*hh,*mm,ss);
$recur->exceptAt(*YYYY,*MM,*DD,*hh,*mm,ss);
#
# on, exceptOn:
#
# On Nth [Weekday] [in Month] [of Year]
#
# Except On Nth [Weekday] [in Month] [of Year]
#
$recur->on(Nth,*WDAY,*MM,*YYYY);
$recur->exceptOn(Nth,*WDAY,*MM,*YYYY);
#
# each, exceptEach:
#
# Each [Weekday] [in Month] [of Year]
#
# Except Each [Weekday] [in Month] [of Year]
#
$recur->each(*WDAY,*MM,*YYYY);
$recur->exceptEach(*WDAY,*MM,*YYYY);
#
# C<loop> and C<coloop> will execute code at the specified
# intervals, in blocking or non-blocking fashion. See examples.
#
The methods every
, at
/exceptAt
, on
/exceptOn
, and each
/exceptEach
may be called as many times as needed, overlaying rules to create complex recurrence loops. If called without any arguments, these methods return an OP::Array instance containing the specific Recur:: helper instances which were added.
INSTANCE GETTERS
$recur->every();
Called with no arguments, returns an OP::Array of all OP::Recur::Every inclusion rules in self.
$recur->at();
Called with no arguments, returns an OP::Array of all OP::Recur::At inclusion rules in self.
$recur->exceptAt();
Called with no arguments, returns an OP::Array of all OP::Recur::At exclusion rules in self.
$recur->on();
Called with no arguments, returns an OP::Array of all OP::Recur::On inclusion rules in self.
$recur->exceptOn();
Called with no arguments, returns an OP::Array of all OP::Recur::On exclusion rules in self.
$recur->each();
Called with no arguments, returns an OP::Array of all OP::Recur::Each inclusion rules in self.
$recur->exceptEach();
Called with no arguments, returns an OP::Array of all OP::Recur::Each exclusion rules in self.
INSTANCE SETTERS
$recur->every(X,[UNITS]);
The
every
method adds a new OP::Recur::Every instance, which represents a recurring fixed time interval.UNITS may be any number where 1 is equal to 1 second. The constants available in the Time::Consts module work well for this. Sub-second or floating point values for either argument are acceptable.
Omitting a UNITS argument implies Seconds (1) as a base unit.
# # Fixed interval, eg every 3 minutes: # my $recur = every(3,MIN); # See Time::Consts # # Another example; every 500 milliseconds: # $recur->every(500,MSEC); # See Time::Consts
$recur->at([YYYY],[MM],[DD],[hh],[mm],ss)
$recur->exceptAt([YYYY],[MM],[DD],[hh],[mm],ss)
The
at
method adds a new OP::Recur::At instance, which represents an interval bound to calendar time.The
exceptAt
method follows the same pattern, but is used to declare excluded times rather than included ones.The magic constant "LAST" may be used for DD to indicate the final day in a given month. LAST only works this way for
at
andexceptAt
rules.A field may be wildcarded by providing
undef
in its place, but note thatat
consumes args in a non-traditional reverse order, and also acts like a multi-method where the number of arguments determines the most significant base value (examples below).The
at
constructor supports 1-6 arguments, always ordered from most significant (ie Year) to least significant (Seconds). The different possible modes of usage are shown here:# # at(YYYY,MM,DD,hh,mm,ss) # # Describes a one-time occurrence, # eg December 21 2012 at midnight: # $recur->at(2012,12,21,00,00,00); # # at(MM,DD,hh,mm,ss) # # Describes a yearly recurrence, # eg Every day in January at midnight: # $recur->at(01,undef,00,00,00); # # at(DD,hh,mm,ss) # # Describes a monthly recurrence, # eg Last day of each month at midnight: # $recur->at(LAST,00,00,00); # # Describes a daily recurrence, # at(hh,mm,ss) # # eg Every day at noon: # $recur->at(12,00,00); # # at(mm,ss) # # Describes an hourly recurrence, # eg Every hour at :45 after: # $recur->at(45,00); # # at(ss) # # Describes an every-minute recurrence, # eg Every minute at 30 seconds: # $recur->at(30);
Hopefully, the above examples illustrate a usage pattern for
at
.$recur->on(Nth,WDAY,*MM,*YYYY)
$recur->exceptOn(Nth,WDAY,*MM,*YYYY)
The
on
method adds a new OP::Recur::On instance, which represents an ordinal weekday in an optional month/year, ie "The second Thursday [in June] [2010]". MM and YYYY are wild ifundef
.WDAY is a day 1-7 where monday = 1, and MM is a month between 1 and 12. YYYY is the actual year, such as "2009". The constants available in OP::Enum::DaysOfWeek and OP::Enum::WeeksOfMonth are suitable for WDAY and MM, respectively.
The
exceptOn
method follows the same pattern, but is used to declare excluded times rather than included ones.use OP::Enum::DaysOfWeek; use OP::Enum::WeeksOfMonth; # # Recur on the 1st monday of january, 2010 # $recur->on(1,MON,JAN,2010); # # Recur every first monday in january # $recur->on(1,MON,JAN); # # Recur every first monday # $recur->on(1,MON); # # Recur every first day # $recur->on(1);
$recur->each(*WDAY,*MM,*YYYY)
$recur->exceptEach(*WDAY,*MM,*YYYY)
each
is just likeon
, but without ordinality.The
each
method adds a new OP::Recur::Each instance, which represents a recurring weekday, optionally within a month/year, ie "Each Thursday [in June] [2010]". WDAY, MM, and YYYY are optional args, but should be given as undef.WDAY is a day 1-7 where monday = 1, and MM is a month between 1 and 12. YYYY is the actual year, such as "2009". The constants available in OP::Enum::DaysOfWeek and OP::Enum::WeeksOfMonth are suitable for WDAY and MM, respectively.
The
exceptEach
method follows the same pattern, but is used to declare excluded times rather than included ones.use OP::Enum::DaysOfWeek; use OP::Enum::WeeksOfMonth; # # Recur each monday in january 2010 # $recur->on(MON,JAN,2010); # # # Recur each monday in january # $recur->on(MON,JAN); # # Recur each monday # $recur->on(MON);
BLOCKING LOOP
$recur->loop($sub), break
Execute the received sub at the defined time interval, within a loop.
To exit the loop from within the sub, call
OP::Recur::break
.use OP; use Time::Consts qw| :ALL |; my $recur = OP::Recur->new(); # # Mix n match # $recur->every(5,SEC); $recur->every(2,SEC); $recur->loop( sub { my $now = shift; print "Doing something at $now...\n"; break if $now > BEDTIME; } );
NON-BLOCKING LOOP
Non-blocking loops utilize Coro, and are compatible with POE (see notes below).
$recur->coloop($sub), snooze($secs), break
coloop
executes the received sub at the defined time interval, within a cooperative Coro thread. It does not wait for the loop to return; you must callsnooze($secs)
orCoro::cede
to yield interpreter control back to the loop, and likewise from within the loop to yield control back to any waiting threads.snooze
is like Perl'ssleep
, except that$secs
may be a floating point value, andsnooze
doesn't block Coro threads. In the context of a coroutine,snooze
cedes control of the interpreter back to any threads which need to do work, and they will do the same in turn. When the specified time has elapsed, the thread will stop ceding and resume work.snooze
otherwise just works like a hi-res version ofsleep
.break
breaks the loop, invoking Perl'slast
.use OP; use Time::Consts qw| :ALL |; my $beep = OP::Recur->new(); # # Start beeping in thread A # $beep->every(4.2,SEC); $beep->coloop( sub { my $now = shift; print "Beep at $now...\n"; break if $now > BEDTIME; } ); # # Start booping in thread B # my $boop = OP::Recur->new(); $boop->every(2.5,SEC); $boop->coloop( sub { my $now = shift; print "Boop at $now.. boop boop!\n"; break if $now > DOOMSDAY } ); # # Insert your main loop here: # while(1) { snooze(.001); }
POE Compatibility
In addition to invoking cede
in Coro, snooze
invokes POE::Kernel's run_one_timeslice
method at each time tick, allowing the developer to interlace POE and Coro threads.
$recur->coloop( sub {
#
# Non-blocking action based on a POE::Component:
#
POE::Session->create( ... );
} );
#
# Insert your main loop here:
#
while(1) {
##### XXX This is now handled by snooze().
##### POE::Kernel->run_one_timeslice;
snooze(.001);
}
SEE ALSO
This file is part of OP.