view release on metacpan or search on metacpan
lib/Activator/Config.pm view on Meta::CPAN
# make sure we can use ENV vars
my $skip_env = $ENV{ACT_CONFIG_skip_env};
$realm ||=
$self->{ARGV}->{realm} ||
( $skip_env ? undef : $ENV{ACT_CONFIG_realm} ) ||
'default';
if ( ref( $realm ) ) {
Activator::Exception::Config->throw( 'realm_specified_more_than_once', Dumper( $realm ) );
}
if ( $realm ne 'default' ) {
Activator::Registry->set_default_realm( $realm );
}
# setup or get the merged YAML configuration settings from files
# into the registry
my $config = $self->{REGISTRY}->get_realm( $realm );
# first call
if ( !keys %$config ) {
# define valid config from config files
try eval {
$self->_process_config_files( $realm, $skip_env, $project_is_arg );
};
if ( catch my $e ) {
$e->rethrow;
}
# read environment variables, set any keys found
if ( !$skip_env ) {
my ( $env_key, $env_realm );
foreach my $env_key ( keys %ENV ) {
next unless $env_key =~ /^ACT_CONFIG_(.+)/;
$opt_key = $1;
$opt_realm = $realm;
lib/Activator/Config.pm view on Meta::CPAN
return;
}
if ( $arg eq '--' ) {
return $arg;
}
my ( $key, $value ) = split /=/xms, $arg, 2;
if ( !defined $key ) {
Activator::Exception::Config->throw( 'argument',
'invalid',
$arg );
}
# clean up key
$key =~ s/^--?//;
# clean up value, if quoted
if ( defined $value ) {
$value =~ s/^"//;
lib/Activator/Config.pm view on Meta::CPAN
# Merge config files into this objects Activator::Registry object
sub _process_config_files {
my ( $pkg, $realm, $skip_env, $project_is_arg ) = @_;
my $self = &new( @_ );
# figure out what project we are working on
my $project =
$self->{ARGV}->{project} ||
( $project_is_arg ? $self->{BAREWORDS}->[-1] : undef ) ||
( $skip_env ? undef : $ENV{ACT_CONFIG_project} ) ||
Activator::Exception::Config->throw( 'project', 'missing' );
# process these files:
# $ENV{USER}.yml
# <realm>.yml - realm specific settings and defaults
# <project>.yml - project specific settings and defaults
# org.yml - top level organization settings and defaults
# in one of these paths, if set
# --conf_file= : use $self->{ARGV}->{conf_file} (which could be an arrayref )
# ACT_CONFIG_conf_file= : comma separated list of files
my $conf_path = $self->{ARGV}->{conf_path};
if ( ! $conf_path ) {
$conf_path = ( $skip_env ? undef : $ENV{ACT_CONFIG_conf_path} );
if ( !$conf_path ) {
ERROR( "Neither ACT_CONFIG conf_path env var nor --conf_path set");
Activator::Exception::Config->throw( 'conf_path', 'missing' );
}
else {
INFO( "Using ACT_CONFIG_conf_path env var: $conf_path");
}
}
else {
INFO( "Using conf_path argument: $conf_path");
}
my @search_paths = split ':', $conf_path;
lib/Activator/Config.pm view on Meta::CPAN
# now that we have all the files, import 'em! This is a super long
# winded but safe "left precedence" merge of all files
my ( $user_config, $realm_config, $project_config, $org_config );
try eval {
if ( exists( $files->{user}->{file} ) ) {
$user_yml = YAML::Syck::LoadFile( $files->{user}->{file} );
}
};
if ( catch my $e ) {
Activator::Exception::Config->throw( 'user_config', 'invalid', $e );
}
try eval {
if ( exists( $files->{realm}->{file} ) ) {
$realm_yml = YAML::Syck::LoadFile( $files->{realm}->{file} );
}
};
if ( catch my $e ) {
Activator::Exception::Config->throw( 'realm_config', 'invalid', $e );
}
try eval {
if ( exists( $files->{project}->{file} ) ) {
$project_yml = YAML::Syck::LoadFile( $files->{project}->{file} );
}
};
if ( catch my $e ) {
Activator::Exception::Config->throw( 'project_config', 'invalid', $e );
}
try eval {
if ( exists( $files->{org}->{file} ) ) {
$org_yml = YAML::Syck::LoadFile( $files->{org}->{file} );
}
};
if ( catch my $e ) {
Activator::Exception::Config->throw( 'org_config', 'invalid', $e );
}
if ( $realm ne 'default' ) {
if ( defined( $user_yml ) && exists( $user_yml->{ $realm } ) ) {
$self->{REGISTRY}->register_hash( 'left', $user_yml->{ $realm }, $realm );
DEBUG('Registered: ' . $files->{user}->{file} . " for realm $realm" );
}
if ( defined( $realm_yml ) && exists( $realm_yml->{ $realm } ) ) {
$self->{REGISTRY}->register_hash( 'left', $realm_yml->{ $realm }, $realm );
lib/Activator/Config.pm view on Meta::CPAN
if ( defined( $org_yml ) && exists( $org_yml->{overrides} ) ) {
$self->{REGISTRY}->register_hash( 'left', $org_yml->{overrides}, 'overrides' );
DEBUG('Registered: ' . $files->{org}->{file} . " overrides" );
}
# make sure all is kosher
my $test = $self->{REGISTRY}->get_realm( $realm );
if ( !keys %$test ) {
DEBUG( Data::Dumper->Dump( [ $self->{REGISTRY} ], [ qw/ registry / ] ) );
ERROR( "After processing, '$realm' realm should not be empty, but it is!");
Activator::Exception::Config->throw('realm', 'empty', $realm);
}
}
# Override any options in $config with the values in $argv. Sets non-existent keys.
#
# Arguments:
# $config : hashref to the options for $realm
# $argv : arrayref to command line arguments. All recognized options are removed.
#
sub _argv_override {
lib/Activator/DB.pm view on Meta::CPAN
$self->{last_alias} = $self->{cur_alias};
$self->{cur_alias} = $self->{default}->{connection};
}
my $conn;
try eval {
$conn = $self->_get_cur_conn();
};
if ( catch my $e ) {
$self->{cur_alias} = $self->{last_alias};
$e->rethrow;
}
# est. the actual connection if it's not set
if ( !$conn->{dbh} ) {
try eval {
$self->_debug_connection( 2, "Connecting to alias $self->{cur_alias}" );
$self->_debug_connection( 2, 'Connect Parameters:');
$self->_debug_connection( 2, " dsn => $conn->{dsn}");
$self->_debug_connection( 2, " user => $conn->{user}");
lib/Activator/DB.pm view on Meta::CPAN
try eval {
$conn->{dbh} = DBI->connect( $conn->{dsn},
$conn->{user} || '',
$conn->{pass} || '',
$conn->{attr}
);
};
if ( catch my $e ) {
Activator::Exception::DB->throw( 'dbh',
'connect',
"$e " .
Data::Dumper->Dump( [ $conn ], [ 'connection' ] )
);
}
# TODO: do something more generic with this
# mysql_auto_reconnect now cannot be disconnected
if ( $conn->{dsn} =~ /mysql/i ) {
$conn->{dbh}->{mysql_auto_reconnect} = $self->{config}->{mysql}->{auto_reconnect};
}
elsif ( my $search_path = $conn->{config}->{Pg}->{search_path} ) {
$self->do("SET search_path TO ?", [ $search_path ]);
}
# test cur_alias $conn->{dbh}, may throw exception
$self->_ping();
$self->_debug_connection( 2, "alias '$conn->{alias}' db handle pinged and ready for action");
};
if ( catch my $e ) {
$e->rethrow;
}
}
return $self;
}
sub _init {
my ( $self ) = @_;
$self->_start_timer();
my $setup = Activator::Registry->get( 'Activator::DB' );
if (!keys %$setup ) {
$setup = Activator::Registry->get( 'Activator->DB' );
if (!keys %$setup ) {
Activator::Exception::DB->throw( 'activator_db_config', 'missing', 'You must define the key "Activator::DB" or "Activator->DB" in your project configuration' );
}
}
# module defaults
$self->{config} = { debug => 0,
debug_connection => 0,
debug_attr => 0,
reconn_att => 3,
reconn_sleep => 1,
mysql => { auto_reconnect => 1 },
lib/Activator/DB.pm view on Meta::CPAN
PrintError => 0,
HandleError => Exception::Class::DBI->handler,
AutoCommit => 1,
};
$self->{connections} = {};
# setup the current alias key
$self->{cur_alias} =
$self->{default}->{connection} =
$setup->{default}->{connection} ||
Activator::Exception::DB->throw( 'connect',
'config',
'default: connection not set!'
);
# setup default attributes. NOTE: even though we only support
# AutoCommit, this block can easily be extended for other
# attributes.
foreach my $key ( 'AutoCommit' ) {
my $value = $setup->{default}->{attr}->{ $key };
$self->{ $key } =
lib/Activator/DB.pm view on Meta::CPAN
try eval { $dbh->ping(); };
if ( catch my $e ) {
$reconn_att--;
sleep $reconn_sleep;
$reconn_sleep *= 2;
} else {
return 1;
}
}
ERROR( "connection to $conn->{alias} appears to be dead" );
Activator::Exception::DB->throw( 'ping', 'failure' );
}
# _get_cur_conn
#
# return the internal connection hash for the current connection alias
sub _get_cur_conn {
my ( $self ) = @_;
if ( exists( $self->{connections}->{ $self->{cur_alias} } ) ) {
my $conn = $self->{connections}->{ $self->{cur_alias} };
# # set the log level to this connection
# LEVEL( $conn->{config}->{debug}
# ? $Log::Log4perl::$self->_debug
# : $Log::Log4perl::WARN );
return $conn;
}
Activator::Exception::DB->throw('alias', 'invalid', $self->{cur_alias} )
}
# explode args for a db query sub
sub _explode {
my ( $pkg, $bindref, $args ) = @_;
my $bind = $bindref || [];
my $self = $pkg;
my $connect_to = $args->{connect};
# handle static calls
if ( !( Scalar::Util::blessed($self) && $self->isa( 'Activator::DB') ) ) {
if ( $connect_to ) {
$self = Activator::DB->connect( $connect_to );
}
else {
Activator::Exception::DB->throw( 'connect', 'missing');
}
}
# static or OO, respect the connect
if ( $connect_to ) {
$self->{cur_alias} = $connect_to;
}
# This next line insures that $self refers to the singleton object
$self = $self->connect( $self->{cur_alias} );
my $conn = $self->_get_cur_conn()
or Activator::Exception::DB->throw( 'connection',
'failure',
"_explode couldn't get connection for alias '$self->{cur_alias}'");
my $attr = $args->{attr} || {};
return ( $self, $bind, $attr );
}
# This can never die, so we jump through hoops to return some valid scalar.
# * replace undef values with NULL, since this is how dbi will do it
lib/Activator/DB.pm view on Meta::CPAN
try eval {
$sth = $conn->{dbh}->prepare_cached( $sql, $attr );
};
if ( catch my $e ) {
$self->_ping();
try eval {
$sth = $conn->{dbh}->prepare_cached( $sql, $attr );
};
if ( catch my $e ) {
Activator::Exception::DB->throw( 'sth',
'prepare',
$e . " SQL: " .
$self->_get_sql( $sql, $bind )
);
}
}
my $res;
try eval {
$res = $sth->execute( @$bind );
};
if ( catch my $e ) {
Activator::Exception::DB->throw( 'sth',
'execute',
$e . " SQL: " .
$self->_get_sql( $sql, $bind )
);
}
if ( $want_exec_result ) {
$sth->finish();
return $res;
}
lib/Activator/DB.pm view on Meta::CPAN
$self->_start_timer();
my $conn = $self->_get_cur_conn();
my ( $sth, $e );
try eval {
$sth = $self->_get_sth( $sql, $bind, $attr );
};
if ( catch my $e ) {
$e->rethrow;
}
my ( @row, $row, $rows );
if ( $fn eq 'getrow') {
try eval {
@row = $sth->fetchrow_array();
$sth->finish();
};
}
elsif ( $fn eq 'getrow_arrayref' ) {
lib/Activator/DB.pm view on Meta::CPAN
};
}
elsif ( $fn eq 'getall_hashrefs' ) {
try eval {
$row = $sth->fetchall_arrayref( {} );
$sth->finish();
};
}
if ( catch my $e ) {
Activator::Exception::DB->throw( 'sth',
'fetch',
$e .
$self->_get_sql( $sql, $bind )
);
}
# clean up return value for total consistency.
if ( !defined( $row ) ) {
if ( $fn eq 'getrow_hashref' ) {
lib/Activator/DB.pm view on Meta::CPAN
my ( $self, $bind, $attr ) = $pkg->_explode( $bindref, \%args );
my $conn = $self->_get_cur_conn();
$self->_start_timer();
my $res;
try eval {
$res = $self->_get_sth( $sql, $bind, $attr, 'want_exec_result' );
};
if ( catch my $e ) {
$e->rethrow;
}
$self->_debug_sql( 4, $sql, $bind, \%args );
if ( $res == 1 ) {
if ( $conn->{engine} eq 'mysql' ) {
return $conn->{dbh}->{mysql_insertid};
}
elsif ( $conn->{engine} eq 'Pg' ) {
my $row = $self->getrow_arrayref( "SELECT currval('$args{seq}')" );
return @$row[0];
}
} else {
Activator::Exception::DB->throw('execute',
'failure',
$self->_get_sql( $sql, $bind ) .
" did not cause an insert"
);
}
}
sub do {
my ( $pkg, $sql, $bindref, %args ) = @_;
my ( $self, $bind, $attr, $alt_error ) = $pkg->_explode( $bindref, \%args );
my $conn = $self->_get_cur_conn();
$self->_start_timer();
my $res;
try eval {
$res = $conn->{dbh}->do( $sql, $attr, @$bind );
};
if ( catch my $e ) {
$e->rethrow;
}
$self->_debug_sql( 4, $sql, $bind, \%args );
if ( $res eq '0E0' ) {
return 0;
}
return $res;
}
lib/Activator/DB.pm view on Meta::CPAN
sub rollback {
my ( $self ) = @_;
my $conn = $self->_get_cur_conn();
try eval {
$conn->{dbh}->rollback;
};
catch my $e;
$conn->{dbh}->{AutoCommit} = 1;
if ( $e ) {
$e->rethrow;
}
}
sub as_string {
my ( $pkg, $sql, $bind ) = @_;
return Activator::DB->_get_sql( $sql, $bind );
}
sub _start_timer {
my ( $self ) = @_;
lib/Activator/DB.pm view on Meta::CPAN
# catch the error
}
We highly recommend (and use extensively)
L<Exception::Class::TryCatch> which allows this syntactic sugar:
try eval {
Activator::DB->query_method( $sql, $bind, @args );
};
if ( catch my $e ) {
# rethrow, throw a new error, print something, AKA: handle it!
}
Errors Thrown:
connection failure - could not connect to database
sql missing - query sub called without 'sql=>' argument
connect missing - static call without 'connect=>' argument
prepare failure - failure to $dbh->prepare
execute failure - failure to $dbh->execute
alias_config missing - connection alias has no configuration
lib/Activator/DB.pm view on Meta::CPAN
##
## =cut
##
## sub getcol_arrayref {
## my ( $sql, $bind, $colsref ) = @_;
##
## $self->{debug_start} = [ gettimeofday ];
##
## my $colref;
##
## my $dbh = &get_dbh(); # may throw connect.failure
##
## eval {
## $colref
## = $dbh->selectcol_arrayref( $sql, { Columns => $colsref },
## @$bind );
## };
## if ( $@ ) {
## Activator::Exception::DB->throw( 'dbi', 'failure', $dbh->errstr || $@);
## }
##
## $self->_get_query_debug( 'getcol_arrayref', @_ );
##
## return $colref;
## }
##
## =item B<getall_hr>($sql, $bind, $key_field)
##
## Prepare and Execute a SQL statement on the default database, and
lib/Activator/Dictionary.pm view on Meta::CPAN
$dict->lookup( "$key_prefix.$col" ); # succeeds
For this reason, it is required that you not use period in the
C<key_prefix> column.
=head2 Failure Mode
Instead of returning undef for non-existent keys, you can configure
this module to fail via one or more of these methods:
die : throws Activator::Exception::Dictionary('key', 'missing')
key : returns the requested key itself
'' : returns empty string
<lang> : return the value for <lang> in the requested realm
<realm> : return the value for <realm>
Examples:
$db->lookup( $key, $realm1 ); # value does not exist
fail_mode: [ realm2, de, key ]
return value for $key in realm2 if it exists
return value for $key in realm1 in german if it exists
return $key
fail_mode: [ realm2, die ]
return value for $key in realm2 if it exists
throw Activator::Exception::Dictionary
fail_mode: [ realm2, realm3 ]
return value for $key in realm2 if it exists
return value for $key in realm3 if it exists
return undef (fallback to default failure mode)
fail_mode: [ '' ]
return empty string
lib/Activator/Dictionary.pm view on Meta::CPAN
$dict->lookup( $key2, $realm );
Static Usage:
Activator::Dictionary->use_lang( $lang );
Activator::Dictionary->lookup( $key, $realm );
Activator::Dictionary->lookup( $key2, $realm );
Returns the value for C<$key> in C<$realm>. Returns C<undef> when the
key does not exist, but you can configure this module to do something
different (see L<Failure Mode> below). If realm does not exist, throws
C<Activator::Exception::Dictionary> no matter the failure mode.
=cut
sub lookup {
my ($pkg, $key, $realm ) = @_;
my $self = &get_dict( $pkg );
my $lang = $self->{cur_lang};
$realm ||= $self->{config}->{default_realm};
if ( !defined( $key ) ) {
Activator::Exception::Dictionary->throw( 'key', 'undefined');
}
if ( !exists( $self->{ $lang }->{ $realm } ) ) {
Activator::Exception::Dictionary->throw( 'realm', 'undefined', $realm);
}
if ( exists( $self->{ $lang }->{ $realm }->{ $key } ) ) {
my $ret = $self->{ $lang }->{ $realm }->{ $key };
DEBUG( "Found key '$key'. value: $ret");
return $ret;
}
# At this point, there was no value for the given key in the given
# realm. Honor configured failure mode.
lib/Activator/Dictionary.pm view on Meta::CPAN
}
my %tried = ( $lang => 1, $realm => 1 );
my @modes = @{ $self->{config}->{fail_mode} };
DEBUG( "Trying modes: ". Dumper( \@modes ) );
foreach my $mode ( @modes ) {
next if $tried{ $mode };
$tried{ $mode } = 1;
DEBUG( "Trying fail_mode '$mode'");
if ( $mode eq 'die' ) {
DEBUG( "die means throw exception");
Activator::Exception::Dictionary->throw('key', 'missing');
}
if ( $mode eq '' ) {
DEBUG( "returning empty string");
return '';
}
if ( $mode eq 'key' ) {
DEBUG( "returning key '$key'");
return $key;
lib/Activator/Dictionary.pm view on Meta::CPAN
}
DEBUG( "No valid fail_mode found. Returning undef");
return;
}
=head2 get_dict( $lang )
Returns a reference to the Activator::Dictionary object. Sets all
future lookups to use the $lang passed in. If $lang is not passed in,
uses 'Activator::Dictionary' registry value for 'default_lang'. If
$lang cannot be determined, throws Activator::Exception::Dictionary.
=cut
sub get_dict {
my ($pkg, $lang ) = @_;
my $self = &new( @_ );
# first call
if( !exists $self->{config} ) {
$self->_init_config();
}
# first call for $lang
$lang ||= $self->{cur_lang} || $self->{config}->{default_lang};
if ( !$lang ) {
Activator::Exception::Dictionary->throw( 'lang', 'undefined' );
}
if( !exists $self->{ $lang } ) {
try eval {
$self->_init_lang( $lang );
};
if ( catch my $e ) {
Activator::Exception::Dictionary->throw( 'init_lang', 'failed', $e );
}
}
$self->{cur_lang} = $lang;
return $self;
}
=head2 new( $lang )
lib/Activator/Dictionary.pm view on Meta::CPAN
$self->{config}->{default_realm} = $config->{default_realm} || 'default';
$self->{config}->{default_lang} = $config->{default_lang} || 'en';
$self->{config}->{dict_tables} = $config->{dict_tables};
$self->{config}->{dict_files} = $config->{dict_files};
$self->{config}->{db_alias} = $config->{db_alias};
$self->{config}->{fail_mode} = $config->{fail_mode};
if ( !( defined( $self->{config}->{dict_files} ) ||
defined( $self->{config}->{dict_tables} )
) ) {
Activator::Exception::Dictionary->throw( 'tables_or_files', 'undefined' );
}
if ( defined( $self->{config}->{dict_tables} ) &&
!defined( $self->{config}->{db_alias} ) ) {
Activator::Exception::Dictionary->throw( 'db_alias', 'missing' );
}
}
sub _init_lang {
my ($self, $lang) = @_;
my $processed = 0;
# import all the realms for this language from the db
if ( defined( $self->{config}->{dict_tables} ) ) {
my ( $sql, $rows, $row, $col, $realm, $key );
foreach my $table ( @{ $self->{config}->{dict_tables} } ) {
$sql = "SELECT * FROM $table WHERE lang = ?";
try eval {
$rows = Activator::DB->getall_hashrefs( $sql, [ $lang ], connect => 'def' );
};
if ( catch my $e ) {
Activator::Exception::Dictionary->throw( 'dict_tables',
'misconfigured',
"Activator::Dictionary caught: \n$e" );
}
foreach $row ( @$rows ) {
foreach $col ( keys %$row ) {
if ( $col !~/_id$|realm|lang|key_prefix|last_modified/ ) {
$realm = $row->{realm};
$key = "$row->{key_prefix}.$col";
if ( exists( $self->{ $lang }->{ $realm }->{ $key } ) ) {
local $Log::Log4perl::caller_depth;
lib/Activator/Dictionary.pm view on Meta::CPAN
my @files = grep { /^[^\.]/ && -f "$dir_loc/$_" } readdir(DIR);
closedir DIR;
my ($file, $realm, $key, $value);
foreach $file ( @files ) {
if ( $file !~ /.dict$/ ) {
WARN("Non-dictionary file '$file' found in lang dir $dir_loc");
next;
}
open DICT, "<$dir_loc/$file" ||
Activator::Exception::Dictionary->throw('dict_file',
'unreadable',
"$dir_loc/$file" );
$file =~ /(.+)\.dict$/;
$realm = $1;
while (<DICT>) {
chomp;
next if /^\s*$/;
next if /^\s*#/;
s/^\s+//;
lib/Activator/Emailer.pm view on Meta::CPAN
$tt_vars->{'Activator_Emailer_format'} = 'text';
$tt_vars->{html_header} = $self->{html_header};
$tt_vars->{html_body} = $self->{html_body};
$tt_vars->{html_footer} = $self->{html_footer};
my $text_body = '';
my $html_body = '';
my $tt = Template->new( $self->{tt_options} ) ||
Activator::Exception::Emailer->throw( 'tt_new_error', $Template::ERROR, "\n" );
$tt->process( $self->{email_wrap}, $tt_vars, \$text_body ) ||
Activator::Exception::Emailer->throw( 'tt_process_error', $tt->error(), "\n" );
$tt_vars->{'Activator_Emailer_format'} = 'html';
$tt->process( $self->{email_wrap}, $tt_vars, \$html_body ) ||
Activator::Exception::Emailer->throw( 'tt_process_error', $tt->error(), "\n" );
my @email_args = (
From => $self->{From},
To => $self->{To},
Cc => $self->{Cc},
Subject => $self->{Subject},
SkipBad => 1,
);
push @email_args, ( Type => 'multipart/alternative' );
lib/Activator/Emailer.pm view on Meta::CPAN
DEBUG("----------------------------------------\nCreated email:\n".
$email->as_string .
"\n----------------------------------------"
);
try eval {
my $retval = $self->{sender}->send( $email->as_string);
die $retval unless $retval;
};
if ( catch my $e ) {
Activator::Exception::Emailer->throw( 'send_error', $e );
}
}
=head2 attach( %args )
Attach an item to this email. When C<send()> is called, C<%args> is
just passed through to the L<MIME::Lite> attach function.
=cut
lib/Activator/Exception.pm view on Meta::CPAN
package Activator::Exception;
use warnings;
use strict;
# override throw to accept shortcut
sub throw {
my ( $pkg, $obj, $code, $extra ) = @_;
$pkg->SUPER::throw( error => $obj,
code => $code,
extra => $extra );
}
# TODO: make this thing do dictionary/lexicon lookups, with support in
# $extra as well. Maybe $extra could "dict-><key>".
# TODO: make this take 2 args, update all of Activator
# NOTE: this is always called from SUPER::as_string
lib/Activator/Options.pm view on Meta::CPAN
--conf_path=<paths_to_conf_dir> # colon separated list
--conf_files=<conf_files> # comma separated list
$ENV{ACT_OPT_conf_path}
$ENV{ACT_OPT_project_home}/.<$ENV{ACT_OPT_project}>.d/
$ENV{HOME}/.<$ENV{ACT_OPT_project}>.d/
/etc/<$ENV{ACT_OPT_project}>.d/
/etc/activator.d/ # useful for org.yml
It is up to the script to define what C<project> is by insuring that
C<$ENV{ACT_OPT_project}> is set. This module will throw
C<Activator::Exception::Option> it is not set by you or passed in as a
command line argument, so you could force the user to use the
C<--project> option if you like.
=head2 Realms
This module supports the concept of realms to allow multiple similar
configurations to override only the esential keys to "git 'er done".
=head2 Configuration Logic Summary
lib/Activator/Options.pm view on Meta::CPAN
# into the registry
my $opts = $self->{REGISTRY}->get_realm( $realm );
# first call
if ( !keys %$opts ) {
# define valid opts from config files
try eval {
$self->_process_config_for( $realm );
};
# _set_reg throws err if $realm is invalid
if ( catch my $e ) {
$e->rethrow;
}
# read environment variables, set any keys found
if ( !$skip_env ) {
my ( $env_key, $env_realm );
foreach my $env_key ( keys %ENV ) {
next unless $env_key =~ /^ACT_OPT_(.+)/;
$opt_key = $1;
$opt_realm = $realm;
lib/Activator/Options.pm view on Meta::CPAN
return;
}
if ( $arg eq '--' ) {
return $arg;
}
my ( $key, $value ) = split /=/xms, $arg, 2;
if ( !defined $key ) {
Activator::Exception::Options->throw( 'argument',
'invalid',
$arg );
}
# clean up key
$key =~ s/^--?//;
# clean up value, if quoted
if ( defined $value ) {
$value =~ s/^"//;
lib/Activator/Options.pm view on Meta::CPAN
# Merge config files into this objects Activator::Registry object
sub _process_config_for {
my ( $pkg, $realm ) = @_;
my $self = &new( @_ );
# figure out what project we are working on
my $project =
$self->{ARGV}->{project} ||
$ENV{ACT_OPT_project} ||
Activator::Exception::Options->throw( 'project', 'missing' );
# assemble a list of paths to look for config files
# TODO: look in all these places:
# --conf_path
# ACT_OPT_conf_path
# $ENV{ACT_OPT_project_home}/.<$ENV{ACT_OPT_project}>.d/
# $ENV{HOME}/.<$ENV{ACT_OPT_project}>.d/
# $ENV{HOME}/.activator.d/
# /etc/<$ENV{ACT_OPT_project}>.d/
# /etc/activator.d/
lib/Activator/Options.pm view on Meta::CPAN
# ACT_OPT_conf_file= : comma separated list of files
# $ENV{USER}.yml
# <realm>.yml - realm specific settings and defaults
# <project>.yml - project specific settings and defaults
# org.yml - top level organization settings and defaults
# For now, just use ~/.activator.d/$project : key/value is path/'where
# found', 'where found' being one of: hardcoded, env, or arg
my $dir = $self->{ARGV}->{conf_path} ||
$ENV{ACT_OPT_conf_path} ||
Activator::Exception::Options->throw( 'conf_path', 'missing');
my $search_paths = { $dir => 'arg' };
my $files = { user => { target => "$ENV{USER}.yml" },
realm => { target => "${realm}.yml" },
project => { target => "${project}.yml" },
org => { target => 'org.yml' } };
foreach my $path ( keys %$search_paths ) {
$path =~ s|/$||;
foreach my $which ( keys %$files ) {
my $target = $files->{ $which }->{target};
lib/Activator/Options.pm view on Meta::CPAN
# now that we have all the files, import 'em! This is a super long
# winded but safe "left precedence" merge of all files
my ( $user_config, $realm_config, $project_config, $org_config );
try eval {
if( exists( $files->{user}->{file} ) ) {
$user_yml = YAML::Syck::LoadFile( $files->{user}->{file} );
}
};
if ( catch my $e ) {
Activator::Exception::Options->throw( 'user_config', 'invalid', $e );
}
try eval {
if( exists( $files->{realm}->{file} ) ) {
$realm_yml = YAML::Syck::LoadFile( $files->{realm}->{file} );
}
};
if ( catch my $e ) {
Activator::Exception::Options->throw( 'realm_config', 'invalid', $e );
}
try eval {
if( exists( $files->{project}->{file} ) ) {
$project_yml = YAML::Syck::LoadFile( $files->{project}->{file} );
}
};
if ( catch my $e ) {
Activator::Exception::Options->throw( 'project_config', 'invalid', $e );
}
try eval {
if( exists( $files->{org}->{file} ) ) {
$org_yml = YAML::Syck::LoadFile( $files->{org}->{file} );
}
};
if ( catch my $e ) {
Activator::Exception::Options->throw( 'org_config', 'invalid', $e );
}
if ( defined( $user_yml ) && exists( $user_yml->{ $realm } ) ) {
$self->{REGISTRY}->register_hash( 'left', $user_yml->{ $realm }, $realm );
}
if ( defined( $realm_yml ) && exists( $realm_yml->{ $realm } ) ) {
$self->{REGISTRY}->register_hash( 'left', $realm_yml->{ $realm }, $realm );
}
lib/Activator/Options.pm view on Meta::CPAN
$self->{REGISTRY}->register_hash( 'left', $project_yml->{overrides}, 'overrides' );
}
if ( defined( $org_yml ) && exists( $org_yml->{overrides} ) ) {
$self->{REGISTRY}->register_hash( 'left', $org_yml->{overrides}, 'overrides' );
}
# make sure all is kosher
my $test = $self->{REGISTRY}->get_realm( $realm );
if ( !keys %$test ) {
Activator::Exception::Options->throw('realm', 'invalid', $realm);
}
}
# Override any options in $opts with the values in $argv. Sets non-existent keys.
#
# Arguments:
# $opts : hashref to the options for $realm
# $argv : arrayref to command line arguments. All recognized options are removed.
#
lib/Activator/Registry.pm view on Meta::CPAN
#### register $value to $key in default realm
Activator::Registry->register( $key, $value );
#### get value for $key from $realm
Activator::Registry->get( $key, $realm );
#### get value for $key from default realm
Activator::Registry->get( $key );
#### get a deep value for $key from default realm
#### this form throws exception for invalid keys
$key = 'top->deep->deeper';
try eval {
Activator::Registry->get( $key );
}
#### register YAML file into realm
Activator::Registry->register_file( $file, $realm );
#### register hash into realm
Activator::Registry->register_hash( $mode, $hashref, $realm );
lib/Activator/Registry.pm view on Meta::CPAN
if ( $mode eq 'left' ) {
Hash::Merge::set_behavior( 'LEFT_PRECEDENT' );
}
elsif ( $mode eq 'right' ) {
Hash::Merge::set_behavior( 'RIGHT_PRECEDENT' );
}
else {
# TODO: consider using custom precedence
#Hash::Merge::specify_behavior( $pkg->{SAFE_LEFT_PRECEDENCE} );
Activator::Exception::Registry->throw( 'mode', 'invalid' );
}
my $reg = $pkg->new();
$realm ||= $reg->{DEFAULT_REALM};
if ( !exists( $reg->{REGISTRY}->{ $realm } ) ) {
$reg->{REGISTRY}->{ $realm } = {};
}
my $merged = {};
try eval {
$merged = Hash::Merge::merge( $reg->{REGISTRY}->{ $realm }, $right );
};
# catch
if ( catch my $e ) {
Activator::Exception::Registry->throw( 'merge', 'failure', $e );
}
elsif( keys %$merged ) {
$reg->{REGISTRY}->{ $realm } = $merged;
}
}
=head2 get( $key, $realm )
Get the value for C<$key> within C<$realm>. If C<$realm> not defined
lib/Activator/Registry.pm view on Meta::CPAN
sub _deep_get {
my ($pkg, $keys, $realm, $reg_ref) = @_;
my $key = shift @$keys;
if ( @$keys == 0 ) {
if ( exists( $reg_ref->{ $key } ) ) {
return $reg_ref->{ $key };
}
else {
Activator::Exception::Registry->throw( 'key', 'invalid', $key );
}
}
if ( exists( $reg_ref->{ $key } ) ) {
return $pkg->_deep_get( $keys, $realm, $reg_ref->{ $key } );
}
else {
Activator::Exception::Registry->throw( 'key', 'invalid', $key );
}
}
=head2 get_realm( $realm )
Return a reference to hashref for an entire C<$realm>.
=cut
sub get_realm {
lib/Activator/Registry.pm view on Meta::CPAN
processed AFTER the passed in C<$replacements> are processed.
=cut
sub replace_in_realm {
my ($pkg, $realm, $replacements) = @_;
my $self = $pkg->new();
my $reg = $self->get_realm( $realm );
if ( !keys %$reg ) {
Activator::Exception::Registry->throw( 'realm', 'invalid', $realm );
}
TRACE("replacing (realm '$realm') ". Dumper($reg) . "\n ---- with ----\n". Dumper($replacements));
$self->replace_in_hashref( $reg, $replacements );
$self->replace_in_hashref( $reg, $reg );
TRACE("Done replacing. End result: ". Dumper($reg));
}
=head2 replace_in_hashref( $hashref, $replacements )
lib/Catalyst/Plugin/Activator/Exception.pm view on Meta::CPAN
package Catalyst::Plugin::Activator::Exception;
use strict;
use warnings;
use Activator::Log qw( :levels );
use Activator::Exception;
use Symbol;
*{Symbol::qualify_to_ref('throw', 'Catalyst')} = sub {
return &Catalyst::Plugin::Activator::Exception::throw( @_ );
};
sub throw {
my ($c, $e) = @_;
if ( !defined $e ) {
$e = new Activator::Exception('unknown');
}
if ( $e eq '' ) {
$e = new Activator::Exception('unknown');
}
lives_ok {
$res = $db->do( "delete from t1 where id='$id'" );
} "do doesn't die";
ok( $res == 1, 'do affects corect num of rows');
lives_ok {
@row = $db->getrow( "select * from t1 where id='$id'" );
} "getrow doesn't die";
ok( @row == 0, 'do successfully deleted row');
# fail on static calls without connect string
throws_ok {
@row = Activator::DB->getrow( "select * from t1 where id='$id'" );
} 'Activator::Exception::DB', 'static call dies without connect arg';
throws_ok {
@row = Activator::DB->getrow( "sel from foo", [], connect => 'def');
} 'Activator::Exception::DB', 'invalid sql throws Activator::Exception::DB';
throws_ok {
@row = Activator::DB->getrow( "select * from t1", [], connect => 'defasdlkj');
} 'Activator::Exception::DB', 'invalid connect alias dies';
# get row as arrayref
lives_ok {
$rowref = $db->getrow_arrayref( "select * from t1" );
} "getrow_arrayref doesn't die after invalid connect attempt";
ok( ref($rowref) eq 'ARRAY', 'getrow_arrayref returns arrayref');
ok( @$rowref[0] eq '1' && @$rowref[1] eq 'd1_t1_r1_c1' && @$rowref[2] eq 'd1_t1_r1_c2', 'getrow_arrayref returns expected data');
t/Exception.t view on Meta::CPAN
#!/usr/bin/perl -w
use Test::More tests => 8;
use Activator::Exception;
use Exception::Class::TryCatch;
use Data::Dumper;
my $err;
try eval {
Activator::Exception->throw( 'MyObj', 'MyCode' );
};
catch $err;
ok( $err, "Can catch $err");
$err = undef;
try eval {
1;
};
ok( !$err, "Catch nothing when no error thrown");
try eval {
Activator::Exception->throw( 'MyObj', 'MyCode', 'MyExtra' );
};
catch $err;
ok( $err eq 'MyObj MyCode MyExtra', 'all fields in err string' );
try eval {
Activator::Exception::DB->throw( 'DbObj', 'DbCode', 'DbExtra' );
};
catch $err;
ok( $err, "Can catch subclass exception");
ok( $err eq 'DbObj DbCode DbExtra', 'subclass exception inherits fields' );
try eval {
die "text failure";
};
catch $err;
ok( $err, "Can catch random die");
t/Registry-oo.t view on Meta::CPAN
my $dne_value = $reg->get('dne_value');
ok( !defined( $dne_value ), 'non-existent key returns undef' );
# deep get
my $deep_key = 'deep_hash->level_1->level_2->level_3';
my $deep_val = $reg->get( $deep_key );
ok( $deep_val && $deep_val eq 'this is level 3', 'deep arrow syntax: value match' );
eval {
$deep_val = $reg->get( "${deep_key}->level_4" );
};
ok( defined $@, 'deep get of non-existent key throws exception' );
# deep register
my $success = $reg->register( $deep_key, 'modified' );
ok( $success, 'deep arrow syntax: register existing key returns true' );
$deep_val = $reg->get( $deep_key );
ok( $deep_val && $deep_val eq 'modified', 'deep arrow syntax: register value match' );
## # create a test file to reload
my $dyn_test_yaml_file = "$ENV{PWD}/t/data/Registry-dyn.yml";