EnvDir

 view release on metacpan or  search on metacpan

lib/EnvDir.pm  view on Meta::CPAN

package EnvDir;
use 5.008005;
use strict;
use warnings;
use Carp ();
use File::Spec;
use Storable ();

our $VERSION = "0.08";
our $DEFAULT_ENVDIR = File::Spec->catdir( File::Spec->curdir, 'env' );

use constant MARK_DELETE => '__MARK_DELETE__';

sub new {
    my $class = shift;
    my %args  = @_;
    bless {
        clean => 0,
        depth => 0,
        cache => [],
        stack => [],
        map { $_ => $args{$_} } qw(clean)
    }, $class;
}

my $GLOBAL_INSTANCE;
my @GLOBAL_GUARD;
sub _instance {
    my $class = shift;
    $GLOBAL_INSTANCE ||= $class->new;
    $GLOBAL_INSTANCE;
}

sub import {
    my $class = shift;
    my @args  = @_;

    my $autoload = 0;
    my $dir      = 0;
    my $clean    = 0;
    my $self;

    while ( defined( my $arg = shift @args ) ) {
        if ( $arg eq '-autoload' ) {
            $self = $class->_instance;
            $autoload = 1;

            $dir = shift @args;
            if ( $dir and $dir eq '-clean' ) {
                push @_, $dir;
                $dir = $DEFAULT_ENVDIR;
            }
        }
        elsif ( $arg eq 'envdir' ) {
            my $package = (caller)[0];
            no strict 'refs';
            *{"$package\::envdir"} = \&envdir;
        }
        elsif ( $arg eq '-clean' ) {
            $self = $class->_instance;
            $self->{clean} = 1;
        }
    }

    if ($autoload) {
        push @GLOBAL_GUARD, $self->envdir($dir);
    }
}

sub envdir {
    my ( $self, $envdir ) = @_;

    unless ( ref $self and ref $self eq 'EnvDir' ) {
        $envdir = $self;
        $self = EnvDir->_instance;
    }

    $self->{depth} = scalar @{ $self->{stack} };
    $envdir ||= $DEFAULT_ENVDIR;

    my $depth = $self->{depth};

    # from cache
    my @keys = keys %{ $self->{cache}->[$depth] };
    if ( scalar @keys ) {
        $self->_push_stack;
        $self->_clean_env if $self->{clean};
        $self->_update_env;

        return EnvDir::Guard->new( sub { $self->_revert if $self } );
    }

    # from dir
    opendir my $dh, $envdir or Carp::croak "Cannot open $envdir: $!";

    for my $key ( grep !/^\./, readdir($dh) ) {
        my $path = File::Spec->catfile( $envdir, $key );
        next if -d $path;
        if ( -s $path == 0 ) {
            $self->{cache}->[$depth]->{ uc $key } = MARK_DELETE;
        }
        else {
            my $value = $self->_slurp($path);
            $self->{cache}->[$depth]->{ uc $key } = $value;
        }
    }

    $self->_push_stack;
    $self->_clean_env if $self->{clean};
    $self->_update_env;

    closedir $dh or Carp::carp "Cannot close $envdir: $!";

    return EnvDir::Guard->new( sub { $self->_revert if $self } );
}



( run in 1.045 second using v1.01-cache-2.11-cpan-ff9377addf4 )