#=============================================================================== # # FILE: Config.pm # # DESCRIPTION: App:;Open::Config - basic configuration interface to App::Open # # FILES: --- # BUGS: --- # NOTES: --- # AUTHOR: Erik Hollensbe (), # COMPANY: # VERSION: 1.0 # CREATED: 06/02/2008 02:27:27 AM PDT # REVISION: --- #=============================================================================== package App::Open::Config; =head2 METHODS =over 4 =cut use strict; use warnings; use YAML::Syck; $YAML::Syck::ImplicitTyping = 1; =item new($config_file) Constructor, optionally takes the name of a config file; calls load_config() automatically. =cut sub new { my ( $class, $config_file ) = @_; my $self = bless { config_file => ( $config_file || "" ) }, $class; $self->load_config; return $self; } =item load_config() Loads the configuration (or resets it). If there is trouble reading the configuration, it will supply a default empty configuration. This call will die if the configuration is available, not undefined and does not evaluate to a hash. =cut sub load_config { my $self = shift; my $config; eval { $config = YAML::Syck::LoadFile( $self->{config_file} ) }; # load a default configuration if Syck fails us $self->{config} = $@ ? {} : ( $config || {} ); if ( !ref( $self->{config} ) || ref( $self->{config} ) ne 'HASH' ) { die "INVALID_CONFIGURATION"; } return; } =item load_backends(@backends) A frontend to load_backend(). Takes a list of backends to be processed in priority. =cut sub load_backends { my ( $self, @backends ) = @_; # # This is a lot more complex than I'd like, but it keeps the end-user # configuration tolerable. # # Basically, if the backend value is a hash, it passes the key to # load_backend() which will ferret the arguments out. The upside of this is # that it's trivial to configure one backend, but multiple backends cannot # guarantee ordering. The value associated with this key must be an array, # and will be used as the arguments for the backend. # # If the value is an array, it expects each array element to be a hash, # with the keys `name` and `args`, which represent the backend name and # arguments respectively. The `args` must be an array. The whole top-level # hash for the backend (the array element) is passed to load_backend(). # if ( exists( $self->config->{backend} ) and defined( $self->config->{backend} ) ) { if (ref( $self->config->{backend} )) { if (ref($self->config->{backend}) eq 'HASH') { foreach my $backend ( keys %{ $self->config->{backend} } ) { $self->load_backend($backend); } } elsif (ref($self->config->{backend}) eq 'ARRAY') { foreach my $backend (@{$self->config->{backend}}) { if (ref($backend) eq 'HASH') { $self->load_backend($backend); } } } } else { $self->load_backend( $self->config->{backend} ); } } if (@backends) { foreach my $backend (@backends) { $self->load_backend($backend); } } return; } =item load_backend($backend) Gets the parameters for the backend, name and arguments. Requires the module for the backend via require_backend() and on success, constructs an object from that module with the supplied arguments and stores it in the backend list. The $backend argument can either be a hashref or string, this is detailed in some comments in load_backends(). If the backend supplied cannot be loaded, it will die with NO_BACKEND_FOUND. =cut sub load_backend { my ( $self, $backend ) = @_; if (ref($backend) eq 'HASH') { if ($backend->{name}) { my $module = $self->require_backend($backend->{name}); if ($module) { my $obj = $module->new($backend->{args}); push @{ $self->backend_order }, $obj; return $module; } } } elsif (!ref($backend)) { my $module = $self->require_backend($backend); if ($module) { my $obj = $module->new( $self->config->{backend}{$backend} ); push @{ $self->backend_order }, $obj; return $module; } } die "NO_BACKEND_FOUND $backend"; } =item require_backend($backend) Attempts to use the module that corresponds to the backend name. This will try a couple of namespaces to load a backend: =over 4 =item App::Open::Backend:: =item "" (root namespace) =back On success, it will return the module name used. Otherwise, undef. =cut sub require_backend { my ($self, $backend) = @_; foreach my $backend_try ( "App::Open::Backend::", "" ) { my $module = "$backend_try$backend"; eval "use $module"; unless ($@) { return $module; } } return undef; } =item config() Convenience call to access the config hash. =cut sub config { $_[0]->{config} } =item config_file() Convenience call to access the config filename. =cut sub config_file { $_[0]->{config_file} } =item backend_order() Returns the lookup order of the various MIME backends as arrayref. In the instance that this does not already exist when it is called, a new, empty arrayref will be created and returned. =cut sub backend_order { my $self = shift; return $self->{backend_order} if ( $self->{backend_order} ); return $self->{backend_order} = []; } =back =cut 1;