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 )