libtie-shadowhash-perl-1.00.orig/0000755000000000000000000000000011355747423013631 5ustar libtie-shadowhash-perl-1.00.orig/ShadowHash.pm0000644000000000000000000003246011355746165016227 0ustar # Tie::ShadowHash -- Merge multiple data sources into a hash. # # Copyright 1999, 2002, 2010 by Russ Allbery # # This program is free software; you may redistribute it and/or modify it # under the same terms as Perl itself. # # This module combines multiple sources of data into a single tied hash, so # that they can all be queried simultaneously, the source of any given # key-value pair irrelevant to the client script. Data sources are searched # in the order that they're added to the shadow hash. Changes to the hashed # data aren't propagated back to the actual data files; instead, they're saved # within the tied hash and override any data obtained from the data sources. ############################################################################## # Modules and declarations ############################################################################## package Tie::ShadowHash; require 5.006; use strict; use vars qw($VERSION); $VERSION = '1.00'; ############################################################################## # Regular methods ############################################################################## # This should pretty much never be called; tie calls TIEHASH. sub new { my $class = shift; return $class->TIEHASH (@_); } # Given a file name and optionally a split regex, builds a hash out of the # contents of the file. If the split sub exists, use it to split each line # into an array; if the array has two elements, those are taken as the key and # value. If there are more, the value is an anonymous array containing # everything but the first. If there's no split sub, take the entire line # modulo the line terminator as the key and the value the number of times it # occurs in the file. sub text_source { my ($self, $file, $split) = @_; unless (open (HASH, '<', $file)) { require Carp; Carp::croak ("Can't open file $file: $!"); } local $_; my ($key, @rest, %hash); while () { chomp; if (defined $split) { ($key, @rest) = &$split ($_); $hash{$key} = (@rest == 1) ? $rest[0] : [ @rest ]; } else { $hash{$_}++; } } close HASH; return \%hash; } # Add data sources to the shadow hash. This takes a list of either anonymous # arrays (in which case the first element is the type of source and the rest # are arguments), filenames (in which case it's taken to be a text file with # each line being a key), or hash references (possibly to tied hashes). sub add { my ($self, @sources) = @_; for my $source (@sources) { if (ref $source eq 'ARRAY') { my ($type, @args) = @$source; if ($type eq 'text') { $source = $self->text_source (@args); } else { require Carp; Carp::croak ("Invalid source type $type"); } } elsif (!ref $source) { $source = $self->text_source ($source); } push (@{ $$self{SOURCES} }, $source); } return 1; } ############################################################################## # Tie methods ############################################################################## # DELETED is a hash holding all keys that have been deleted; it's checked # first on any access. EACH is a pointer to the current structure being # traversed on an "each" of the shadow hash, so that they can all be traversed # in order. OVERRIDE is a hash containing values set directly by the user, # which override anything in the shadow hash's underlying data structures. # And finally, SOURCES is an array of the data structures (all Perl hashes, # possibly tied). sub TIEHASH { my $class = shift; $class = ref $class || $class; my $self = { DELETED => {}, EACH => -1, OVERRIDE => {}, SOURCES => [] }; bless ($self, $class); $self->add (@_) if @_; return $self; } # Note that this doesn't work quite right in the case of keys with undefined # values, but we can't make it work right since that would require using # exists and a lot of common data sources (such as NDBM_File tied hashes) # don't implement exists. sub FETCH { my ($self, $key) = @_; return if $self->{DELETED}{$key}; return $self->{OVERRIDE}{$key} if exists $self->{OVERRIDE}{$key}; for my $source (@{ $self->{SOURCES} }) { return $source->{$key} if defined $source->{$key}; } return; } sub STORE { my ($self, $key, $value) = @_; delete $self->{DELETED}{$key}; $self->{OVERRIDE}{$key} = $value; } sub DELETE { my ($self, $key) = @_; delete $self->{OVERRIDE}{$key}; $self->{DELETED}{$key} = 1; } sub CLEAR { my ($self) = @_; $self->{DELETED} = {}; $self->{OVERRIDE} = {}; $self->{SOURCES} = []; $self->{EACH} = -1; } # This could throw an exception if any underlying source doesn't support # exists (like NDBM_File). sub EXISTS { my ($self, $key) = @_; return if exists $self->{DELETED}{$key}; for my $source ($self->{OVERRIDE}, @{ $self->{SOURCES} }) { return 1 if exists $source->{$key}; } return; } # We have to reset the each counter on all hashes. For tied hashes, we call # FIRSTKEY directly because it's potentially more efficient than calling keys # on the hash. sub FIRSTKEY { my ($self) = @_; keys %{ $self->{OVERRIDE} }; for my $source (@{ $self->{SOURCES} }) { my $tie = tied $source; if ($tie) { $tie->FIRSTKEY; } else { keys %$source; } } $self->{EACH} = -1; return $self->NEXTKEY; } # Walk the sources by calling each on each one in turn, skipping deleted # keys and keys shadowed by earlier hashes and using $self->{EACH} to # store the number of source we're at. sub NEXTKEY { my ($self) = @_; my @result = (); SOURCE: while (!@result && $self->{EACH} < @{ $self->{SOURCES} }) { if ($self->{EACH} == -1) { @result = each %{ $self->{OVERRIDE} }; } else { @result = each %{ $self->{SOURCES}[$self->{EACH}] }; } if (@result && $self->{DELETED}{$result[0]}) { undef @result; next; } if (@result && $self->{EACH} > -1) { my $key = $result[0]; if (exists $self->{OVERRIDE}{$key}) { undef @result; next; } for (my $index = $self->{EACH} - 1; $index >= 0; $index--) { if (defined $self->{SOURCES}[$index]{$key}) { undef @result; next SOURCE; } } } return (wantarray ? @result : $result[0]) if @result; $self->{EACH}++; } return; } ############################################################################## # Module return value and documentation ############################################################################## # Make sure the module returns true. 1; __DATA__ =head1 NAME Tie::ShadowHash - Merge multiple data sources into a hash =for stopwords DBM Allbery =head1 SYNOPSIS use Tie::ShadowHash; use DB_File; tie (%db, 'DB_File', 'file.db'); $obj = tie (%hash, 'Tie::ShadowHash', \%db, "otherdata.txt"); # Accesses search %db first, then the hashed "otherdata.txt". print "$hash{key}\n"; # Changes override data sources, but don't change them. $hash{key} = 'foo'; delete $hash{bar}; # Add more data sources on the fly. %extra = (fee => 'fi', foe => 'fum'); $obj->add (\%extra); # Add a text file as a data source, taking the first "word" up # to whitespace on each line as the key and the rest of the line # as the value. $split = sub { split (' ', $_[0], 2) }; $obj->add ([text => "pairs.txt", $split]); # Add a text file as a data source, splitting each line on # whitespace and taking the first "word" to be the key and an # anonymous array consisting of the remaining words to be the # data. $split = sub { split (' ', $_[0]) }; $obj->add ([text => "triples.txt", $split]); =head1 DESCRIPTION This module merges together multiple sets of data in the form of hashes into a data structure that looks to Perl like a single simple hash. When that hash is accessed, the data structures managed by that shadow hash are searched in order they were added for that key. This allows the rest of a program simple and convenient access to a disparate set of data sources. Tie::ShadowHash can handle anything that looks like a hash; just give it a reference as one of the additional arguments to tie(). This includes other tied hashes, so you can include DB and DBM files as data sources for a shadow hash. If given a plain file name instead of a reference, it will build a hash to use internally, with each chomped line of the file being the key and the number of times that line is seen in the file being the value. Tie::Shadowhash also supports special tagged data sources that can take options specifying their behavior. The only tagged data source currently supported is C, which takes a file name of a text file and a reference to a sub. The sub is called for every line of the file, with that line as an argument, and is expected to return a list. The first element of the list will be the key, and the second and subsequent elements will be the value or values. If there is more than one value, the value stored in the hash and associated with that key is an anonymous array containing all of them. Tagged data sources are distinguished from normal data sources by passing them to tie() (or to add() -- see below) as an anonymous array. The first element is the data source tag and the remaining elements are arguments for that data source. For a text data source, see the usage summary above for examples. The shadow hash can be modified, and the modifications override the data sources, but modifications aren't propagated back to the data sources. In other words, the shadow hash treats all data sources as read-only and saves your modifications only in internal memory. This lets you make changes to the shadow hash for the rest of your program without affecting the underlying data in any way (and this behavior is the main reason why this is called a shadow hash). If the shadow hash is cleared, by assigning the empty list to it, by explicitly calling CLEAR(), or by some other method, all data sources are dropped from the shadow hash. There is no other way of removing a data source from a shadow hash after it's been added (you can, of course, always untie the shadow hash and dispose of the underlying object if you saved it to destroy the shadow hash completely). =head1 INSTANCE METHODS =over 4 =item add(SOURCE [, SOURCE ...]) Adds the given sources to an existing shadow hash. This method can be called on the object returned by the initial tie() call. It takes the same arguments as the initial tie() and interprets them the same way. =back =head1 DIAGNOSTICS =over 4 =item Can't open file %s: %s Tie::ShadowHash was given a file name to use as a source, but when it tried to open that file, the open failed with that system error message. =item Invalid source type %s Tie::Shadowhash was given a tagged data source of an unknown type. The only currently supported tagged data source is C. =back =head1 CAVEATS It's worth paying very careful attention to L when using this module. It's also important to be careful about what you do with tied hashes that are included in a shadow hash. Tie::ShadowHash stores a reference to such arrays; if you untie them out from under a shadow hash, you may not get the results you expect. Remember that if you put something in a shadow hash, you'll need to clean out the shadow hash as well as everything else that references a variable if you want to free it completely. Not all tied hashes implement EXISTS; in particular, ODBM_File, NDBM_File, and some old versions of GDBM_File don't, and therefore AnyDBM_File doesn't either. Calling exists on a shadow hash that includes one of those tied hashes as a data source may therefore result in an exception. Tie::ShadowHash doesn't use exists except to implement the EXISTS method because of this. Because it can't use EXISTS due to the above problem, Tie::ShadowHash cannot correctly distinguish between a non-existent key and an existing key associated with an undefined value. This isn't a large problem, since many tied hashes can't store undefined values anyway, but it means that if one of your data sources contains a given key associated with an undefined value and one of your later data sources contains the same key but with a defined value, when the shadow hash is accessed using that key, it will return the first defined value it finds. This is an exception to the normal rule that all data sources are searched in order and the value returned by an access is the first value found. (Tie::ShadowHash does correctly handle undefined values stored directly in the shadow hash.) =head1 AUTHOR Russ Allbery =head1 COPYRIGHT AND LICENSE Copyright 1999, 2002, 2010 by Russ Allbery This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L The current version of this module is always available from its web site at L. =cut libtie-shadowhash-perl-1.00.orig/README0000644000000000000000000001040211355746064014506 0ustar Tie::ShadowHash version 1.0 (Merge multiple data sources into a hash with overrides) Copyright 1999, 2002, 2010 by Russ Allbery . This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself. I welcome all bug reports and patches for this package (and in particular, if you're looking for a project, see TODO). However, please be aware that I tend to be extremely busy and to get a lot of mail. I'll save your mail and get to it as soon as I can, but depending on how busy I am it may take me a couple of months. BLURB Tie::ShadowHash is a Perl module that lets you stack together multiple hash-like data structures, including tied hashes such as DB_File databases or text files parsed into a hash, and then treat them like a merged hash. Lookups are handled in the order of the added sources. You can store additional values, change values, and delete values from the hash and those actions will be reflected in later operations, but the underlying objects are not changed. DESCRIPTION If you have a bunch of separate sources of data in the form of Perl hashes, tied hashes (of whatever type, including on-disk databases tied with DB_File, GDBM_File, or similar modules), or text files that you want to turn into hashes, and you want to be able to query all of those sources of data at once for a particular key without having to check each one of them individually each time, this module is what you're looking for. If you want to use a hash-like data source, even just one, but make modifications to its data over the course of your program that override its contents while your program runs but which don't have any permanent effect on it, then this module may be what you're looking for. Tie::ShadowHash lets you create a "shadow hash" that looks like a regular Perl hash to your program but behind the scenes queries a whole list of data sources. All the data sources underneath have to also behave like Perl hashes, but that's the only constraint. They can be regular Perl hashes or other tied hashes, including tied DB_File or GDBM_File hashes or the like to access on-disk databases. All data sources are treated as read-only; modifications to any data is stored in the shadow hash itself, and subsequent accesses reflect any modifications, but none of the data sources are changed. See the POD documentation for complete details, features, and usage. REQUIREMENTS Perl 5.006 or later is the only requirement for this module. To run the test suite, Test::More is required. It is available from CPAN and part of Perl core as of 5.6.2. The test suite includes a formatting and spelling check of all of the POD documentation. To check formatting, Test::Pod is required. To check spelling, Pod::Spell and either aspell or ispell with the american dictionary are also required. The user's path is searched for aspell or ispell and aspell is preferred. Spelling tests are disabled by default since spelling dictionaries differ too much between systems. To enable those tests, set RRA_MAINTAINER_TESTS to a true value. INSTALLATION Follow the standard installation procedure for Perl modules, which is to type the following commands: perl Makefile.PL make make test make install You'll probably need to do the "make install" as root. If instead you wish to install the module by hand, simply copy ShadowHash.pm into a directory named Tie in your Perl library directory. HOMEPAGE AND SOURCE REPOSITORY The podlators web page at: http://www.eyrie.org/~eagle/software/shadowhash/ will always have the current version of this package, the current documentation, and pointers to any additional resources. Tie::ShadowHash is maintained using Git. You can access the current source by cloning the repository at: git://git.eyrie.org/perl/shadowhash.git or view the repository on the web at: http://git.eyrie.org/?p=perl/shadowhash.git THANKS To Chris Nandor for testing this module on the Mac, pointing out that SDBM_File wasn't available there, mentioning that SDBM was byte-order-dependent anyway, and suggesting using AnyDBM_File instead. libtie-shadowhash-perl-1.00.orig/MANIFEST0000644000000000000000000000126511355747423014766 0ustar ChangeLog GNU-style change log of package changes Makefile.PL ExtUtils::MakeMaker build and install driver MANIFEST This list of files README General package documentation ShadowHash.pm The Tie::ShadowHash module t/basic.t Basic test suite for Tie::ShadowHash t/data/first.txt Test data for t/basic.t t/data/full Test data for t/basic.t t/data/pairs.txt Test data for t/basic.t t/data/second.txt Test data for t/basic.t t/data/triples.txt Test data for t/basic.t t/pod-spelling.t Test spelling in POD documentation t/pod.t Test POD syntax in documentation TODO General package to-do list META.yml Module meta-data (added by MakeMaker) libtie-shadowhash-perl-1.00.orig/META.yml0000644000000000000000000000104011355747423015075 0ustar --- #YAML:1.0 name: Tie-ShadowHash version: 1.00 abstract: Merge multiple data sources into a hash author: - Russ Allbery license: perl distribution_type: module configure_requires: ExtUtils::MakeMaker: 0 build_requires: ExtUtils::MakeMaker: 0 requires: {} no_index: directory: - t - inc generated_by: ExtUtils::MakeMaker version 6.55_02 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 libtie-shadowhash-perl-1.00.orig/TODO0000644000000000000000000000135411355723622014317 0ustar Tie::ShadowHash To-Do List A list of things planned for the future for this module, in no particular order. As this is a module I can only work on in my free time, or when I need something for something else I'm doing, I probably won't get to any of this as fast as I'd like. If you'd like to implement anything on this list, drop me a line first at rra@stanford.edu and then have at it! Credits will be noted in the README. * A way of removing a specific source from the shadow hash might be nice, but we'd have to solve the naming problem. * Querying the shadow hash for status would also be nice; things like the full source list, the override hash, and the deleted hash could be exposed to the intrepid. libtie-shadowhash-perl-1.00.orig/t/0000755000000000000000000000000011355747423014074 5ustar libtie-shadowhash-perl-1.00.orig/t/pod.t0000755000000000000000000000054111355744626015050 0ustar #!/usr/bin/perl -w # # Test POD formatting. # # Copyright 2009 Russ Allbery # # This program is free software; you may redistribute it and/or modify it # under the same terms as Perl itself. use strict; use Test::More; eval 'use Test::Pod 1.00'; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok (); libtie-shadowhash-perl-1.00.orig/t/data/0000755000000000000000000000000011355747423015005 5ustar libtie-shadowhash-perl-1.00.orig/t/data/full0000644000000000000000000000033511355723622015666 0ustar meta admin sg jp repost precog rev omega lnh hype rp starfall acraphobe racccafe rc3 www ash nop review kewl esp hapcc misc lbp eleck rant raccies grafek wchr ntc sgn osd ntb cleric pulp ip mu raccie dm fcc aep acra acro libtie-shadowhash-perl-1.00.orig/t/data/first.txt0000644000000000000000000000015311355723622016667 0ustar acraphobe acro aep ash dm eleck esp lnh meta misc mu ntb pulp raccies rc3 repost rev review rp sg sgn wchr libtie-shadowhash-perl-1.00.orig/t/data/pairs.txt0000644000000000000000000000006211355723622016655 0ustar apple red or green orange orange banana yellow libtie-shadowhash-perl-1.00.orig/t/data/second.txt0000644000000000000000000000016211355723622017013 0ustar admin jp precog omega hype starfall racccafe www nop kewl hapcc lbp rant grafek ntc osd cleric ip raccie fcc acra libtie-shadowhash-perl-1.00.orig/t/data/triples.txt0000644000000000000000000000017711355723622017230 0ustar comp news.announce.newgroups newsgroups-request@isc.org slac slac.groups news@news.stanford.edu us us.config usadmin@wwa.com libtie-shadowhash-perl-1.00.orig/t/basic.t0000755000000000000000000001432711355744002015342 0ustar #!/usr/bin/perl -w # # Copyright 1999, 2002, 2010 Russ Allbery # # This program is free software; you may redistribute it and/or modify it # under the same terms as Perl itself. use strict; use AnyDBM_File; use Fcntl qw(O_CREAT O_RDONLY O_RDWR); use Test::More tests => 48; require_ok ('Tie::ShadowHash'); # Test setup. Locate the test data directory and then tie an AnyDBM_File # object and create a tied hash with something interesting in it. my $data; for my $dir (qw(./data ./t/data ../t/data)) { $data = $dir if -d $dir; } BAIL_OUT ('Cannot find test data directory') unless $data; my (%hash, $db); $db = tie (%hash, 'AnyDBM_File', "$data/first", O_RDWR | O_CREAT, 0666); BAIL_OUT ('Cannot create AnyDBM_File tied hash') unless $db; open (DATA, '<', "$data/first.txt") or BAIL_OUT ("Can't open $data/first.txt: $!"); while () { chomp; $hash{$_} = 1; } close DATA; undef $db; untie %hash; # Some basic checks against a text file. my $obj = tie (%hash, 'Tie::ShadowHash', "$data/second.txt"); isa_ok ($obj, 'Tie::ShadowHash'); is ($hash{admin}, 1, 'Found existing key in text source'); ok (!exists ($hash{meta}), 'Non-existing key returned false to exists'); $hash{meta} = 2; $hash{admin} = 2; is ($hash{meta}, 2, 'Overriding non-existing key'); is ($hash{admin}, 2, 'Overriding existing key'); is ($hash{jp}, 1, 'Another untouched key is still correct'); delete $hash{jp}; ok (!exists ($hash{jp}), '...and it does not exist after we delete it'); $hash{jp} = 2; is ($hash{jp}, 2, '...and we can set it to another value'); # Tie only the dbm file and check some basic functionality. undef $obj; untie %hash; my %db; unless (tie (%db, 'AnyDBM_File', "$data/first", O_RDONLY, 0666)) { BAIL_OUT ("Cannot tie newly created db file"); } $obj = tie (%hash, 'Tie::ShadowHash', \%db); isa_ok ($obj, 'Tie::ShadowHash'); is ($hash{meta}, 1, 'Found existing key in dbm source'); is ($hash{admin}, undef, 'Non-existing key returns undef'); $hash{admin} = 2; is ($hash{admin}, 2, 'Overriding existing key'); is ($db{admin}, undef, '...and underlying source is unchanged'); delete $hash{meta}; is ($hash{meta}, undef, 'Deleting existing key'); is ($db{meta}, 1, '...and underlying source is unchanged'); # Check clearning the hash. %hash = (); is ($hash{sg}, undef, 'Existing key is undefined after clearing'); # Add back in both the dbm file and the text file. is ($obj->add (\%db, "$data/second.txt"), 1, 'Adding sources'); is ($hash{admin}, 1, 'Found data in text file'); is ($hash{meta}, 1, 'Found data in dbm file'); is ($hash{fooba}, undef, 'Keys missing in both fall through'); # Compare a keys listing with the full data. open (FULL, '<', "$data/full") or BAIL_OUT ("Cannot open $data/full: $!"); my @full = sort ; close FULL; chomp @full; my @keys = sort keys %hash; is_deeply (\@keys, \@full, 'Complete key listing matches'); # Make sure deleted keys are skipped in a key listing. delete $hash{sg}; @keys = keys %hash; is (scalar (@keys), scalar (@full) - 1, 'One fewer key after deletion'); ok (!(grep { $_ eq 'sg' } @keys), '...and the deleted key is missing'); # Add an additional hash with a key that duplicates a key from an earlier hash # and ensure that we don't see it twice in the keys listing. my %extra = (admin => 'foo'); is ($obj->add (\%extra), 1, 'Adding another hash source succeeds'); @keys = keys %hash; is (scalar (@keys), scalar (@full) - 1, 'Duplicate keys do not add to count'); is ($hash{admin}, 1, '...and the earlier source still prevails'); # Restoring the deleted key should increment our key count again. $hash{sg} = 'override'; @keys = keys %hash; is (scalar (@keys), scalar (@full), 'Setting a deleted key restores the count'); # Now add an override and ensure that doesn't cause duplicate keys either, but # adding a new key via an override should increase our key count. $hash{admin} = 'foo'; @keys = keys %hash; is (scalar (@keys), scalar (@full), 'Overriden keys do not add to count'); is ($hash{admin}, 'foo', '...and the override is effective'); $hash{override} = 1; @keys = keys %hash; is (scalar (@keys), scalar (@full) + 1, 'Added keys do add to count'); # Try adding a special text source with a sub to split key and value. %hash = (); is ($obj->add ([text => "$data/pairs.txt", sub { split (' ', $_[0], 2) }]), 1, 'Adding special text source works'); open (FULL, '<', "$data/pairs.txt") or BAIL_OUT ("Cannot open $data/pairs.txt: $!"); my %full; while () { chomp; my ($key, $value) = split (' ', $_, 2); $full{$key} = $value; } close FULL; is (scalar keys (%full), scalar keys (%hash), '...and has correct key count'); for my $key (sort keys %full) { is ($hash{$key}, $full{$key}, "...and value of $key is correct"); } # Add a special text source that returns an array of values. %hash = (); is ($obj->add ([text => "$data/triples.txt", sub { split (' ', $_[0]) }]), 1, 'Adding second special text source works'); open (FULL, '<', "$data/triples.txt") or BAIL_OUT ("Cannot open $data/triples.txt: $!"); undef %full; while () { chomp; my ($key, @value) = split (' ', $_); $full{$key} = [ @value ]; } close FULL; is (scalar keys (%full), scalar keys (%hash), '...and has correct key count'); for my $key (sort keys %full) { is_deeply ($hash{$key}, $full{$key}, "...and value of $key is correct"); } # Test handling of the hash in a scalar context. %hash = (); ok (!scalar %hash, 'Scalar value is false when the hash as been cleared'); %extra = (foo => 1, bar => 1); is ($obj->add (\%extra), 1, 'Adding a hash works'); ok (scalar %hash, '...and now the scalar value is true'); delete $hash{foo}; delete $hash{bar}; ok (!scalar %hash, 'The scalar value is false after deleting both members'); # Ensure that storing an undefined value directly in the shadow hash works # properly with FETCH. %hash = (); is ($obj->add (\%extra), 1, 'Adding the hash again works'); is ($hash{foo}, 1, '...and the value of foo is what we expect'); $hash{foo} = undef; is ($hash{foo}, undef, 'The value is undef after explicitly storing that'); # Clean up after ourselves (delete first* in $data except for first.txt). opendir (DATA, $data) or BAIL_OUT ("Cannot open $data to clean up: $!"); for my $file (grep { /^first/ } readdir DATA) { unlink "$data/$file" unless $file eq 'first.txt'; } closedir DATA; libtie-shadowhash-perl-1.00.orig/t/pod-spelling.t0000755000000000000000000000466111355744626016672 0ustar #!/usr/bin/perl -w # # Check for spelling errors in POD documentation # # Checks all POD files in the tree for spelling problems using Pod::Spell and # either aspell or ispell. aspell is preferred. This test is disabled unless # RRA_MAINTAINER_TESTS is set, since spelling dictionaries vary too much # between environments. # # Copyright 2008, 2009 Russ Allbery # # This program is free software; you may redistribute it and/or modify it # under the same terms as Perl itself. use strict; use Test::More; # Skip all spelling tests unless the maintainer environment variable is set. plan skip_all => 'Spelling tests only run for maintainer' unless $ENV{RRA_MAINTAINER_TESTS}; # Load required Perl modules. eval 'use Test::Pod 1.00'; plan skip_all => 'Test::Pod 1.00 required for testing POD' if $@; eval 'use Pod::Spell'; plan skip_all => 'Pod::Spell required to test POD spelling' if $@; # Locate a spell-checker. hunspell is not currently supported due to its lack # of support for contractions (at least in the version in Debian). my @spell; my %options = (aspell => [ qw(-d en_US --home-dir=./ list) ], ispell => [ qw(-d american -l -p /dev/null) ]); SEARCH: for my $program (qw/aspell ispell/) { for my $dir (split ':', $ENV{PATH}) { if (-x "$dir/$program") { @spell = ("$dir/$program", @{ $options{$program} }); } last SEARCH if @spell; } } plan skip_all => 'aspell or ispell required to test POD spelling' unless @spell; # Prerequisites are satisfied, so we're going to do some testing. Figure out # what POD files we have and from that develop our plan. $| = 1; my @pod = all_pod_files (); plan tests => scalar @pod; # Finally, do the checks. for my $pod (@pod) { my $child = open (CHILD, '-|'); if (not defined $child) { die "Cannot fork: $!\n"; } elsif ($child == 0) { my $pid = open (SPELL, '|-', @spell) or die "Cannot run @spell: $!\n"; open (POD, '<', $pod) or die "Cannot open $pod: $!\n"; my $parser = Pod::Spell->new; $parser->parse_from_filehandle (\*POD, \*SPELL); close POD; close SPELL; exit ($? >> 8); } else { my @words = ; close CHILD; SKIP: { skip "@spell failed for $pod", 1 unless $? == 0; for (@words) { s/^\s+//; s/\s+$//; } is ("@words", '', $pod); } } } libtie-shadowhash-perl-1.00.orig/Makefile.PL0000644000000000000000000000073111355747402015601 0ustar # Makefile.PL for Tie::ShadowHash module. -*- perl -*- use ExtUtils::MakeMaker; WriteMakefile ( NAME => 'Tie::ShadowHash', DISTNAME => 'Tie-ShadowHash', ($] >= 5.005 ? (ABSTRACT => 'Merge multiple data sources into a hash', AUTHOR => 'Russ Allbery ') : ()), ($] >= 5.010 ? (LICENSE => 'perl') : ()), VERSION_FROM => 'ShadowHash.pm', dist => { COMPRESS => 'gzip', SUFFIX => 'gz' } ); libtie-shadowhash-perl-1.00.orig/ChangeLog0000644000000000000000000000717611355747414015416 0ustar 2010-04-03 Russ Allbery * ShadowHash.pm: Tie::ShadowHash 1.0 released. * Makefile.PL: Change the dist name to Tie-ShadowHash. Use angle brackets for my e-mail address. Set the LICENSE parameter for Perl 5.10 or later. * t/pod.t: Test syntactic validity of POD documentation. * t/pod-spelling.t: Test spelling in POD documentation, but only for maintainers. * ShadowHash.pm: Add stopwords for spelling checks. * ShadowHash.pm (FETCH): Correctly return undef if undef was explicitly stored in the hash. * t/basic.t: Test handling of explicit stores of undef values. * t/basic.t: Add some tests for the scalar value of the hash. * ShadowHash.pm: Add explicit documentation for the add() method. Mention that AnyDBM_File doesn't support EXISTS since some of its underlying modules don't. * ShadowHash.pm (NEXTKEY): When traversing the hash, adjust for keys that are shadowed by earlier hashes or by the override hash. Previously, keys that occurred in multiple sources or in the override hash would be returned multiple times by each. * t/basic.t: Test correct override handling on each. * test.pl: Moved to... * t/basic.t: ...here and rewritten to use Test::More. Moved all test data from test to t/data. * ShadowHash.pm: Require Perl 5.006 or later. Use the three argument form of open and declare iterator variables in for statements. Clean up coding style for explicit return and dereferencing. 2002-07-27 Russ Allbery * README: Tie::ShadowHash 0.7 released. * ShadowHash.pm: Add SEE ALSO and COPYRIGHT AND LICENSE sections to the documentation. Reformat for current formatting style. 1999-06-02 Russ Allbery * README: Tie::ShadowHash 0.6 released. * ShadowHash.pm: Added documentation of tagged data sources and of the "text" tagged data source in particular, as well as some examples, now that this has been verified as already working. * test.pl: Added tests for special text data sources that take a filename and a sub that returns a list of key and one or more values. * test/pairs.txt: New file. * test/triples.txt: New file. 1999-04-03 Russ Allbery * README: Tie::ShadowHash 0.5 released. * ShadowHash.pm: Fixed NEXTKEY again; it was skipping over too much of the source when it hit a deleted key. * test.pl: Added a test to ensure that deleted keys don't show up in the keys of the shadow hash. * ShadowHash.pm: Added some comments to the tied hash section of the code, fixed a bug in NEXTKEY where it didn't skip past entries that had been deleted. * test.pl: Switched from using SDBM_File to using AnyDBM_File since for some reason SDBM isn't built on the Mac port. Also switched to building the DBM on the fly before running any tests, since a lot of DBMs, including SDBM, are byte-order-dependent. * test/first.txt: New file. * test/first.dir: Removed. * test/first.pag: Removed. 1999-03-22 Russ Allbery * README: Tie::ShadowHash 0.3 released. * TODO: New file. * ShadowHash.pm: [Revision 0.3] Added documentation. * test/first.dir: New file. * test/first.pag: New file. * test/full: New file. * test/second.txt: New file. * test.pl: New file. * Makefile.PL: New file. * ShadowHash.pm: [Revision 0.2] Don't use exists when finding a key in the databases, since some tied databases can't handle it such as ODBM, NDBM, and SDBM without my patch. This means that keys with undefined values don't correctly override later identical keys with defined values. *sigh* Also, make add() return true. 1999-03-21 Russ Allbery * ShadowHash.pm: [Revision 0.1] New file.