App-JobLog

 view release on metacpan or  search on metacpan

lib/App/JobLog/Command/add.pm  view on Meta::CPAN

 houghton@NorthernSpy:~$ job a Getting stared back at.

=head1 DESCRIPTION

B<App::JobLog::Command::add> is the command you'll use most often. It appends an event to the log.

=head2 TAGS

You may optionally attach categories to tasks with tags. Any string can be a tag but to make the output readable you'll want them
to be short. Also, in the logs tags are delimited by whitespace and separated from the timestamp and description by colons, so
these characters will be escaped with a slash. If you edit the log by hand and forget to escape these characters the log will
still parse but you will be surprised by the summaries you get.

You may specify multiple tags, but each one needs its own B<--tag> flag.

If you don't specify otherwise the new event will inherit the tags of the previous event, so you will need to apply
the B<--clear-tags> option to prevent this. The reasoning behind this feature is that you change tags seldom but change tasks
often so inheriting tags by default saves labor.

=head1 SEE ALSO

lib/App/JobLog/Command/info.pm  view on Meta::CPAN

The text between the two colons, or between the first colon and the E<lt>NOTEE<gt> tag, which is blank in these
examples, is a list of space-delimited tags one can use to categorize things. For
instance, if you were performing this task for Acme Widgets you might have typed

   $executable @{[App::JobLog::Command::add->name]} -t "Acme Widgets" what I am doing now

producing

   2011 2 1 15 19 12:Acme\\ Widgets:what I am doing now

Note the I<\\> character. This is the escape character which neutralizes any special value of
the character after it -- I<\\>, I<:>, or a whitespace character.

You may tag an event multiple times. E.g.,

   $executable @{[App::JobLog::Command::add->name]} -t "Acme Widgets" -t foo -t bar what I am doing now

producing

   2011 2 1 15 19 12:Acme\\ Widgets foo bar:what I am doing now

lib/App/JobLog/Command/note.pm  view on Meta::CPAN

 * they have a timestamp but no duration

They are like tasks in that it is nice to find them by time, tag, text, etc. and they
are well suited to a log format. C<note> is the command that lets you log notes as you
would tasks.

=head2 TAGS

You may optionally attach categories to tasks with tags. Any string can be a tag but to make the output readable you'll want them
to be short. Also, in the logs tags are delimited by whitespace and separated from the timestamp and description by colons, so
these characters will be escaped with a slash. If you edit the log by hand and forget to escape these characters the log will
still parse but you will be surprised by the summaries you get.

You may specify multiple tags, but each one needs its own B<--tag> flag.

If you don't specify otherwise the new note will inherit the tags of the previous note, so you will need to apply
the B<--clear-tags> option to prevent this. The reasoning behind this feature is that when you take notes you frequently take
several in succession and want them all tagged the same way.

=head1 AUTHOR

lib/App/JobLog/Log/Line.pm  view on Meta::CPAN

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

lib/App/JobLog/Vacation/Period.pm  view on Meta::CPAN


# log line parser
my $re = qr{
    ^ (?&ts) : (?&non_ts) $
    (?(DEFINE)
     (?<ts> (?&date) : (?&date) )
     (?<date> (\d{4}\s++\d++\s++\d++\s++\d++\s++\d++\s++\d++) (?{push @dates, $^N}) )
     (?<non_ts> (?&flex) : (?&tags) : (?&description))
     (?<flex> ([012]{2}) (?{$type = $^N}))
     (?<tags> (?:(?&tag)(\s++(?&tag))*+)?)
     (?<tag> ((?:[^\s:\\]|(?&escaped))++) (?{push @tags, $^N}))
     (?<escaped> \\.)
     (?<description> (.++) (?{$description = $^N}))
    )
}xi;


sub parse {
    my ( $class, $text ) = @_;
    $class = ref $class || $class;
    local ( @dates, $type, @tags, $description );
    if ( $text =~ $re ) {

t/LogLine.t  view on Meta::CPAN

# check stringification
subtest 'stringification' => sub {
    $stringification = '2011  2  8  9 50 12:da di la:this is the description';
    is( $ll->to_string, $stringification, 'stringifies as expected' );
};

subtest 'tag escaping' => sub {
    push @{ $ll->tags }, 'uh oh', 'Foo::Bar', '\\';
    $stringification =
'2011  2  8  9 50 12:Foo\\:\\:Bar \\\\ da di la uh\\ oh:this is the description';
    is( $ll->to_string, $stringification, 'escapes tags properly' );
    my %tags = map { $_ => 1 } @{ $ll->tags };
    ok( $tags{'uh oh'},    'retains tag containing space without escape' );
    ok( $tags{'Foo::Bar'}, 'retains tag containing colon without escape' );
    ok( $tags{'\\'},       'retains tag containing slash without escape' );
};

subtest 'tag existence tests' => sub {
    ok( $ll->all_tags( 'la', 'di', 'da' ), 'all_tags method works 1' );
    ok( !$ll->all_tags( 'la', 'di', 'da', 'quux' ), 'all_tags method works 2' );
    ok( $ll->exists_tag( 'la', 'di', 'da', 'quux' ),
        'exists_tag method works 1' );
    ok( !$ll->exists_tag('quux'), 'exists_tag method works 2' );
    $ll->tags = [];
    ok( @{ $ll->tags } == 0, 'cleared tags' );

t/LogLine.t  view on Meta::CPAN


subtest 'description modification' => sub {
    push @{ $ll->description }, 'yada yada';
    $stringification = '2011  2  8  9 50 12::this is the description;yada yada';
    is( $ll->to_string, $stringification,
        'multiple element description stringifies correctly' );
    $ll->description = [];
    ok( @{ $ll->description } == 0, 'cleared description' );
    push @{ $ll->description }, ';', '\\';
    $stringification = '2011  2  8  9 50 12::\\;;\\\\';
    is( $ll->to_string, $stringification, 'description correctly escaped' );
    my %description = map { $_ => 1 } @{ $ll->description };
    ok( $description{';'},
        'retains description containing semicolon without escape' );
    ok( $description{'\\'},
        'retains description containing slash without escape' );
};

subtest 'comments' => sub {
    $line = ' # this is the comment ';
    $ll   = $module->parse($line);
    ok( $ll->is_comment, 'recognized comment' );
    is( $ll->comment, 'this is the comment', 'extracted comment' );
};

subtest 'done event' => sub {



( run in 0.379 second using v1.01-cache-2.11-cpan-c21f80fb71c )