diff options
author | Florian Ragwitz <rafl@debian.org> | 2010-12-10 22:02:52 +0100 |
---|---|---|
committer | Florian Ragwitz <rafl@debian.org> | 2010-12-10 22:02:52 +0100 |
commit | 41e13b7c97391e529c57ed40083c910e3b9f3951 (patch) | |
tree | 3dce7149ee8de08b96ec7c86b2160c52bfe13bcd /dist/Env | |
parent | 4206729ba3c39e440203a8ac3ecda62348881cf3 (diff) | |
download | perl-41e13b7c97391e529c57ed40083c910e3b9f3951.tar.gz |
Dual-life Env
Diffstat (limited to 'dist/Env')
-rw-r--r-- | dist/Env/lib/Env.pm | 254 | ||||
-rw-r--r-- | dist/Env/t/array.t | 20 | ||||
-rw-r--r-- | dist/Env/t/env.t | 95 |
3 files changed, 369 insertions, 0 deletions
diff --git a/dist/Env/lib/Env.pm b/dist/Env/lib/Env.pm new file mode 100644 index 0000000000..deac5fc4b9 --- /dev/null +++ b/dist/Env/lib/Env.pm @@ -0,0 +1,254 @@ +package Env; + +our $VERSION = '1.01'; + +=head1 NAME + +Env - perl module that imports environment variables as scalars or arrays + +=head1 SYNOPSIS + + use Env; + use Env qw(PATH HOME TERM); + use Env qw($SHELL @LD_LIBRARY_PATH); + +=head1 DESCRIPTION + +Perl maintains environment variables in a special hash named C<%ENV>. For +when this access method is inconvenient, the Perl module C<Env> allows +environment variables to be treated as scalar or array variables. + +The C<Env::import()> function ties environment variables with suitable +names to global Perl variables with the same names. By default it +ties all existing environment variables (C<keys %ENV>) to scalars. If +the C<import> function receives arguments, it takes them to be a list of +variables to tie; it's okay if they don't yet exist. The scalar type +prefix '$' is inferred for any element of this list not prefixed by '$' +or '@'. Arrays are implemented in terms of C<split> and C<join>, using +C<$Config::Config{path_sep}> as the delimiter. + +After an environment variable is tied, merely use it like a normal variable. +You may access its value + + @path = split(/:/, $PATH); + print join("\n", @LD_LIBRARY_PATH), "\n"; + +or modify it + + $PATH .= ":."; + push @LD_LIBRARY_PATH, $dir; + +however you'd like. Bear in mind, however, that each access to a tied array +variable requires splitting the environment variable's string anew. + +The code: + + use Env qw(@PATH); + push @PATH, '.'; + +is equivalent to: + + use Env qw(PATH); + $PATH .= ":."; + +except that if C<$ENV{PATH}> started out empty, the second approach leaves +it with the (odd) value "C<:.>", but the first approach leaves it with "C<.>". + +To remove a tied environment variable from +the environment, assign it the undefined value + + undef $PATH; + undef @LD_LIBRARY_PATH; + +=head1 LIMITATIONS + +On VMS systems, arrays tied to environment variables are read-only. Attempting +to change anything will cause a warning. + +=head1 AUTHOR + +Chip Salzenberg E<lt>F<chip@fin.uucp>E<gt> +and +Gregor N. Purdy E<lt>F<gregor@focusresearch.com>E<gt> + +=cut + +sub import { + my ($callpack) = caller(0); + my $pack = shift; + my @vars = grep /^[\$\@]?[A-Za-z_]\w*$/, (@_ ? @_ : keys(%ENV)); + return unless @vars; + + @vars = map { m/^[\$\@]/ ? $_ : '$'.$_ } @vars; + + eval "package $callpack; use vars qw(" . join(' ', @vars) . ")"; + die $@ if $@; + foreach (@vars) { + my ($type, $name) = m/^([\$\@])(.*)$/; + if ($type eq '$') { + tie ${"${callpack}::$name"}, Env, $name; + } else { + if ($^O eq 'VMS') { + tie @{"${callpack}::$name"}, Env::Array::VMS, $name; + } else { + tie @{"${callpack}::$name"}, Env::Array, $name; + } + } + } +} + +sub TIESCALAR { + bless \($_[1]); +} + +sub FETCH { + my ($self) = @_; + $ENV{$$self}; +} + +sub STORE { + my ($self, $value) = @_; + if (defined($value)) { + $ENV{$$self} = $value; + } else { + delete $ENV{$$self}; + } +} + +###################################################################### + +package Env::Array; + +use Config; +use Tie::Array; + +@ISA = qw(Tie::Array); + +my $sep = $Config::Config{path_sep}; + +sub TIEARRAY { + bless \($_[1]); +} + +sub FETCHSIZE { + my ($self) = @_; + return 1 + scalar(() = $ENV{$$self} =~ /\Q$sep\E/g); +} + +sub STORESIZE { + my ($self, $size) = @_; + my @temp = split($sep, $ENV{$$self}); + $#temp = $size - 1; + $ENV{$$self} = join($sep, @temp); +} + +sub CLEAR { + my ($self) = @_; + $ENV{$$self} = ''; +} + +sub FETCH { + my ($self, $index) = @_; + return (split($sep, $ENV{$$self}))[$index]; +} + +sub STORE { + my ($self, $index, $value) = @_; + my @temp = split($sep, $ENV{$$self}); + $temp[$index] = $value; + $ENV{$$self} = join($sep, @temp); + return $value; +} + +sub EXISTS { + my ($self, $index) = @_; + return $index < $self->FETCHSIZE; +} + +sub DELETE { + my ($self, $index) = @_; + my @temp = split($sep, $ENV{$$self}); + my $value = splice(@temp, $index, 1, ()); + $ENV{$$self} = join($sep, @temp); + return $value; +} + +sub PUSH { + my $self = shift; + my @temp = split($sep, $ENV{$$self}); + push @temp, @_; + $ENV{$$self} = join($sep, @temp); + return scalar(@temp); +} + +sub POP { + my ($self) = @_; + my @temp = split($sep, $ENV{$$self}); + my $result = pop @temp; + $ENV{$$self} = join($sep, @temp); + return $result; +} + +sub UNSHIFT { + my $self = shift; + my @temp = split($sep, $ENV{$$self}); + my $result = unshift @temp, @_; + $ENV{$$self} = join($sep, @temp); + return $result; +} + +sub SHIFT { + my ($self) = @_; + my @temp = split($sep, $ENV{$$self}); + my $result = shift @temp; + $ENV{$$self} = join($sep, @temp); + return $result; +} + +sub SPLICE { + my $self = shift; + my $offset = shift; + my $length = shift; + my @temp = split($sep, $ENV{$$self}); + if (wantarray) { + my @result = splice @temp, $self, $offset, $length, @_; + $ENV{$$self} = join($sep, @temp); + return @result; + } else { + my $result = scalar splice @temp, $offset, $length, @_; + $ENV{$$self} = join($sep, @temp); + return $result; + } +} + +###################################################################### + +package Env::Array::VMS; +use Tie::Array; + +@ISA = qw(Tie::Array); + +sub TIEARRAY { + bless \($_[1]); +} + +sub FETCHSIZE { + my ($self) = @_; + my $i = 0; + while ($i < 127 and defined $ENV{$$self . ';' . $i}) { $i++; }; + return $i; +} + +sub FETCH { + my ($self, $index) = @_; + return $ENV{$$self . ';' . $index}; +} + +sub EXISTS { + my ($self, $index) = @_; + return $index < $self->FETCHSIZE; +} + +sub DELETE { } + +1; diff --git a/dist/Env/t/array.t b/dist/Env/t/array.t new file mode 100644 index 0000000000..ed84834525 --- /dev/null +++ b/dist/Env/t/array.t @@ -0,0 +1,20 @@ +#!./perl + +BEGIN { + $ENV{FOO} = "foo"; + $ENV{BAR} = "bar"; +} + +use Env qw(FOO $BAR); + +$FOO .= "/bar"; +$BAR .= "/baz"; + +print "1..2\n"; + +print "not " if $FOO ne 'foo/bar'; +print "ok 1\n"; + +print "not " if $BAR ne 'bar/baz'; +print "ok 2\n"; + diff --git a/dist/Env/t/env.t b/dist/Env/t/env.t new file mode 100644 index 0000000000..888120270c --- /dev/null +++ b/dist/Env/t/env.t @@ -0,0 +1,95 @@ +#!./perl + +$| = 1; + +if ($^O eq 'VMS') { + print "1..11\n"; + foreach (1..11) { print "ok $_ # skipped for VMS\n"; } + exit 0; +} + +use Env qw(@FOO); +use vars qw(@BAR); + +sub array_equal +{ + my ($a, $b) = @_; + return 0 unless scalar(@$a) == scalar(@$b); + for my $i (0..scalar(@$a) - 1) { + return 0 unless $a->[$i] eq $b->[$i]; + } + return 1; +} + +sub test +{ + my ($desc, $code) = @_; + + &$code; + + print "# $desc...\n"; + print "# FOO = (", join(", ", @FOO), ")\n"; + print "# BAR = (", join(", ", @BAR), ")\n"; + + if (defined $check) { print "not " unless &$check; } + else { print "not " unless array_equal(\@FOO, \@BAR); } + + print "ok ", ++$i, "\n"; +} + +print "1..11\n"; + +test "Assignment", sub { + @FOO = qw(a B c); + @BAR = qw(a B c); +}; + +test "Storing", sub { + $FOO[1] = 'b'; + $BAR[1] = 'b'; +}; + +test "Truncation", sub { + $#FOO = 0; + $#BAR = 0; +}; + +test "Push", sub { + push @FOO, 'b', 'c'; + push @BAR, 'b', 'c'; +}; + +test "Pop", sub { + pop @FOO; + pop @BAR; +}; + +test "Shift", sub { + shift @FOO; + shift @BAR; +}; + +test "Push", sub { + push @FOO, 'c'; + push @BAR, 'c'; +}; + +test "Unshift", sub { + unshift @FOO, 'a'; + unshift @BAR, 'a'; +}; + +test "Reverse", sub { + @FOO = reverse @FOO; + @BAR = reverse @BAR; +}; + +test "Sort", sub { + @FOO = sort @FOO; + @BAR = sort @BAR; +}; + +test "Splice", sub { + splice @FOO, 1, 1, 'B'; + splice @BAR, 1, 1, 'B'; +}; |