NAME
Tie::Array::AsHash - tie arrays as hashes by splitting lines on separator
SYNOPSIS
use Tie::Array::AsHash;
my $t = tie my %hash, 'Tie::Array::AsHash', array => \@array, split => ':'
or die "Problem tying %hash: $!";
print $hash{foo}; # access hash value via key name
$hash{foo} = "bar"; # assign new value
my @keys = keys %hash; # get the keys
my @values = values %hash; # ... and values
exists $hash{perl}; # check for existence
delete $hash{baz}; # delete line from file
$hash{newkey} = "perl"; # entered at end of file
while (($key,$val) = each %hash) # iterate through hash
%hash = (); # empty file
untie %hash; # all done
Here is sample text that would work with the above code when contained in a file:
foo:baz
key:val
baz:whatever
DESCRIPTION
Tie::Array::AsHash
uses some practical extracting code so arrays can be tied to hashes.
The module was initially written by Chris Angell <chris@chrisangell.com> for managing htpasswd-format password files.
SYNOPSIS
use Tie::Array::AsHash;
tie %hash, 'Tie::Array::AsHash', array => \@array, split => ':'
or die "Problem tying %hash: $!";
(use %hash like a regular ol' hash)
untie %hash; # changes saved to disk
Easy enough eh?
New key/value pairs are appended to the end of the file, delete
removes lines from the file, keys
and each
work as expected, and so on.
Tie::Array::AsHash
will not die or exit if there is a problem tying a file, so make sure to check the return value and check $!
as the examples do.
OPTIONS
The only argument Tie::Array::AsHash
requires is the "split" option, besides a filename. The split option's value is the delimiter that exists in the file between the key and value portions of the line. It may be a regular expression, and if so, the "join" option must be used to tell Tie::Array::AsHash
what to stick between the key and value when writing to the file. Otherwise, the module dies with an error message.
tie %hash, 'Tie::Array::AsHash', array => \@array, split => qr(\s+), join => ' '
or die "Problem tying %hash: $!";
Obviously no one wants lines like "key(?-xism:\s+)val" in their files.
All other options are passed directly to Tie::File
, so read its documentation for more information.
CAVEATS
When keys
, values
, or each
is used on the hash, the values are returned in the same order as the data exists in the file, from top to bottom, though this behavior should not be relied on and is subject to change at any time (but probably never will).
Tie::Array::AsHash
doesn't force keys to be unique. If there are multiple keys, the first key in the file, starting at the top, is used. However, when keys
, values
, or each
is used on the hash, every key/value combination is returned, including duplicates, triplicates, etc.
Keys can't contain the split character. Look at the perl code that Tie::Array::AsHash
is comprised of to see why (look at the regexes). Using a regex for the split value may be one way around this issue.
Tie::Array::AsHash
hasn't been optimized much. Maybe it doesn't need to be. Optimization could add overhead. Maybe there can be options to turn on and off various types of optimization?
EXAMPLES
changepass.pl
changepass.pl
changes password file entries when the lines are of "user:encryptedpass" format. It can also add users.
#!/usr/bin/perl -w
use strict;
use warnings;
use Tie::Array::AsHash;
die "Usage: $0 user password" unless @ARGV == 2;
my ($user, $newpass) = @ARGV;
tie my @userlist, 'Tie::File', '/pwdb/users.txt';
tie my %users, 'Tie::Array::AsHash', array => \@userlist, split => ':'
or die "Problem tying %hash: $!";
# username isn't in the password file? see if the admin wants it added
unless (exists $users{$user})
{
print "User '$user' not found in db. Add as a new user? (y/n)\n";
chomp(my $y_or_n = <STDIN>);
set_pw($user, $newpass) if $y_or_n =~ /^[yY]/;
}
else
{
set_pw($user, $newpass);
print "Done.\n";
}
sub set_pw { $users{$_[0]} = crypt($_[1], "AA") }
Using the join option
Here's code that would allow the delimiter to be ':' or '#' but prefers '#':
tie my %hash, 'Tie::Array::AsHash', array => \@array, split => qr/[:#]/, join => "#" or die $!;
Say you want to be sure no ':' delimiters exist in the file:
while (my ($key, $val) = each %hash)
{
$hash{$key} = $val;
}
TODO
add supoort for comments and/or commented lines
AUTHOR
Chris Angell <chris@chrisangell.com>, Jens Rehsack <rehsack@cpan.org>
Feel free to email me with suggestions, fixes, etc.
Thanks to Mark Jason Dominus for authoring the superb Tie::File module.
COPYRIGHT
Copyright (C) 2004, Chris Angell, 2008-2013, Jens Rehsack. All Rights Reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, including any version of Perl 5.
SEE ALSO
perl(1), perltie(1), Tie::File(3pm), Tie::File::AsHash(3pm)