App-Jiffy
view release on metacpan or search on metacpan
lib/App/Jiffy.pm view on Meta::CPAN
use 5.008_005;
our $VERSION = '0.09';
use App::Jiffy::TimeEntry;
use App::Jiffy::View::Timesheet;
use App::Jiffy::Util::Duration qw/round/;
use YAML::Any qw( LoadFile );
use JSON::MaybeXS 'JSON';
use Getopt::Long;
Getopt::Long::Configure("pass_through");
use Moo;
has cfg => (
is => 'ro',
default => sub {
LoadFile( $ENV{HOME} . '/.jiffy.yml' ) || {};
},
);
has terminator_regex => (
is => 'ro',
isa => sub {
die 'terminator_regex must be a regex ref' unless ref $_[0] eq 'Regexp';
},
default => sub {
qr/^end$|
^done$|
^eod$|
^finished$|
^\\\(^\s*\.^\s*\)\/$| # This is a smily face with hands raised
^â$|
^x$/x;
},
);
sub remove_terminators {
my $self = shift;
return (
title => {
'$not' => $self->terminator_regex,
} );
}
sub add_entry {
my $self = shift;
my $options = shift;
my $title;
if ( ref $options ne 'HASH' ) {
$title = $options;
undef $options;
} else {
$title = shift;
}
my $start_time;
my $LocalTZ = DateTime::TimeZone->new( name => 'local' ); # For caching
my $now = DateTime->now( time_zone => $LocalTZ );
if ( $options->{time} ) {
require DateTime::Format::Strptime;
# @TODO Figure out something more flexible and powerful to get time
# First try H:M:S
my $strp = DateTime::Format::Strptime->new(
pattern => '%T',
time_zone => $LocalTZ,
);
$start_time = $strp->parse_datetime( $options->{time} );
# If no time found try just H:M
if ( not $start_time ) {
my $strp = DateTime::Format::Strptime->new(
pattern => '%R',
time_zone => $LocalTZ,
);
$start_time = $strp->parse_datetime( $options->{time} );
}
# Make sure the date part of the datetime is not set to the
# beginning of time.
if ( $start_time and $start_time->year < $now->year ) {
$start_time->set(
day => $now->day,
month => $now->month,
year => $now->year,
);
}
}
# Create and save Entry
App::Jiffy::TimeEntry->new(
title => $title,
start_time => $start_time // $now,
cfg => $self->cfg,
)->save;
}
sub current_time {
my $self = shift;
my $latest = App::Jiffy::TimeEntry::last_entry( $self->cfg );
my $duration = $latest->duration;
print '"' . $latest->title . '" has been running for';
my %deltas = $duration->deltas;
foreach my $unit ( keys %deltas ) {
next unless $deltas{$unit};
print " " . $deltas{$unit} . " " . $unit;
}
print ".\n";
}
sub time_sheet {
my $self = shift;
my $options = shift;
my $from;
if ( ref $options ne 'HASH' ) {
$from = $options;
undef $options;
} else {
$from = shift;
}
my $from_date = DateTime->today( time_zone => 'local' );
if ( defined $from ) {
$from_date->subtract( days => $from );
}
my @entries = App::Jiffy::TimeEntry::search(
$self->cfg,
query => {
start_time => { '$gt' => $from_date, },
$self->remove_terminators,
},
sort => {
start_time => 1,
},
);
if ( $options->{round} ) {
@entries = map { $_->duration( round( $_->duration ) ); $_ } @entries;
}
if ( $options->{json} ) {
my $json = JSON::MaybeXS->new( pretty => 1, convert_blessed => 1 );
print $json->encode( \@entries );
} else {
$options->{from} = $from;
App::Jiffy::View::Timesheet::render( \@entries, $options );
}
}
sub search {
my $self = shift;
my $query_text = shift;
my $options = shift;
my $days;
if ( ref $options ne 'HASH' ) {
$days = $options;
undef $options;
} else {
$days = shift;
}
my $from_date = DateTime->today( time_zone => 'local' );
if ( defined $days ) {
$from_date->subtract( days => $days );
}
my @entries = App::Jiffy::TimeEntry::search(
$self->cfg,
query => {
start_time => { '$gt' => $from_date, },
$self->remove_terminators,
title => qr/$query_text/,
},
sort => {
start_time => 1,
},
);
if ( $options->{round} ) {
@entries = map { $_->duration( round( $_->duration ) ); $_ } @entries;
}
if ( not @entries ) {
print "No Entries Found\n";
return;
}
if ( $options->{json} ) {
my $json = JSON::MaybeXS->new( pretty => 1, convert_blessed => 1 );
print $json->encode( \@entries );
} else {
$options->{from} = $days;
App::Jiffy::View::Timesheet::render( \@entries, $options );
}
}
sub run {
my $self = shift;
my @args = @_;
if ( $args[0] ) {
if ( $args[0] eq 'current' ) {
shift @args;
return $self->current_time(@args);
} elsif ( $args[0] eq 'timesheet' ) {
shift @args;
my $p = Getopt::Long::Parser->new( config => ['pass_through'], );
$p->getoptionsfromarray(
\@args,
'verbose' => \my $verbose,
'round' => \my $round,
'json' => \my $json
);
return $self->time_sheet( {
verbose => $verbose,
round => $round,
json => $json,
},
@args
( run in 1.145 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )