App-JobLog
view release on metacpan or search on metacpan
lib/App/JobLog/Log/Line.pm view on Meta::CPAN
package App::JobLog::Log::Line;
$App::JobLog::Log::Line::VERSION = '1.042';
# ABSTRACT: encapsulates one line of log text
use Modern::Perl;
use Class::Autouse qw{DateTime};
use autouse 'App::JobLog::Time' => qw(now tz);
# represents a single non-comment line in the log
# not using Moose to keep CLI snappy
# to_string method for convenience
use overload '""' => \&to_string;
use overload 'bool' => sub { 1 };
# some global variables for use in BNF regex
our ( $date, @tags, @description, $is_beginning, $is_note );
# log line parser
our $re = qr{
^ (?&ts) (?&non_ts) $
(?(DEFINE)
(?<ts> (\d{4}\s++\d++\s++\d++\s++\d++\s++\d++\s++\d++) (?{$date = $^N}) )
(?<non_ts> (?¬e) | (?&duration_mark) )
(?<duration_mark> : (?: (?&done) | (?&event) ) )
(?<done> DONE )
(?<note> <NOTE> (?&event) (?{$is_note = 1}) )
(?<event> (?&tags) : (?&descriptions) (?{$is_beginning = 1}) )
(?<tags> (?:(?&tag)(\s++(?&tag))*+)?)
(?<tag> ((?:[^\s:\\]|(?&escaped))++) (?{push @tags, $^N}))
(?<escaped> \\.)
(?<descriptions> (?: (?&description) (?: ; \s*+ (?&description) )*+ )? )
(?<description> ((?:[^;\\]|(?&escaped))++) (?{push @description, $^N}))
)
}xi;
sub new {
my ( $class, @args ) = @_;
$class = ref $class || $class;
my %opts = @args;
# validate %opts
my $self = bless {}, $class;
if ( exists $opts{comment} ) {
$self->{comment} = $opts{comment};
delete $opts{comment};
die 'inconsistent arguments: ' . join( ', ', @args ) if keys %opts;
}
elsif ( exists $opts{done} ) {
my $time = $opts{time};
die "invalid value for time: $time"
if $time && ref $time ne 'DateTime';
$self->{time} = $time || now;
$self->{done} = 1;
delete $opts{done};
delete $opts{time};
die 'inconsistent arguments: ' . join( ', ', @args ) if keys %opts;
}
elsif ( exists $opts{time} ) {
my $time = $opts{time};
die "invalid value for time: $time"
if $time && ref $time ne 'DateTime';
$self->{time} = $time;
my $tags = $opts{tags};
die 'invalid value for tags: ' . $tags
if defined $tags && ref $tags ne 'ARRAY';
unless ($tags) {
$tags = [];
$self->{tags_unspecified} = 1;
}
$self->{tags} = $tags;
my $description = $opts{description};
if ( my $type = ref $description ) {
die 'invalid type for description: ' . $type
unless $type eq 'ARRAY';
$self->{description} = $description;
}
elsif ( defined $description ) {
# normalize whitespace; this is useful for testing
$description =~ s/^\s++|\s++$//g;
$description =~ s/\s++/ /g;
$description = [$description];
}
else {
$description = [];
}
$self->{description} = $description;
delete @opts{qw(time tags description)};
die 'inconsistent arguments: ' . join( ', ', @args ) if keys %opts;
}
elsif ( exists $opts{text} ) {
die 'text lines in log must be blank' if $opts{text} =~ /\S/;
$self->{text} = $opts{text} . '';
delete $opts{text};
die 'inconsistent arguments: ' . join( ', ', @args ) if keys %opts;
}
return $self;
}
( run in 0.941 second using v1.01-cache-2.11-cpan-39bf76dae61 )