Aion-Env

 view release on metacpan or  search on metacpan

lib/Aion/Env.pm  view on Meta::CPAN

package Aion::Env;

use common::sense;

our $VERSION = "0.2";

use constant {};

our %env = %{ -e '.env'? parse('.env'): () };

sub import {
    my ($cls, $name, %kw) = @_;
    my $isa = delete $kw{isa};
    my $is_default = exists $kw{default};
    my $default = delete $kw{default};
    die sprintf "Unknown aspect%s: %s",
    	scalar keys %kw == 1? '': 's',
     	join ", ", sort keys %kw if keys %kw;
      
    die "$name is'nt defined!" if !exists $ENV{$name} && !exists $env{$name} && !$is_default;

    my $pkg = caller;
    my $val = $ENV{$name} // $env{$name} // $default;

    if($isa) {
   		if(UNIVERSAL::isa($isa, "Aion::Type")) { $isa->validate($val, $name) }
    	else {
	    	local $_ = $val;
	    	die UNIVERSAL::can($isa, "get_message")? $isa->get_message($val): "$name type is'nt isa!" unless $isa->();
		}
    }
    
    constant->import("$pkg\::$name", $val);
}

my $BOM = "\x{feff}";
sub parse {
    my ($file) = @_;
    open my $f, '<:utf8', $file or die "$file: $!";

    my %env;
    my $interpolate = sub {
    	$_[0] =~ s!\$\{(\w+)\}!$env{$1}!ge;
    };
     
    while(<$f>) {
    	s/^$BOM// if $. == 1;
        next if /^\s*(?:#|$)/;
        
        if(my ($k, $v) = /^\s*([a-z_]\w*)\s*=\s*(.*?)\s*$/i) {
            if($v =~ s/^(['"])(.*)\1\z/$2/) {
            	if($1 eq '"') {
	                $v =~ s/\\n/\n/g;
	                $v =~ s/\\//g;
					$interpolate->($v);
                }
            }
            else { $interpolate->($v) }
            $env{$k} = $v;
        }
        else {
        	my $message = "Can't parse $file line $.: $_";
            close $f;
            die $message;
        }
    }

    close $f;
    
    \%env
};

1;

__END__

=encoding utf-8

=head1 NAME

Aion::Env - creates a constant associated with the value from .env

=head1 VERSION

0.2

=head1 SYNOPSIS

.env file:

	BIN_TEST=10
	OCT_TEST=${BIN_TEST}20



	BEGIN {
		delete @ENV{qw/BIN_TEST OCT_TEST BB_TEST NN_TEST/};
	
		$ENV{UNI_TEST} = 30;
	}
	
	sub Int { sub { /^-?\d+$/ } }
	
	use Aion::Env BIN_TEST => (isa => Int);
	use Aion::Env OCT_TEST => (isa => Int);
	use Aion::Env UNI_TEST => (isa => Int);
	use Aion::Env BB_TEST => (isa => Int, default => 1);



( run in 1.994 second using v1.01-cache-2.11-cpan-c966e8aa7e8 )