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> (?&note) | (?&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 )