NAME

Time::Activated - Syntactic sugar over time activated code supporting DateTime and ISO8601 (a.k.a. "Javascript dates").

VERSION

Version 1.01

SYNOPSIS

use Time::Activated;

# simple statements
time_activated after_moment '1985-01-01T00:00:00' => execute_logic { print "New feature beginning Jan 1st 1985!" };
time_activated before_moment '1986-12-31T00:00:00' => execute_logic { print "This feature ends by 1986!" };
time_activated before_moment '2000' => execute_logic { print "Let's dance like its 1999!" };
time_activated
	between_moments '2016-01-01T00:00:00' => '2016-12-31T23:59:59' =>
	execute_logic { print "Business logic exception for 2016!" };

# combined statements a la try {} catch {} by Try::Tiny (tm)
time_activated
	after_moment '1985-01T00:00:00-03:00' => execute_logic { print "New business logic!" }, # <-- Gotcha! it is a ,
	before_moment '1986-12-31T00:00:00-03:00' => execute_logic { print "Old business logic!" };

# elements get evaluated in order
time_activated
	before_moment '1986-12-31T00:00:00-03:00' => execute_logic { print "Old business logic!" }, # <-- Switch that ;
	after_moment '1985-01-01T00:00:00-03:00' => execute_logic { print "New business logic!" }; # <-- Switch that ,

# overlapping allowed, all matching items get executed
time_activated
	after_moment '2018', execute_logic { print "This is from 2018-01-01 and on." },
	after_moment '2018-06-01', execute_logic { print "This is from 2018-06-01 and on. On top of the previuos." };

# Alternate syntax
time_activated
	after_moment '2018', execute_logic { print "Welcome to new business process for 2018!" }, #=> is a ,
	after_moment '2019', execute_logic { print "This is added on top of 2018 processes for 2019!" };

# DateTime objects can be used to define points in time
my $dt = DateTime->new(year=>2018, month=>10, day=>16);
time_activated after_moment $dt => execute_logic { print "This happens after 2018-10-16!" };

DESCRIPTION

This modules aims at managing and documenting time activated code such as that which may araise from migrations and planified process changes in a way that can be integrated and tested in advance.

You can use Time::Activated before, after and between to state which parts of code will be executed on certain dates due to changing business rules, programmed web service changes in endpoints/contracts or other time related events.

USAGE

EXPORTS

By default Time::Activated exports time_activated, before, after, between and execute.

If you need to rename the time_activated, after, before, between or executye keyword consider using Sub::Import to get Sub::Exporter's flexibility.

If automatic exporting sound nasty: use Time::Activated qw();

SYNTAX

time_activated "CONDITION" "WHEN" "WHAT"

"CONDITION"

Can be any of after_moment, before_moment, between_moments. after_moment, accepts a parameters representing a point in time at and after which the execute_logic statement will be executed. before_moment, accepts a parameters representing a point in time before, but not including, which the execute_logic statement will be executed. between_moments, accepts two parameters representing a range in time between, both limits included, which the execute_logic statement will be executed.

"WHEN"

Is either a DateTime object or a scalar representing a iso8601 (a.k.a. Javascript date)

Expansion is supported so '2000', '2000-01', '2000-01-01' and '2000-01-01T00:00' all are equivalents to '2000-01-01T00:00:00'.

Timezones are supported and honored. Thus:

    time_activated
		after_moment '1999-12-31T23:00:00-01:00' => execute_logic { print('Matches from 2000-01-01T00:00:00 GMT!') },
		after_moment '2000-01-01T00:00:00+01:00' => execute_logic { print('Matches from 1999-01-01T23:00:00 GMT!') };

after includes the exact time which is used as parameter, before does not. Thus using after and before with the same time parameter ensures that only one statement gets executed. i.e.:

time_activated
	before_moment 	SOME_DATE => execute { print "Before!" },
	after_moment 	SOME_DATE => execute { print "After!" };

"WHAT"

Is either an anonymous code block or a reference to subroutine Code that will be executed on a given conditions in many ways:

time_activated
	after_moment '2001' => execute_logic \&my_great_new_feature; #No parameters can be passed with references...

time_activated
	after_moment '2000' => execute_logic { print 'Y2K ready!' },
	after_moment '2001' => execute_logic (\&my_great_new_feature), #References with multilines need ()
	after_moment '2002' => execute_logic { &my_great_new_feature("We need parameters by 2002")};

CONSTANTS

It is cool to use constants documenting both time and intent.

use constants PROCESS_X_CUTOVER_DATE => '2017-01-01T00:00:00';

time_activated after_moment PROCESS_X_CUTOVER_DATE => execute_logic { &new_business_process($some_state) };

TESTING

Test::MockTime is your friend.

use Test::More tests => 1;
use Time::Activated;
use Test::MockTime;

Test::MockTime::set_absolute_time('1986-05-27T00:00:00Z');
time_activated after_moment '1985-01-01T00:00:00-03:00' => execute_logic { pass('Basic after') }; # this gets executed

Test::MockTime::set_absolute_time('1984-05-27T00:00:00Z');
time_activated after_moment '1985-01-01T00:00:00-03:00' => execute_logic { fail('Basic after') }; # this does not get executed

SUBROUTINES/METHODS

time_activated

time_activated is both the syntactical placeholder for grammar in Time::Activated and the internal implementation of the modules functionality.

Syntactically the structure is like so (note the ','s and ';'):

time_activated
	after_moment ..., execute_logic ...,
	before_moment ..., execute_logic ...,
	between_moments ..., ... execute_logic ...;

Alternatively some can be changed for a => for a fancy syntax. This abuses anonymous hashes, some inteligent selections of prototypes (stolen from Try::Tiny) and probably other clever perl-ish syntactical elements that escape my understanding. Note '=>'s, ','s and ';':

time_activated
	after_moment ... => execute_logic ...,
	before_moment ... => execute_logic ...,
	between_moments ... => ... => execute_logic ...; #Given. This does not look so fancy but more into the weird side...

before_moment

before_moment defines a point in time before not including the exact point in time which code is executed.

This does not happen before January 1st 2018 at 00:00 but does happen from that exact point in time and on.

time_activated
	before_moment '2018', execute_logic { print "We are awaiting for 1/1/2018..." };

Another fancy way to say do not do that before January 1st 2018 at 00:00.

ime_activated
	before_moment '2018' => execute_logic { print "We are awaiting for 1/1/2018..." };

A fancy way to combine before statements.

time_activated
	before_moment '2018' => execute_logic { print "We are awaiting for 1/1/2018..." },
	before_moment '2019' => execute_logic { print "Not quite there for 1/1/2019..." };

after_moment

after_moment defines a point in time after including the exact point in time which code is executed.

time_activated
	after_moment '2018' => execute { print "Wea are either at 1/1/2018 or after it..." };

As with before_moment statements can be combined with before_moment, after_moment and between_moments with no limit.

between_moments

between_moments defines two points in time between which code is executes including both exact points in time.

time_activated
	between_moment '2018' => '2018-12-31T23:59:59' => execute_logic { print "This is 2018..." };

As with before_moments statements can be combined with before_moment, after_moment and between_moment with no limit.

execute_logic

Exists for the sole reason of verbosity. Accepts a single parameters that must be a subroutine or anonymous code block.

execute_logic { print "This is a verbose way of saying that this will be executed!" };

PRIVATES

_spawn_dt

_spawn_dt is a private function defined in hopes that additional date formats can be used to define points in time.

DIAGNOSTICS

time_activated

(F) time_activated() encountered an unexpected argument...

time_activated is not followed by either after_moment, before_moment or between_moments

time_activated wierd_sub(); #<- Plain weird but it could somehow happen
after_moment before_moment between_moments

(F) Useless bare after_moment() (F) Useless bare before_moment() (F) Useless bare between_moments()

Use of xxxxx() with no time_activated before it. Generally the result of a ; instead of a ,.

time_activated
	after_moment '2018' {}; #<- mind the ;
	before_moment '2018' {}; #<- This one triggers a 'Useless bare before()' since it is not part of the time_activated call

BUGS AND LIMITATIONS

No known bugs, but you cannot have this syntax. Some , and/or => required:

time_activated
	before_moment '2016-09-24' {}
	after_moment '2016-10-24' {};

DEPENDENCIES

DateTime, DateTime::Format::ISO8601, Carp, Exporter, Sub::Name.

INCOMPATIBILITIES

Versions prior to 1.00 have collission with Moose. Naturally, Moose wins and compatibility breaks from 0.12 to 1.00.

Some old distributions that cannot set dates beyond 2038 fail some tests.

SEE ALSO

Try::Tiny

A non related module that became the inspiration for Time::Activated.

VERSION CONTROL

http://github.com/gbarco/Time-Activated/

SUPPORT

Bugs may be submitted through the RT bug tracker (or bug-Time-Activated@rt.cpan.org).

AUTHOR

  • Gonzalo Barco <gbarco uy at gmail.com, no spaces>

LICENSE AND COPYRIGHT

Copyright 2016 Gonzalo Barco.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 367:

You forgot a '=back' before '=head1'