File Coverage

blib/lib/Tie/File/AsHash.pm
Criterion Covered Total %
statement 30 30 100.0
branch 4 8 50.0
condition 1 3 33.3
subroutine 8 8 100.0
pod n/a
total 43 49 87.7


line stmt bran cond sub pod time code
1             package Tie::File::AsHash;
2              
3 9     9   233946 use strict;
  9         21  
  9         371  
4              
5             # use warnings;
6 9     9   50 use vars qw($VERSION);
  9         21  
  9         477  
7 9     9   51 use Carp;
  9         22  
  9         859  
8 9     9   11849 use Tie::File;
  9         222415  
  9         346  
9 9     9   111 use base qw(Tie::Array::AsHash);
  9         18  
  9         13158  
10              
11             $VERSION = "0.200";
12              
13             my $usage = "usage: tie %hash, 'Tie::File::AsHash', 'filename', "
14             . "split => ':' [, join => '#', 'Tie::File option' => value, ... ]\n";
15              
16             sub TIEHASH
17             {
18 8 50   8   708 croak( $usage ) if ( scalar(@_) % 2 );
19              
20 8         57 my ( $obj, $filename, %opts ) = @_;
21              
22             # set delimiter and croak if none was supplied
23 8 50       50 my $split = delete( $opts{split} ) or croak( $usage );
24              
25             # set join, an optional argument
26 8         22 my $join = delete( $opts{join} );
27              
28             # if split's value is a regex and join isn't specified, croak
29 8 50 33     59 croak( "Tie::File::AsHash error: no 'join' option specified and 'split' option is a regular expression\n", $usage )
30             if ( ref($split) eq 'Regexp' and not defined($join) );
31              
32             # the rest of the options can feed right into Tie::File
33             # Tie::File can worry about checking the arguments for validity, etc.
34 8 50       83 my $tiefile = tie my @file, 'Tie::File', $filename, %opts or return;
35              
36 8         1620 $obj = $obj->SUPER::TIEHASH(
37             array => \@file,
38             split => $split,
39             join => $join,
40             );
41              
42 8         469 $obj->{file} = $tiefile;
43              
44 8         90 return $obj;
45             }
46              
47             sub UNTIE
48             {
49 8     8   21 my ($self) = @_;
50              
51 8         22 $self->{file} = undef;
52 8         15 untie @{ $self->{array} };
  8         86  
53              
54 8         425 $self->SUPER::UNTIE();
55             }
56              
57 8     8   13230 sub DESTROY { UNTIE(@_) }
58              
59             =head1 NAME
60              
61             Tie::File::AsHash - access lines of a file as a hash splitting at separator
62              
63             =head1 SYNOPSIS
64              
65             use Tie::File::AsHash;
66              
67             tie my %hash, 'Tie::File::AsHash', 'filename', split => ':'
68             or die "Problem tying %hash: $!";
69              
70             print $hash{foo}; # access hash value via key name
71             $hash{foo} = "bar"; # assign new value
72             my @keys = keys %hash; # get the keys
73             my @values = values %hash; # ... and values
74             exists $hash{perl}; # check for existence
75             delete $hash{baz}; # delete line from file
76             $hash{newkey} = "perl"; # entered at end of file
77             while (($key,$val) = each %hash) # iterate through hash
78             %hash = (); # empty file
79              
80             untie %hash; # all done
81              
82             Here is sample text that would work with the above code when contained in a
83             file:
84              
85             foo:baz
86             key:val
87             baz:whatever
88              
89             =head1 DESCRIPTION
90              
91             C uses C and perl code from C
92             so files can be tied to hashes. C does all the hard work while
93             C works a little magic of its own.
94              
95             The module was initially written by Chris Angell for
96             managing htpasswd-format password files.
97              
98             =head1 USAGE
99              
100             use Tie::File::AsHash;
101             tie %hash, 'Tie::File::AsHash', 'filename', split => ':'
102             or die "Problem tying %hash: $!";
103              
104             (use %hash like a regular ol' hash)
105              
106             untie %hash; # changes saved to disk
107              
108             Easy enough eh?
109              
110             New key/value pairs are appended to the end of the file, C removes lines
111             from the file, C and C work as expected, and so on.
112              
113             C will not die or exit if there is a problem tying a
114             file, so make sure to check the return value and check C<$!> as the examples do.
115              
116             =head2 OPTIONS
117              
118             The only argument C requires is the "split" option, besides
119             a filename. The split option's value is the delimiter that exists in the file
120             between the key and value portions of the line. It may be a regular
121             expression, and if so, the "join" option must be used to tell
122             C what to stick between the key and value when writing
123             to the file. Otherwise, the module dies with an error message.
124              
125             tie %hash, 'Tie::File::AsHash', 'filename', split => qr(\s+), join => " "
126             or die "Problem tying %hash: $!";
127              
128             Obviously no one wants lines like "key(?-xism:\s+)val" in their files.
129              
130             All other options are passed directly to C, so read its
131             documentation for more information.
132              
133             =head1 CAVEATS
134              
135             When C, C, or C is used on the hash, the values are
136             returned in the same order as the data exists in the file, from top to
137             bottom, though this behavior should not be relied on and is subject to change
138             at any time (but probably never will).
139              
140             C doesn't force keys to be unique. If there are multiple
141             keys, the first key in the file, starting at the top, is used. However, when
142             C, C, or C is used on the hash, every key/value combination
143             is returned, including duplicates, triplicates, etc.
144              
145             Keys can't contain the split character. Look at the perl code that
146             C is comprised of to see why (look at the regexes). Using
147             a regex for the split value may be one way around this issue.
148              
149             C hasn't been optimized much. Maybe it doesn't need to be.
150             Optimization could add overhead. Maybe there can be options to turn on and off
151             various types of optimization?
152              
153             =head1 EXAMPLES
154              
155             =head2 changepass.pl
156              
157             C changes password file entries when the lines are of
158             "user:encryptedpass" format. It can also add users.
159              
160             #!/usr/bin/perl -w
161              
162             use strict;
163             use Tie::File::AsHash;
164              
165             die "Usage: $0 user password" unless @ARGV == 2;
166             my ($user, $newpass) = @ARGV;
167              
168             tie my %users, 'Tie::File::AsHash', '/pwdb/users.txt', split => ':'
169             or die "Problem tying %hash: $!";
170              
171             # username isn't in the password file? see if the admin wants it added
172             unless (exists $users{$user}) {
173              
174             print "User '$user' not found in db. Add as a new user? (y/n)\n";
175             chomp(my $y_or_n = );
176             set_pw($user, $newpass) if $y_or_n =~ /^[yY]/;
177              
178             } else {
179              
180             set_pw($user, $newpass);
181             print "Done.\n";
182              
183             }
184              
185             sub set_pw { $users{$_[0]} = crypt($_[1], "AA") }
186              
187             =head2 Using the join option
188              
189             Here's code that would allow the delimiter to be ':' or '#' but prefers '#':
190              
191             tie my %hash, 'Tie::File::AsHash', 'filename', split => qr/[:#]/, join => "#" or die $!;
192              
193             Say you want to be sure no ':' delimiters exist in the file:
194              
195             while (my ($key, $val) = each %hash) {
196              
197             $hash{$key} = $val;
198              
199             }
200              
201             =head1 AUTHOR
202              
203             Chris Angell , Jens Rehsack
204              
205             Feel free to email me with suggestions, fixes, etc.
206              
207             Thanks to Mark Jason Dominus for authoring the superb Tie::File module.
208              
209             =head1 COPYRIGHT
210              
211             Copyright (C) 2004, Chris Angell, 2008-2013, Jens Rehsack. All Rights Reserved.
212              
213             This library is free software; you can redistribute it and/or modify
214             it under the same terms as Perl itself, including any version of Perl 5.
215              
216             =head1 SEE ALSO
217              
218             perl(1), perltie(1), Tie::File(3pm), Tie::Array::AsHash(3pm)
219              
220             =cut
221              
222             # vim:ts=4
223              
224             1;