App-JobLog
view release on metacpan or search on metacpan
lib/App/JobLog/Config.pm view on Meta::CPAN
$App::JobLog::Config::VERSION = '1.042';
# ABSTRACT: central depot for App::JobLog configuration parameters and controller allowing their modification
use Exporter 'import';
our @EXPORT_OK = qw(
columns
day_length
dir
editor
hidden_columns
init_file
is_hidden
is_workday
log
merge
pay_period_length
precision
readme
start_pay_period
sunday_begins_week
time_zone
_tz
vacation
workdays
DAYS
DIRECTORY
HIDABLE_COLUMNS
HOURS
MERGE
NONE_COLUMN
PERIOD
PRECISION
SUNDAY_BEGINS_WEEK
TIME_ZONE
WORKDAYS
);
use Class::Autouse qw{
File::HomeDir
File::Spec
Config::Tiny
FileHandle
App::JobLog::Command::info
};
use autouse 'File::Path' => qw(mkpath);
use autouse 'Cwd' => qw(abs_path);
use autouse 'Term::ReadKey' => qw(GetTerminalSize);
use Modern::Perl;
# default precision
use constant PRECISION => 2;
# default pay period
use constant PERIOD => 14;
# hours worked in day
use constant HOURS => 8;
# whether Sunday is the first day of the week
# otherwise it's Monday, as in DateTime
use constant SUNDAY_BEGINS_WEEK => 1;
# environment variables
# identifies directory to write files into
use constant DIRECTORY => 'JOB_LOG_DIRECTORY';
# expected abbreviations for working days in week
use constant WORKDAYS => 'MTWHF';
# expected abbreviations for weekdays
use constant DAYS => 'S' . WORKDAYS . 'A';
# default level of merging
use constant MERGE => 'adjacent same tags';
# name of hide nothing "column"
use constant NONE_COLUMN => 'none';
# array of hidable columns
use constant HIDABLE_COLUMNS => [
NONE_COLUMN, qw(
date
description
duration
tags
time
)
];
# default time zone; necessary because Cygwin doesn't support local
use constant TIME_ZONE => $^O eq 'cygwin' ? 'floating' : 'local';
sub init_file {
my ($path) = @_;
unless ( -e $path ) {
my ( $volume, $directories, $file ) = File::Spec->splitpath($path);
my $dir = File::Spec->catfile( $volume, $directories );
mkpath( $dir, { verbose => 0, mode => 0711 } ) unless -d $dir;
unless ( -e readme() ) {
my $fh = FileHandle->new( readme(), 'w' )
or die 'could not create file ' . readme();
my $executable = abs_path($0);
# to protect against refactoring
my $command = App::JobLog::Command::info->name;
print $fh <<END;
Job Log
This directory holds files used by Job Log to maintain
a work log. For more details type
$executable $command
on the command line.
END
$fh->close;
lib/App/JobLog/Config.pm view on Meta::CPAN
my $vacation_file;
sub vacation {
$vacation_file ||= File::Spec->catfile( dir(), 'vacation' );
return $vacation_file;
}
# configuration object and whether any changes need to be written to this file
my ( $config, $config_changed );
END {
if ($config_changed) {
init_file( _config_file() );
$config->write( _config_file() );
}
}
# construct configuration object as necessary
sub _config {
unless ($config) {
my $f = _config_file();
$config = -e $f ? Config::Tiny->read($f) : Config::Tiny->new;
}
return $config;
}
sub precision {
my ($value) = @_;
return _param( 'precision', PRECISION, 'summary', $value );
}
sub merge {
my ($value) = @_;
return _param( 'merge', MERGE, 'summary', $value );
}
sub day_length {
my ($value) = @_;
return _param( 'day-length', HOURS, 'time', $value );
}
sub pay_period_length {
my ($value) = @_;
return _param( 'pay-period-length', PERIOD, 'time', $value );
}
sub sunday_begins_week {
my ($value) = @_;
return _param( 'sunday-begins-week', SUNDAY_BEGINS_WEEK, 'time', $value );
}
sub start_pay_period {
my ($value) = @_;
require DateTime;
if ( ref $value eq 'DateTime' ) {
$value = sprintf '%d %d %d', $value->year, $value->month, $value->day;
}
$value = _param( 'start-pay-period', undef, 'time', $value );
if ($value) {
my @parts = split / /, $value;
return DateTime->new(
year => $parts[0],
month => $parts[1],
day => $parts[2],
time_zone => _tz(),
);
}
return;
}
# abstracts out code for maintaining config file
sub _param {
my ( $param, $default, $section, $new_value ) = @_;
$section ||= 'main';
my $config = _config();
my $value = $config->{$section}->{$param};
if ( defined $new_value ) {
if ( defined $default && $new_value eq $default && !defined $value ) {
return $new_value;
}
return $value if defined $value && $value eq $new_value;
$config_changed = 1;
return $config->{$section}->{$param} = $new_value;
}
else {
return defined $value ? $value : $default;
}
}
sub editor {
my ($value) = @_;
$value = _param( 'editor', undef, 'external', $value );
return $value;
}
sub columns {
my ($cols) = GetTerminalSize;
$cols ||= 76;
return $cols;
}
sub workdays {
my ($value) = @_;
return _param( 'workdays', WORKDAYS, 'time', $value );
}
my %workdays;
sub is_workday {
my ($date) = @_;
# initialize map
unless (%workdays) {
my @days = split //, DAYS;
# move Sunday into DateTime's expected position
push @days, shift @days;
my %day_map;
for ( 0 .. $#days ) {
$day_map{ $days[$_] } = $_ + 1;
}
for ( split //, workdays() ) {
$workdays{ $day_map{$_} } = 1;
}
}
return $workdays{ $date->day_of_week };
}
sub hidden_columns {
my ($value) = @_;
return _param( 'hidden_columns', NONE_COLUMN, 'summary', $value );
}
my %hidden_columns;
sub is_hidden {
my ($value) = @_;
unless (%hidden_columns) {
%hidden_columns = map { $_ => 1 } split / /, hidden_columns();
}
return $hidden_columns{$value};
}
sub time_zone {
my ($value) = @_;
return _param( 'time_zone', TIME_ZONE, 'time', $value );
}
our $tz;
# removed from App::JobLog::Time to prevent dependency cycle
sub _tz {
if ( !defined $tz ) {
require DateTime::TimeZone;
eval { $tz = DateTime::TimeZone->new( name => time_zone() ) };
if ($@) {
print STDERR 'DateTime::TimeZone doesn\'t like the time zone '
. time_zone()
. "\nreverting to floating time\n full error: $@";
$tz = DateTime::TimeZone->new( name => 'floating' );
}
}
return $tz;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
App::JobLog::Config - central depot for App::JobLog configuration parameters and controller allowing their modification
=head1 VERSION
version 1.042
=head1 DESCRIPTION
C<App::JobLog::Config> is a central repository for program state that may be conserved from
session to session. It also serves as a general interface between the program and the machine.
This wasn't written to be used outside of C<App::JobLog>.
=head1 METHODS
=head2 init_file
C<init_file> manages configuration files. It ensures that the
working directory and the README file exist before
we try to create or modify any files in the working directory.
=head2 dir
Working directory.
=head2 log
Log file.
=head2 readme
README file.
=head2 vacation
Obtain the file in which vacation information is stored.
=head2 precision
Obtain the number of decimal places represented when displaying the duration
of events.
=head2 day_length
The number of hours one is expected to work in a day.
=head2 pay_period_length
The number of days between paychecks.
=head2 sunday_begins_week
Whether to regard Sunday or Monday as the first day in the week
when interpreting time expressions such as 'last week'. L<DateTime>
uses Monday. The default for L<App::JobLog> is Sunday. For the purposes
of calculating hours worked this will make no difference for most people.
=head2 start_pay_period
Returns DateTime representing start date of pay period or null if none is defined.
=head2 editor
Log editing program.
=head2 columns
The number of columns available in the terminal. This defaults to
76 when L<Term::ReadKey> is unable to determine terminal width.
=head2 workdays
The days of the week when one expects to be working.
=head2 is_workday
Returns whether a particular L<DateTime> object represents a workday.
=head2 hidden_columns
Returns those columns never displayed by summary command.
=head2 is_hidden
Whether a particular column is among those hidden.
=head2 time_zone
Time zone used for time calculations.
=head1 AUTHOR
David F. Houghton <dfhoughton@gmail.com>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2011 by David F. Houghton.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
( run in 0.785 second using v1.01-cache-2.11-cpan-39bf76dae61 )