NAME
OP::Recur - Object class to represent recurring points 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
everymethod 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
atmethod adds a new OP::Recur::At instance, which represents an interval bound to calendar time.The
exceptAtmethod 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
atandexceptAtrules.A field may be wildcarded by providing
undefin its place, but note thatatconsumes 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
atconstructor 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
onmethod 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
exceptOnmethod 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)
eachis just likeon, but without ordinality.The
eachmethod 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
exceptEachmethod 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
coloopexecutes 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::cedeto yield interpreter control back to the loop, and likewise from within the loop to yield control back to any waiting threads.snoozeis like Perl'ssleep, except that$secsmay be a floating point value, andsnoozedoesn't block Coro threads. In the context of a coroutine,snoozecedes 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.snoozeotherwise just works like a hi-res version ofsleep.breakbreaks 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.