Class-Usul

 view release on metacpan or  search on metacpan

lib/Class/Usul/Config.pm  view on Meta::CPAN

package Class::Usul::Config;

use namespace::autoclean;

use Class::Usul::Constants   qw( CONFIG_EXTN DEFAULT_CONFHOME
                                 DEFAULT_ENCODING DEFAULT_L10N_DOMAIN
                                 FALSE LANG NUL PERL_EXTNS PHASE TRUE );
use Class::Usul::File;
use Class::Usul::Functions   qw( app_prefix canonicalise class2appdir
                                 home2appldir is_arrayref split_on__
                                 split_on_dash untaint_cmdline
                                 untaint_identifier untaint_path );
use Class::Usul::Types       qw( ArrayRef DataEncoding HashRef NonEmptySimpleStr
                                 NonZeroPositiveInt PositiveInt Str );
use Config;
use English                  qw( -no_match_vars );
use File::Basename           qw( basename dirname );
use File::DataClass::Types   qw( Directory File Path );
use File::Gettext::Constants qw( LOCALE_DIRS );
use File::Spec::Functions    qw( canonpath catdir catfile
                                 rel2abs rootdir tmpdir );
use File::Which              qw( which );
use Scalar::Util             qw( blessed );
use Moo;

# Attribute constructors
my $_build_l10n_attributes = sub {
   return { %{ $_[ 0 ]->_l10n_attributes }, domains => $_[ 0 ]->l10n_domains, };
};

# Public attributes
has 'appclass'  => is => 'ro',   isa => NonEmptySimpleStr, required => TRUE;

has 'appldir'   => is => 'lazy', isa => Directory, coerce => TRUE;

has 'binsdir'   => is => 'lazy', isa => Path, coerce => TRUE;

has 'cfgfiles'  => is => 'lazy', isa => ArrayRef[NonEmptySimpleStr],
   builder      => sub { [] };

has 'ctlfile'   => is => 'lazy', isa => Path, coerce => TRUE;

has 'ctrldir'   => is => 'lazy', isa => Path, coerce => TRUE;

has 'datadir'   => is => 'lazy', isa => Path, coerce => TRUE;

has 'encoding'  => is => 'ro',   isa => DataEncoding, coerce => TRUE,
   default      => DEFAULT_ENCODING;

has 'extension' => is => 'lazy', isa => NonEmptySimpleStr,
   default      => CONFIG_EXTN;

has 'home'      => is => 'lazy', isa => Directory, coerce => TRUE,
   default      => DEFAULT_CONFHOME;

has 'locale'    => is => 'ro',   isa => NonEmptySimpleStr, default => LANG;

has 'localedir' => is => 'lazy', isa => Directory, coerce => TRUE;

has 'locales'   => is => 'ro',   isa => ArrayRef[NonEmptySimpleStr],
   builder      => sub { [ LANG ] };

has 'logfile'   => is => 'lazy', isa => Path, coerce => TRUE;

has 'logsdir'   => is => 'lazy', isa => Directory, coerce => TRUE;

has 'name'      => is => 'lazy', isa => NonEmptySimpleStr;

has 'no_thrash' => is => 'ro',   isa => NonZeroPositiveInt, default => 3;

has 'phase'     => is => 'lazy', isa => PositiveInt;

has 'prefix'    => is => 'lazy', isa => NonEmptySimpleStr,
   coerce       => sub { untaint_cmdline $_[ 0 ] };

has 'pathname'  => is => 'lazy', isa => File, coerce => TRUE;

has 'root'      => is => 'lazy', isa => Path, coerce => TRUE;

has 'rundir'    => is => 'lazy', isa => Path, coerce => TRUE;

has 'salt'      => is => 'lazy', isa => NonEmptySimpleStr;

has 'sessdir'   => is => 'lazy', isa => Path, coerce => TRUE;

has 'sharedir'  => is => 'lazy', isa => Path, coerce => TRUE;

has 'shell'     => is => 'lazy', isa => File, coerce => TRUE;

has 'suid'      => is => 'lazy', isa => Path, coerce => TRUE;

has 'tempdir'   => is => 'lazy', isa => Directory, coerce => TRUE;

has 'vardir'    => is => 'lazy', isa => Path, coerce => TRUE;

has 'l10n_attributes'  => is => 'lazy', isa => HashRef,
   builder             => $_build_l10n_attributes, init_arg => undef;

has 'l10n_domains'     => is => 'lazy', isa => ArrayRef[NonEmptySimpleStr],
   builder             => sub { [ DEFAULT_L10N_DOMAIN, $_[ 0 ]->name ] };

has '_l10n_attributes' => is => 'lazy', isa => HashRef,
   builder             => sub { {} }, init_arg => 'l10n_attributes';

has 'lock_attributes'  => is => 'ro',   isa => HashRef, builder => sub { {} };

has 'log_attributes'   => is => 'ro',   isa => HashRef, builder => sub { {} };

# Private functions
my $_is_inflated = sub {
   my ($attr, $attr_name) = @_;

   return exists $attr->{ $attr_name } && defined $attr->{ $attr_name }
       && $attr->{ $attr_name } !~ m{ \A __ }mx ? TRUE : FALSE;
};

my $_unpack = sub {
   my ($self, $attr) = @_; $attr //= {};

   blessed $self and return ($self, $self->{appclass}, $self->{home});

   return ($self, $attr->{appclass}, $attr->{home});
};

# Construction
around 'BUILDARGS' => sub {
   my ($orig, $self, @args) = @_; my $attr = $orig->( $self, @args );

   my $paths; if ($paths = $attr->{cfgfiles} and $paths->[ 0 ]) {
      my $loaded = Class::Usul::File->data_load( paths => $paths ) || {};

      $attr = { %{ $loaded }, %{ $attr } }; # Yes this way round. Leave it alone
   }

   for my $name (keys %{ $attr }) {
      defined $attr->{ $name }
          and $attr->{ $name } =~ m{ \A __([^\(]+?)__ \z }mx
          and $attr->{ $name } = $self->inflate_symbol( $attr, $1 );
   }

   $self->inflate_paths( $attr );

   return $attr;
};

sub _build_appldir {
   my ($self, $appclass, $home) = $_unpack->( @_ ); my $dir;

   $dir = home2appldir $home
      and $dir = rel2abs( untaint_path $dir )
      and -d catdir( $dir, 'lib' ) and return $dir;

   $dir = catdir( NUL, 'var', class2appdir $appclass )
      and $dir = rel2abs( untaint_path $dir )
      and -d $dir and return $dir;

   $dir = rel2abs( untaint_path $home ) and -d $dir and return $dir;

   return rel2abs( untaint_path rootdir );
}

sub _build_binsdir {
   my $dir = $_[ 0 ]->inflate_path( $_[ 1 ], 'appldir', 'bin' );

   return -d $dir ? $dir : untaint_path $Config{installsitescript};
}

lib/Class/Usul/Config.pm  view on Meta::CPAN


sub _build_tempdir {
   my $dir = $_[ 0 ]->inflate_path( $_[ 1 ], 'vardir', 'tmp' );

   return -d $dir ? $dir : untaint_path tmpdir;
}

sub _build_vardir {
   my $dir = $_[ 0 ]->inflate_path( $_[ 1 ], 'appldir', 'var' );

   return -e $dir ? $dir : $_[ 0 ]->inflate_path( $_[ 1 ], 'appldir' );
}

# Public methods
sub inflate_path {
   return canonicalise $_[ 0 ]->inflate_symbol( $_[ 1 ], $_[ 2 ] ), $_[ 3 ];
}

sub inflate_paths {
   my ($self, $attr) = @_; defined $attr or return;

   for my $name (keys %{ $attr }) {
      defined $attr->{ $name }
          and $attr->{ $name } =~ m{ \A __(.+?)\((.+?)\)__ \z }mx
          and $attr->{ $name } = $self->inflate_path( $attr, $1, $2 );
   }

   return;
}

sub inflate_symbol {
   my ($self, $attr, $symbol) = @_; $attr //= {}; defined $symbol or return;

   my $attr_name = lc $symbol; my $method = "_build_${attr_name}";

   return blessed $self                        ? $self->$attr_name()
        : $_is_inflated->( $attr, $attr_name ) ? $attr->{ $attr_name }
                                               : $self->$method( $attr );
}

1;

__END__

=pod

=head1 Name

Class::Usul::Config - Configuration class with sensible attribute defaults

=head1 Synopsis

   use Class::Usul::Constants qw( TRUE );
   use Class::Usul::Types     qw( ConfigType HashRef LoadableClass );
   use Moo;

   has 'config'       => is => 'lazy', isa => ConfigType, builder => sub {
      $_[ 0 ]->config_class->new( $_[ 0 ]->_config_attr ) },
      init_arg        => undef;

   has '_config_attr' => is => 'ro',   isa => HashRef, builder => sub { {} },
      init_arg        => 'config';

   has 'config_class' => is => 'ro',   isa => LoadableClass, coerce => TRUE,
      default         => 'Class::Usul::Config';

=head1 Description

Defines the configuration object. Attributes have sensible defaults that
can be overridden by values in configuration files which are loaded on
request

Pathnames passed in the L</cfgfiles> attribute are loaded and their contents
merged with the values passed to the configuration class constructor

=head1 Configuration and Environment

Defines the following list of attributes;

=over 3

=item C<appclass>

Required string. The classname of the application for which this is the
configuration class

=item C<appldir>

Directory. Defaults to the application's install directory

=item C<binsdir>

Directory. Defaults to the application's F<bin> directory. Prefers
L</appldir>F</bin> but defaults to L<Config>s C<installsitebin> attribute

=item C<cfgfiles>

An array reference of non empty simple strings. The list of configuration
files to load when instantiating an instance of the configuration class.
Defaults to an empty list

=item C<ctlfile>

File in the F<ctrldir> directory that contains this programs control data
The default filename is comprised of L</name> and L</extension>

=item C<ctrldir>

Directory containing the per program configuration files. Prefers F<var/etc>,
then L</appldir>F</etc> defaulting to F</usr/local/etc>

=item C<datadir>

Directory containing data files used by the application. Prefers F<var/data>
but defaults to L</tempdir>

=item C<encoding>

String default to the constant C<DEFAULT_ENCODING>

=item C<extension>



( run in 0.797 second using v1.01-cache-2.11-cpan-39bf76dae61 )