# $Id: Crontab.pm,v 1.00 2001/04/30 23:44:44 ams Exp $
# Copyright 2001 Abhijit Menon-Sen <ams@wiw.org>
package Set::Crontab;
use strict;
use Carp;
use vars qw( $VERSION );
($VERSION) = q$Revision: 1.00 $ =~ /([\d.]+)/;
sub _expand
{
my (@list, @and, @not);
my ($self, $spec, $range) = @_;
# 1,2-4,*/3,!13,>9,<15
foreach (split /,/, $spec) {
my @pick;
my $step = $1 if s#/(\d+)$##;
# 0+"01" == 1
if (/^(\d+)$/) { push @pick, 0+$1; }
elsif (/^\*$/) { push @pick, @$range; }
elsif (/^(\d+)-(\d+)$/) { push @pick, 0+$1..0+$2; }
elsif (/^!(\d+)$/) { push @not, "\$_ != 0+$1"; }
elsif (/^([<>])(\d+)$/) { push @and, "\$_ $1 0+$2"; }
if ($step) {
my $i;
@pick = grep { defined $_ if $i++ % $step == 0 } @pick;
}
push @list, @pick;
}
if (@and) {
my $and = join q{ && }, @and;
push @list, grep { defined $_ if eval $and } @$range;
}
if (@not) {
my $not = join q{ && }, @not;
@list = grep { defined $_ if eval $not } (@list ? @list : @$range);
}
return \@list;
}
sub _initialise
{
my ($self, $spec, $range) = @_;
return undef unless ref($self);
croak "Usage: ".__PACKAGE__."->new(\$spec, [\@range])"
unless defined $spec && ref($range) eq "ARRAY";
$self->{LIST} = $self->_expand($spec, $range);
$self->{HASH} = {map {$_ => 1} @{$self->{LIST}}};
return $self;
};
sub new
{
my $class = shift;
my $self = bless {}, ref($class) || $class;
return $self->_initialise(@_);
}
sub contains
{
my ($self, $num) = @_;
croak "Usage: \$set->contains(\$num)" unless ref($self) && defined $num;
return exists $self->{HASH}{$num};
}
sub list
{
my $self = shift;
croak "Usage: \$set->list()" unless ref($self);
return @{$self->{LIST}};
}
1;
__END__
=head1 NAME
Set::Crontab - Expand crontab(5)-style integer lists
=head1 SYNOPSIS
$s = Set::Crontab->new("1-9/3,>15,>30,!23", [0..30]);
if ($s->contains(3)) { ... }
=head1 DESCRIPTION
Set::Crontab parses crontab-style lists of integers and defines some
utility functions to make it easier to deal with them.
=head2 Syntax
Numbers, ranges, *, and step values all work exactly as described in
L<crontab(5)>. A few extensions to the standard syntax are described
below.
=over 4
=item < and >
<N selects the elements smaller than N from the entire range, and adds
them to the set. >N does likewise for elements larger than N.
=item !
!N excludes N from the set. It applies to the other specified
range; otherwise it applies to the specified ranges (i.e. "!3" with a
range of "1-10" corresponds to "1-2,4-10", but ">3,!7" in the same range
means "4-6,8-10").
=back
=head2 Functions
=over 4
=item new($spec, [@range])
Creates a new Set::Crontab object and returns a reference to it.
=item contains($num)
Returns true if C<$num> exists in the set.
=item list()
Returns the expanded list corresponding to the set.
=back
The functions described above croak if they are called with incorrect
arguments.
=head1 SEE ALSO
L<crontab(5)>
=head1 AUTHOR
Abhijit Menon-Sen <ams@wiw.org>
Copyright 2001 Abhijit Menon-Sen <ams@wiw.org>
This software is distributed under the terms of the Artistic License
<URL:http://ams.wiw.org/code/artistic.txt>.
syntax highlighted by Code2HTML, v. 0.9.1