App-Chart

 view release on metacpan or  search on metacpan

lib/App/Chart.pm  view on Meta::CPAN

# Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2023, 2024 Kevin Ryde

# This file is part of Chart.
#
# Chart is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3, or (at your option) any later version.
#
# Chart is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with Chart.  If not, see <http://www.gnu.org/licenses/>.

package App::Chart;
use 5.010;
use strict;
use warnings;
use Carp;
use Date::Calc;
use File::Spec;
use List::Util qw(min max);
use POSIX qw(floor ceil);
use Regexp::Common 'whitespace';
use Scalar::Util;
use Locale::TextDomain;
use Locale::TextDomain ('App-Chart');
use Glib;

# uncomment this to run the ### lines
#use Smart::Comments;

our $VERSION = 275;

use Locale::Messages 1.16; # version 1.16 for turn_utf_8_on()
BEGIN {
  Locale::Messages::bind_textdomain_codeset ('App-Chart','UTF-8');
  Locale::Messages::bind_textdomain_filter ('App-Chart',
                                            \&Locale::Messages::turn_utf_8_on);
}
# sub chart_gettext_filter {
#   my ($str) = @_;
#   Locale::Messages::turn_utf_8_on ($str);
#   $str =~ s/^CONTEXT\(.*?\): *//;
#   return $str;
# }

# Return the user's ~/Chart directory, as an absolute path in filesystem
# charset encoding.
# Note not using Glib::get_home_dir() here, since it wrongly prefers 
# /etc/passwd file over $HOME.
use constant::defer chart_directory => sub {
  if (defined $ENV{'CHART_DIRECTORY'}) {
    return $ENV{'CHART_DIRECTORY'}
  } else {
    require File::HomeDir;
    my $home = File::HomeDir->my_home
      // die "No home directory can be found by File::HomeDir\n";
    return File::Spec->catdir($home, 'Chart');
  }
};

use constant::defer chart_dirbroadcast => sub {
  require App::Chart::Glib::Ex::DirBroadcast;
  return App::Chart::Glib::Ex::DirBroadcast->new
    (File::Spec->catdir(chart_directory(), 'broadcast'));
};

# force LC_NUMERIC to the locale, whereas perl normally runs with "C"
use constant::defer number_formatter => sub {
  require Number::Format;
  my $oldlocale = POSIX::setlocale(POSIX::LC_NUMERIC());
  POSIX::setlocale (POSIX::LC_NUMERIC(), "");
  my $nf = Number::Format->new;
  POSIX::setlocale (POSIX::LC_NUMERIC(), $oldlocale);
  return $nf;
};

use constant { UP_COLOUR   => 'light green',
                 DOWN_COLOUR => 'pink',
                 BAND_COLOUR => 'blue',
                 GREY_COLOUR => 'grey' };

#------------------------------------------------------------------------------

our %option
  = (verbose => 0,
     d_fmt   => do {
       # langinfo D_FMT if available, otherwise fallback to a neutral YYYY-MM-DD
       eval {
         require I18N::Langinfo;
         require I18N::Langinfo::Wide;
         I18N::Langinfo::Wide::langinfo(I18N::Langinfo::D_FMT())
         }
         || '%Y-%m-%d'
       },
     http_get_cost => 3000,
    );
$option{'wd_fmt'} = __x('%a {d_fmt}', d_fmt => $option{'d_fmt'});



#------------------------------------------------------------------------------

sub symbol_sans_suffix {
  my ($symbol) = @_;
  return ($symbol =~ /(.*)\./ ? $1 : $symbol);
}

lib/App/Chart.pm  view on Meta::CPAN

}
sub ymd_to_tdate_ceil {
  my ($year, $month, $day) = @_;
  return adate_to_tdate_ceil (ymd_to_adate ($year, $month, $day));
}


#------------------------------------------------------------------------------

sub collapse_whitespace {
  my ($str) = @_;
  $str =~ s/\x{A0}+/ /g;       # latin1/unicode non-breaking space
  $str =~ s/$RE{ws}{crop}//g;  # leading and trailing whitespace
  $str =~ s/\s+/ /g;           # middle whitespace
  return $str;
}

#------------------------------------------------------------------------------

sub decimal_sub {
  my ($x, $y) = @_;
  # would prefer an actual decimal-arithmetic subtract here
  my $decimals = max (count_decimals($x), count_decimals($y));
  return sprintf ('%.*f', $decimals, $x - $y);
}

#------------------------------------------------------------------------------

sub count_decimals {
  my ($str) = @_;
  my $pos = index ($str, '.');
  if ($pos >= 0) {
    return length($str) - $pos - 1;
  } else {
    return 0;
  }
}

#------------------------------------------------------------------------------

# Return min or max of the arguments, ignoring any undefs.
# If no args (no undefs that is) then return undef.
# List::Util min() and max() return undef for no args, but they want all args
# to be numeric.
#
sub min_maybe {
  return min (grep {defined} @_);
}
sub max_maybe {
  return max (grep {defined} @_);
}

#------------------------------------------------------------------------------

# App::Chart::datafilename ($filename)
# App::Chart::datafilename ($dir,...,$dir, $filename)
#
# Return an absolute path like /usr/share/perl5/App/Chart/$filename,
# wherever App/Chart/$filename is found in @INC.  $dir arguments specify a
# subdirectory like App/Chart/$dir1/$dir2/$filename.  All args and the
# return are in filesystem charset bytes.
#
# Module::Find and Module::Util have similar @INC searches, but only for .pm
# files it seems.
#
sub datafilename {
  foreach my $inc (@INC) {
    my $filename = File::Spec->catfile ($inc, 'App', 'Chart', @_);
    if (-e $filename) { return $filename; }
  }
  require File::Basename;
  return File::Spec->catfile (File::Basename::dirname($INC{'App/Chart.pm'}),
                              'Chart', @_);
}

# return true if range ($alo,$ahi) overlaps range ($blo,$bhi)
# each endpoint is taken as inclusive, so say (1,4) and (4,7) do overlap
#
sub overlap_inclusive_p {
  my ($alo, $ahi, $blo, $bhi) = @_;
  return ! ($ahi < $blo || $alo > $bhi);
}

1;
__END__

=head1 NAME

App::Chart -- various shared Chart things

=head1 SYMBOL FUNCTIONS

=over 4

=cut

=item C<< %App::Chart::option >>

Various program options.

=over 4

=item C<verbose> (default false)

Print more things (mainly during downloads).  This is the C<--verbose>
command line option.

=item C<d_fmt> (default from C<langinfo()>)

C<strftime> format string for a date.  Non-ASCII can be included as Perl
wide-chars.

The default is from C<langinfo(D_FMT)> if the L<I18N::Langinfo> and
L<I18N::Langinfo::Wide> modules are available.  Otherwise the default is
C<%Y-%m-%d> which gives an ISO style YYYY-MM-DD.

=item C<wd_fmt> (default C<%a> and C<d_fmt>)

C<strftime> format string for a weekday name and date.

=item C<http_get_cost> (default 3000)



( run in 3.081 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )