Build.PL | 018 |
Changes | 814 |
MANIFEST | 612 |
META.yml | 031 |
Makefile.PL | 1114 |
README | 77 |
WithDefaults.pm | 6480 |
lib/Hash/WithDefaults.pm | 0629 |
t/01-case_behaviour.t | 0395 |
t/02-case_behaviour_init.t | 01116 |
t/03-defaults.t | 081 |
t/pod-coverage.t | 018 |
t/pod.t | 012 |
test.pl | 170 |
14 files changed (This is a version diff) | 6972347 |
@@ -0,0 +1,18 @@
+use strict;
+use warnings;
+use Module::Build;
+
+my $builder = Module::Build->new(
+ module_name => 'Hash::WithDefaults',
+ license => 'perl',
+ dist_author => 'Jenda Krynicky <Jenda@Krynicky.cz>',
+ dist_version_from => 'lib/Hash/WithDefaults.pm',
+ dist_abstract => 'class for hashes with key-casing requirements supporting defaults',
+ build_requires => {
+ 'Test::More' => 0,
+ },
+ add_to_cleanup => [ 'Hash-WithDefaults-*' ],
+ create_makefile_pl => 'traditional',
+);
+
+$builder->create_build_script();
@@ -1,8 +1,14 @@
-Revision history for Perl extension Hash::WithDefaults.
-
-0.01 Tue Jul 23 17:39:23 2002
- - original version; created by h2xs 1.21 with options
- -X -n Hash::WithDefaults
-
-0.04 Thu Dec 5 13:22 2002 (CET)
- - made public
+Revision history for Perl extension Hash::WithDefaults.
+
+0.01 Tue Jul 23 17:39:23 2002
+ - original version; created by h2xs 1.21 with options
+ -X -n Hash::WithDefaults
+
+0.04 Thu Dec 5 13:22 2002 (CET)
+ - made public
+
+0.05 Sun May 31 2002
+ - -w clean
+ - tests
+ - changed to Module::Build
+ - a few fixes
@@ -1,6 +1,12 @@
-Changes
-Makefile.PL
-MANIFEST
-README
-test.pl
-WithDefaults.pm
+Changes
+Build.PL
+Makefile.PL
+MANIFEST
+README
+lib/Hash/WithDefaults.pm
+t/01-case_behaviour.t
+t/02-case_behaviour_init.t
+t/03-defaults.t
+t/pod.t
+t/pod-coverage.t
+META.yml
@@ -0,0 +1,31 @@
+---
+name: Hash-WithDefaults
+version: 0.05
+author:
+ - 'Jenda Krynicky <Jenda@Krynicky.cz>'
+abstract: class for hashes with key-casing requirements supporting defaults
+license: perl
+resources:
+ license: http://dev.perl.org/licenses/
+build_requires:
+ Test::More: 0
+provides:
+ Hash::WithDefaults:
+ file: lib/Hash/WithDefaults.pm
+ version: 0.05
+ Hash::WithDefaults::lower:
+ file: lib/Hash/WithDefaults.pm
+ Hash::WithDefaults::preserve:
+ file: lib/Hash/WithDefaults.pm
+ Hash::WithDefaults::sensitive:
+ file: lib/Hash/WithDefaults.pm
+ Hash::WithDefaults::tolower:
+ file: lib/Hash/WithDefaults.pm
+ Hash::WithDefaults::toupper:
+ file: lib/Hash/WithDefaults.pm
+ Hash::WithDefaults::upper:
+ file: lib/Hash/WithDefaults.pm
+generated_by: Module::Build version 0.2808
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.2.html
+ version: 1.2
@@ -1,11 +1,14 @@
-use ExtUtils::MakeMaker;
-# See lib/ExtUtils/MakeMaker.pm for details of how to influence
-# the contents of the Makefile that is written.
-WriteMakefile(
- 'NAME' => 'Hash::WithDefaults',
- 'VERSION_FROM' => 'WithDefaults.pm', # finds $VERSION
- 'PREREQ_PM' => {}, # e.g., Module::Name => 1.1
- ($] >= 5.005 ? ## Add these new keywords supported since 5.005
- (ABSTRACT_FROM => 'WithDefaults.pm', # retrieve abstract from module
- AUTHOR => 'Jenda Krynicky (Jenda@Krynicky.cz)') : ()),
-);
+# Note: this file was auto-generated by Module::Build::Compat version 0.03
+use ExtUtils::MakeMaker;
+WriteMakefile
+(
+ 'PL_FILES' => {},
+ 'INSTALLDIRS' => 'site',
+ 'NAME' => 'Hash::WithDefaults',
+ 'EXE_FILES' => [],
+ 'VERSION_FROM' => 'lib/Hash/WithDefaults.pm',
+ 'PREREQ_PM' => {
+ 'Test::More' => 0
+ }
+ )
+;
@@ -1,4 +1,4 @@
-Hash/WithDefaults version 0.04
+Hash/WithDefaults version 0.05
==============================
This module implements hashes that support "defaults". That is you may specify
@@ -9,20 +9,20 @@ INSTALLATION
To install this module type the following:
- perl Makefile.PL
- make
- make test
- make install
+ perl Build.PL
+ Build
+ Build test
+ Build install
DEPENDENCIES
This module requires these other modules and libraries:
- Tie::StdHash
+ none
COPYRIGHT AND LICENCE
-Copyright (C) 2002 Jenda Krynicky <Jenda@Krynicky.cz>
+Copyright (C) 2002-2009 Jenda Krynicky <Jenda@Krynicky.cz>
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
@@ -1,648 +0,0 @@
-package Hash::WithDefaults;
-use strict;
-use Carp;
-require Tie::Hash;
-use vars qw(@ISA $VERSION);
-@ISA = qw(Tie::StdHash);
-$VERSION = '0.04';
-
-sub DATA () {0}
-sub DEFAULTS () {1}
-sub ACTDEFAULT () {2}
-sub SEEN () {3}
-
-sub makeTIEHASH {
- my ($class, $set) = @_;
- $class = 'Hash::WithDefaults::' . $class;
- eval "sub ${class}::TIEHASH {" . <<'*END*' . "\t\t\t" . $set . <<'*END*' . "\t\t\t" . $set . <<'*END*';
- my $class = shift();
- my $data = {};
-
- if (! @_) {
- # no parameters
- return bless [ $data, []], $class;
- }
-
- if (@_ == 1 and ref $_[0] eq 'HASH') {
- my $input=$_[0];
- my ($key,$value);
- while (($key,$value) = each(%$input)) {
-*END*
-
- }
- } else {
- my ($i, $arr) = (0);
- if (ref $_[0] eq 'ARRAY') {
- $arr = $_[0];
- } elsif (@_ % 2 == 0) {
- $arr = \@_;
- } else {
- croak "Ussage: tie %hashname, $class, \%hash\n or tie %hashname, $class, \\\%hash\n or tie %hashname, $class, \\\@array\n";
- }
- while ($i <= $#$arr) {
- my ($key,$value)=($arr->[$i],$arr->[$i+1]); $i+=2;
-*END*
-
- }
- }
-
- bless [$data, []];
-}
-*END*
-}
-
-makeTIEHASH 'sensitive', '$data->{$key} = $value;';
-makeTIEHASH 'tolower', '$data->{lc $key} = $value;';
-makeTIEHASH 'toupper', '$data->{uc $key} = $value;';
-makeTIEHASH 'lower', '$data->{lc $key} = $value;';
-makeTIEHASH 'upper', '$data->{uc $key} = $value;';
-makeTIEHASH 'preserve', '$data->{lc $key} = [$key,$value];';
-
-sub TIEHASH {
- shift(); # shift out class name
- if (@_ == 0) {
- # no parameters
- unshift @_, 'Hash::WithDefaults::preserve';
- goto &Hash::WithDefaults::preserve::TIEHASH;
- }
-
- if (!ref $_[0] and (ref $_[1] eq 'HASH' or @_ % 2 == 1)) {
- # type plus either \%hash or %hash
- my $type = lc(splice(@_, 0, 1));
- if ($type =~ /^(?:sensitive|preserve|lower|upper|tolower|toupper)$/) {
- unshift @_, 'Hash::WithDefaults::' . $type;
- no strict 'refs';
- goto &{"Hash::WithDefaults::".$type."::TIEHASH"};
- } else {
- croak "Unknown type '$type'! Use one of:\n\tsensitive, preserve, lower, upper, tolower, toupper";
- }
- } else {
- unshift @_, 'Hash::WithDefaults::preserve';
- goto &Hash::WithDefaults::preserve::TIEHASH;
- }
-}
-
-sub AddDefault {
- push @{$_[0]->[DEFAULTS]}, $_[1];
- return 1;
-}
-
-sub GetDefaults {
- my $self = shift;
- return $self->[DEFAULTS];
-}
-
-sub CLEAR {
- my $self = shift;
- undef $self->[SEEN];
- undef $self->[ACTDEFAULT];
- $self
-}
-
-
-#############################
-
-package Hash::WithDefaults::preserve;
-BEGIN {*Hash::WithDefaults::Preserve:: = \%Hash::WithDefaults::preserve::;}
-@Hash::WithDefaults::preserve::ISA = qw(Hash::WithDefaults);
-sub DATA () {0}
-sub DEFAULTS () {1}
-sub ACTDEFAULT () {2}
-sub SEEN () {3}
-
-sub TIEHASH {
- splice( @_, 1, 0, 'preserve');
- goto &Hash::WithDefaults::TIEHASH;
-}
-
-sub STORE {
- $_[0]->[DATA]->{lc $_[1]} = [$_[1],$_[2]];
-}
-
-sub FETCH {
- my $lc_key = lc $_[1];
- return ${$_[0]->[DATA]->{$lc_key}}[1]
- if exists $_[0]->[DATA]->{$lc_key};
-
- foreach my $default (@{$_[0]->[DEFAULTS]}) {
- return $default->{$_[1]}
- if exists($default->{$_[1]});
- }
-
- return;
-}
-
-sub EXISTS {
- return 1
- if exists $_[0]->[DATA]->{lc $_[1]};
-
- foreach my $default (@{$_[0]->[DEFAULTS]}) {
- return 1
- if exists($default->{$_[1]});
- }
-
- return;
-}
-
-sub DELETE {
- delete $_[0]->[DATA]->{lc $_[1]}
-}
-
-sub FIRSTKEY {
- my $self = $_[0];
- undef $self->[ACTDEFAULT];
- $self->[SEEN] = {};
- keys %{$self->[DATA]};
- my ($key,$val);
- if (($key,$val) = each %{$self->[DATA]}) {
- $self->[SEEN]->{$key}=1;
- return wantarray ? ($val->[0], $val->[1]) : $val->[0];
- } elsif (@{$self->[DEFAULTS]}) {
- return $self->NEXTKEY();
- } else {
- return;
- }
-}
-
-sub NEXTKEY {
- my $self = $_[0];
- my $seen = $self->[SEEN];
- my ($key,$val);
- if (!defined $self->[ACTDEFAULT]) {
- # processing the base hash
- if (($key,$val) = each %{$self->[DATA]}) {
- $seen->{$key}=1;
- return wantarray ? ($val->[0], $val->[1]) : $val->[0];
- } else {
- # base hash done
- if (! @{$self->[DEFAULTS]}) {
- # no defaults
- return;
- } else {
- $self->[ACTDEFAULT]=0;
- # reset the first default
- keys %{$self->[DEFAULTS]->[0]};
- }
- }
- }
-
- while (exists $self->[DEFAULTS]->[$self->[ACTDEFAULT]]) {
- while (($key,$val) = each %{$self->[DEFAULTS]->[$self->[ACTDEFAULT]]}) {
- return wantarray ? ($key, $val) : $key
- unless $seen->{lc $key}++;
- }
-
- $self->[ACTDEFAULT]++;
- keys %{$self->[DEFAULTS]->[$self->[ACTDEFAULT]]}
- if exists $self->[DEFAULTS]->[$self->[ACTDEFAULT]];
- }
-
- # all hashes done. Cleanup
- undef $self->[SEEN];
- undef $self->[ACTDEFAULT];
- return;
-}
-
-#############################
-
-package Hash::WithDefaults::lower;
-BEGIN {*Hash::WithDefaults::Lower:: = \%Hash::WithDefaults::lower::;}
-@Hash::WithDefaults::lower::ISA = qw(Hash::WithDefaults::preserve);
-sub DATA () {0}
-sub DEFAULTS () {1}
-sub ACTDEFAULT () {2}
-sub SEEN () {3}
-
-sub TIEHASH {
- splice( @_, 1, 0, 'lower');
- goto &Hash::WithDefaults::TIEHASH;
-}
-
-sub STORE {
- $_[0]->[DATA]->{lc $_[1]} = $_[2];
-}
-
-sub FETCH {
- return $_[0]->[DATA]->{lc $_[1]}
- if exists $_[0]->[DATA]->{lc $_[1]};
-
- foreach my $default (@{$_[0]->[DEFAULTS]}) {
- return $default->{$_[1]}
- if exists($default->{$_[1]});
- }
-
- return;
-}
-
-sub EXISTS {
- return 1
- if exists $_[0]->[DATA]->{lc $_[1]};
-
- foreach my $default (@{$_[0]->[DEFAULTS]}) {
- return 1
- if exists($default->{$_[1]});
- }
-
- return;
-}
-
-sub DELETE {
- delete $_[0]->[DATA]->{lc $_[1]}
-}
-
-sub FIRSTKEY {
- my $self = $_[0];
- $self->[ACTDEFAULT] = -1;
- $self->[SEEN] = {};
- keys %{$self->[DATA]};
- my ($key,$val);
- if (($key,$val) = each %{$self->[DATA]}) {
- $self->[SEEN]->{$key}=1;
- return wantarray ? ($key, $val) : $key;
- } elsif (@{$self->[DEFAULTS]}) {
- return $self->NEXTKEY();
- } else {
- return;
- }
-}
-
-sub NEXTKEY {
- my $self = $_[0];
- my $seen = $self->[SEEN];
- my $defaults = $self->[DEFAULTS];
- my ($key,$val);
- if ($self->[ACTDEFAULT] == -1) {
- # processing the base hash
- if (($key,$val) = each %{$self->[DATA]}) {
- $seen->{$key}=1;
- return wantarray ? ($key, $val) : $key;
- } else {
- # base hash done
- $self->[ACTDEFAULT]=0;
- if (! @$defaults) {
- # no defaults
- return;
- } else {
- # reset the first default
- keys %{$defaults->[0]};
- }
- }
- }
- while (exists $defaults->[$self->[ACTDEFAULT]]) {
- while (($key,$val) = each %{$defaults->[$self->[ACTDEFAULT]]}) {
- return wantarray ? ($key, $val) : $key
- unless $seen->{lc $key}++;
- }
-
- $self->[ACTDEFAULT]++;
- keys %{$defaults->[$self->[ACTDEFAULT]]}
- if exists $defaults->[$self->[ACTDEFAULT]];
- }
-
- # all hashes done. Cleanup
- undef $self->[SEEN];
- undef $self->[ACTDEFAULT];
- return;
-}
-
-#############################
-
-package Hash::WithDefaults::upper;
-BEGIN {*Hash::WithDefaults::Upper:: = \%Hash::WithDefaults::upper::;}
-@Hash::WithDefaults::upper::ISA = qw(Hash::WithDefaults::preserve);
-sub DATA () {0}
-sub DEFAULTS () {1}
-sub ACTDEFAULT () {2}
-sub SEEN () {3}
-
-sub TIEHASH {
- splice( @_, 1, 0, 'upper');
- goto &Hash::WithDefaults::TIEHASH;
-}
-
-sub STORE {
- $_[0]->[DATA]->{uc $_[1]} = $_[2];
-}
-
-sub FETCH {
- return $_[0]->[DATA]->{uc $_[1]}
- if exists $_[0]->[DATA]->{uc $_[1]};
-
- foreach my $default (@{$_[0]->[DEFAULTS]}) {
- return $default->{$_[1]}
- if exists($default->{$_[1]});
- }
-
- return;
-}
-
-sub EXISTS {
- return 1
- if exists $_[0]->[DATA]->{uc $_[1]};
-
- foreach my $default (@{$_[0]->[DEFAULTS]}) {
- return 1
- if exists($default->{$_[1]});
- }
-
- return;
-}
-
-sub DELETE {
- delete $_[0]->[DATA]->{uc $_[1]}
-}
-
-sub FIRSTKEY {
- my $self = $_[0];
- $self->[ACTDEFAULT] = -1;
- $self->[SEEN] = {};
- keys %{$self->[DATA]};
- my ($key,$val);
- if (($key,$val) = each %{$self->[DATA]}) {
- $self->[SEEN]->{$key}=1;
- return wantarray ? ($key, $val) : $key;
- } elsif (@{$self->[DEFAULTS]}) {
- return $self->NEXTKEY();
- } else {
- return;
- }
-}
-
-sub NEXTKEY {
- my $self = $_[0];
- my $seen = $self->[SEEN];
- my $defaults = $self->[DEFAULTS];
- my ($key,$val);
- if ($self->[ACTDEFAULT] == -1) {
- # processing the base hash
- if (($key,$val) = each %{$self->[DATA]}) {
- $seen->{$key}=1;
- return wantarray ? ($key, $val) : $key;
- } else {
- # base hash done
- $self->[ACTDEFAULT]=0;
- if (! @$defaults) {
- # no defaults
- return;
- } else {
- # reset the first default
- keys %{$defaults->[0]};
- }
- }
- }
- while (exists $defaults->[$self->[ACTDEFAULT]]) {
- while (($key,$val) = each %{$defaults->[$self->[ACTDEFAULT]]}) {
- return wantarray ? ($key, $val) : $key
- unless $seen->{uc $key}++;
- }
-
- $self->[ACTDEFAULT]++;
- keys %{$defaults->[$self->[ACTDEFAULT]]}
- if exists $defaults->[$self->[ACTDEFAULT]];
- }
-
- # all hashes done. Cleanup
- undef $self->[SEEN];
- undef $self->[ACTDEFAULT];
- return;
-}
-
-
-#############################
-
-package Hash::WithDefaults::sensitive;
-BEGIN {*Hash::WithDefaults::Sensitive:: = \%Hash::WithDefaults::sensitive::;}
-@Hash::WithDefaults::sensitive::ISA = qw(Hash::WithDefaults);
-sub DATA () {0}
-sub DEFAULTS () {1}
-sub ACTDEFAULT () {2}
-sub SEEN () {3}
-
-sub TIEHASH {
- splice( @_, 1, 0, 'sensitive');
- goto &Hash::WithDefaults::TIEHASH;
-}
-
-sub STORE {
- $_[0]->[DATA]->{$_[1]} = $_[2];
-}
-
-sub FETCH {
- return $_[0]->[DATA]->{$_[1]}
- if exists $_[0]->[DATA]->{$_[1]};
-
- foreach my $default (@{$_[0]->[DEFAULTS]}) {
- return $default->{$_[1]}
- if exists($default->{$_[1]});
- }
-
- return;
-}
-
-sub EXISTS {
- return 1
- if exists $_[0]->[DATA]->{$_[1]};
-
- foreach my $default (@{$_[0]->[DEFAULTS]}) {
- return 1
- if exists($default->{$_[1]});
- }
-
- return;
-}
-
-sub DELETE {
- delete $_[0]->[DATA]->{$_[1]}
-}
-
-sub FIRSTKEY {
- my $self = $_[0];
- $self->[ACTDEFAULT] = -1;
- $self->[SEEN] = {};
- keys %{$self->[DATA]};
- my ($key,$val);
- if (($key,$val) = each %{$self->[DATA]}) {
- $self->[SEEN]->{$key}=1;
- return wantarray ? ($key, $val) : $key;
- } elsif (@{$self->[DEFAULTS]}) {
- return $self->NEXTKEY();
- } else {
- return;
- }
-}
-
-sub NEXTKEY {
- my $self = $_[0];
- my $seen = $self->[SEEN];
- my $defaults = $self->[DEFAULTS];
- my ($key,$val);
- if ($self->[ACTDEFAULT] == -1) {
- # processing the base hash
- if (($key,$val) = each %{$self->[DATA]}) {
- $seen->{$key}=1;
- return wantarray ? ($key, $val) : $key;
- } else {
- # base hash done
- $self->[ACTDEFAULT]=0;
- if (! @$defaults) {
- # no defaults
- return;
- } else {
- # reset the first default
- keys %{$defaults->[0]};
- }
- }
- }
- while (exists $defaults->[$self->[ACTDEFAULT]]) {
- while (($key,$val) = each %{$defaults->[$self->[ACTDEFAULT]]}) {
- return wantarray ? ($key, $val) : $key
- unless $seen->{$key}++;
- }
-
- $self->[ACTDEFAULT]++;
- keys %{$defaults->[$self->[ACTDEFAULT]]}
- if exists $defaults->[$self->[ACTDEFAULT]];
- }
-
- # all hashes done. Cleanup
- undef $self->[SEEN];
- undef $self->[ACTDEFAULT];
- return;
-}
-
-
-#############################
-
-package Hash::WithDefaults::toupper;
-BEGIN {*Hash::WithDefaults::Toupper:: = \%Hash::WithDefaults::toupper::;}
-@Hash::WithDefaults::toupper::ISA = qw(Hash::WithDefaults::sensitive);
-sub DATA () {0}
-sub DEFAULTS () {1}
-sub ACTDEFAULT () {2}
-sub SEEN () {3}
-
-sub TIEHASH {
- splice( @_, 1, 0, 'toupper');
- goto &Hash::WithDefaults::TIEHASH;
-}
-
-sub STORE {
- $_[0]->[DATA]->{uc $_[1]} = $_[2];
-}
-
-#############################
-
-package Hash::WithDefaults::tolower;
-BEGIN {*Hash::WithDefaults::Tolower:: = \%Hash::WithDefaults::tolower::;}
-@Hash::WithDefaults::tolower::ISA = qw(Hash::WithDefaults::sensitive);
-sub DATA () {0}
-sub DEFAULTS () {1}
-sub ACTDEFAULT () {2}
-sub SEEN () {3}
-
-sub TIEHASH {
- splice( @_, 1, 0, 'tolower');
- goto &Hash::WithDefaults::TIEHASH;
-}
-
-sub STORE {
- $_[0]->[DATA]->{lc $_[1]} = $_[2];
-}
-
-1;
-
-__END__
-=head1 NAME
-
-Hash::WithDefaults - class for hashes with key-casing requirements supporting defaults
-
-version 0.04
-
-=head1 SYNOPSIS
-
- use Hash::WithDefaults;
-
- %main = ( ... );
- tie %h1, 'Hash::WithDefaults', {...};
- tied(%h1)->AddDefault(\%main);
- tie %h2, 'Hash::WithDefaults', {...};
- tied(%h2)->AddDefault(\%main);
-
- # now if you use $h1{$key}, the value is looked up first
- # in %h1, then in %main.
-
-=head1 DESCRIPTION
-
-This module implements hashes that support "defaults". That is you may specify
-several more hashes in which the data will be looked up in case it is not found in
-the current hash.
-
-=head2 Object creation
-
- tie %hash, 'Hash::WithDefault', [$case_option], [\%values];
- tie %hash, 'Hash::WithDefault', [$case_option], [%values];
-
-The optional $case_option may be one of these values:
-
- Sensitive - the hash will be case sensitive
- Tolower - the hash will be case sensitive, all keys are made lowercase
- Toupper - the hash will be case sensitive, all keys are made uppercase
- Preserve - the hash will be case insensitive, the case is preserved
- Lower - the hash will be case insensitive, all keys are made lowercase
- Upper - the hash will be case insensitive, all keys are made uppercase
-
-If you pass a hash reference or an even list of keys and values to the tie() function,
-those keys and values will be COPIED to the resulting magical hash!
-
-After you tie() the hash, you use it just like any other hash.
-
-=head2 Functions
-
-=head3 AddDefault
-
- tied(%hash)->AddDefault(\%defaults);
-
-This instructs the object to include the %defaults in the search for values.
-After this the value will be looked up first in %hash itself and then in %defaults.
-
-You may keep modifying the %defaults and your changes WILL be visible through %hash!
-
-You may add as many defaults to one Hash::WithDefaults object as you like.
-
-=head3 GetDefaults
-
- $defaults = tied(%hash)->GetDefaults();
- push @$defaults, \%another_default;
-
-Returns a reference to the array that stores the defaults.
-You may delete or insert hash references into the array, but make sure you
-NEVER EVER insert anything else than a hash reference into the array!
-
-=head2 Config::IniHash example
-
- use Config::IniHash;
- $config = ReadIni $inifile, withdefaults => 1, insensitive => 'preserve';
-
- if (exists $config->{':default'}) {
- my $default = $config->{':default'};
- foreach my $section (keys %$config) {
- next if $section =~ /^:/;
- tied(%{$config->{$section}})->AddDefault($default)
- }
- }
-
-And now all normal sections will get the default values from [:default] section ;-)
-
-=head1 AUTHOR
-
-Jan Krynicky <Jenda@Krynicky.cz>
-http://Jenda.Krynicky.cz
-
-=head1 COPYRIGHT
-
-Copyright (c) 2002 Jan Krynicky <Jenda@Krynicky.cz>. All rights reserved.
-
-This program is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=cut
@@ -0,0 +1,629 @@
+package Hash::WithDefaults;
+use strict;
+use Carp;
+require Tie::Hash;
+use vars qw(@ISA $VERSION);
+@ISA = qw(Tie::StdHash);
+$VERSION = '0.05';
+
+sub _DATA () {0}
+sub _DEFAULTS () {1}
+sub _ACTDEFAULT () {2}
+sub _SEEN () {3}
+
+sub _makeTIEHASH {
+ my ($class, $set) = @_;
+ $class = 'Hash::WithDefaults::' . $class;
+ eval "sub ${class}::TIEHASH {" . <<'*END*' . "\t\t\t" . $set . <<'*END*' . "\t\t\t" . $set . <<'*END*';
+ my $class = shift();
+ my $data = {};
+
+ if (! @_) {
+ # no parameters
+ return bless [ $data, []], $class;
+ }
+
+ if (@_ == 1 and ref $_[0] eq 'HASH') {
+ my $input=$_[0];
+ my ($key,$value);
+ while (($key,$value) = each(%$input)) {
+*END*
+
+ }
+ } else {
+ my ($i, $arr) = (0);
+ if (ref $_[0] eq 'ARRAY') {
+ $arr = $_[0];
+ } elsif (@_ % 2 == 0) {
+ $arr = \@_;
+ } else {
+ croak "Ussage: tie %hashname, $class, \%hash\n or tie %hashname, $class, \\\%hash\n or tie %hashname, $class, \\\@array\n";
+ }
+ while ($i <= $#$arr) {
+ my ($key,$value)=($arr->[$i],$arr->[$i+1]); $i+=2;
+*END*
+
+ }
+ }
+
+ bless [$data, []], $class;
+}
+*END*
+}
+
+_makeTIEHASH 'sensitive', '$data->{$key} = $value;';
+_makeTIEHASH 'tolower', '$data->{lc $key} = $value;';
+_makeTIEHASH 'toupper', '$data->{uc $key} = $value;';
+_makeTIEHASH 'lower', '$data->{lc $key} = $value;';
+_makeTIEHASH 'upper', '$data->{uc $key} = $value;';
+_makeTIEHASH 'preserve', '$data->{lc $key} = [$key,$value];';
+
+sub TIEHASH {
+ shift(); # shift out class name
+ if (@_ == 0) {
+ # no parameters
+ unshift @_, 'Hash::WithDefaults::preserve';
+ goto &Hash::WithDefaults::preserve::TIEHASH;
+ }
+
+ if (!ref $_[0] and (ref $_[1] eq 'HASH' or ref $_[1] eq 'ARRAY' or @_ % 2 == 1)) {
+ # type plus either \%hash or %hash
+ my $type = lc(splice(@_, 0, 1));
+ if ($type =~ /^(?:sensitive|preserve|lower|upper|tolower|toupper)$/) {
+ unshift @_, 'Hash::WithDefaults::' . $type;
+ no strict 'refs';
+ goto &{"Hash::WithDefaults::".$type."::TIEHASH"};
+ } else {
+ croak "Unknown type '$type'! Use one of:\n\tsensitive, preserve, lower, upper, tolower, toupper";
+ }
+ } else {
+ unshift @_, 'Hash::WithDefaults::preserve';
+ goto &Hash::WithDefaults::preserve::TIEHASH;
+ }
+}
+
+sub AddDefault {
+ push @{$_[0]->[_DEFAULTS]}, $_[1];
+ return 1;
+}
+
+sub GetDefaults {
+ my $self = shift;
+ return $self->[_DEFAULTS];
+}
+
+sub CLEAR {
+ my $self = shift;
+ undef $self->[_DATA];
+ @{$self->[_DEFAULTS]} = ();
+ undef $self->[_SEEN];
+ undef $self->[_ACTDEFAULT];
+ $self
+}
+
+
+#############################
+
+package Hash::WithDefaults::preserve;
+BEGIN {*Hash::WithDefaults::Preserve:: = \%Hash::WithDefaults::preserve::;}
+@Hash::WithDefaults::preserve::ISA = qw(Hash::WithDefaults);
+sub _DATA () {0}
+sub _DEFAULTS () {1}
+sub _ACTDEFAULT () {2}
+sub _SEEN () {3}
+
+
+sub STORE {
+ $_[0]->[_DATA]->{lc $_[1]} = [$_[1],$_[2]];
+}
+
+sub FETCH {
+ my $lc_key = lc $_[1];
+ return ${$_[0]->[_DATA]->{$lc_key}}[1]
+ if exists $_[0]->[_DATA]->{$lc_key};
+
+ foreach my $default (@{$_[0]->[_DEFAULTS]}) {
+ return $default->{$_[1]}
+ if exists($default->{$_[1]});
+ }
+
+ return;
+}
+
+sub EXISTS {
+ return 1
+ if exists $_[0]->[_DATA]->{lc $_[1]};
+
+ foreach my $default (@{$_[0]->[_DEFAULTS]}) {
+ return 1
+ if exists($default->{$_[1]});
+ }
+
+ return;
+}
+
+sub DELETE {
+ delete $_[0]->[_DATA]->{lc $_[1]}
+}
+
+sub FIRSTKEY {
+ my $self = $_[0];
+ undef $self->[_ACTDEFAULT];
+ $self->[_SEEN] = {};
+ keys %{$self->[_DATA]};
+ my ($key,$val);
+ if (($key,$val) = each %{$self->[_DATA]}) {
+ $self->[_SEEN]->{$key}=1;
+ return wantarray ? ($val->[0], $val->[1]) : $val->[0];
+ } elsif (@{$self->[_DEFAULTS]}) {
+ return $self->NEXTKEY();
+ } else {
+ return;
+ }
+}
+
+sub NEXTKEY {
+ my $self = $_[0];
+ my $seen = $self->[_SEEN];
+ my ($key,$val);
+ if (!defined $self->[_ACTDEFAULT]) {
+ # processing the base hash
+ if (($key,$val) = each %{$self->[_DATA]}) {
+ $seen->{$key}=1;
+ return wantarray ? ($val->[0], $val->[1]) : $val->[0];
+ } else {
+ # base hash done
+ if (! @{$self->[_DEFAULTS]}) {
+ # no defaults
+ return;
+ } else {
+ $self->[_ACTDEFAULT]=0;
+ # reset the first default
+ keys %{$self->[_DEFAULTS]->[0]};
+ }
+ }
+ }
+
+ while (exists $self->[_DEFAULTS]->[$self->[_ACTDEFAULT]]) {
+ while (($key,$val) = each %{$self->[_DEFAULTS]->[$self->[_ACTDEFAULT]]}) {
+ return wantarray ? ($key, $val) : $key
+ unless $seen->{lc $key}++;
+ }
+
+ $self->[_ACTDEFAULT]++;
+ keys %{$self->[_DEFAULTS]->[$self->[_ACTDEFAULT]]}
+ if exists $self->[_DEFAULTS]->[$self->[_ACTDEFAULT]];
+ }
+
+ # all hashes done. Cleanup
+ undef $self->[_SEEN];
+ undef $self->[_ACTDEFAULT];
+ return;
+}
+
+#############################
+
+package Hash::WithDefaults::lower;
+BEGIN {*Hash::WithDefaults::Lower:: = \%Hash::WithDefaults::lower::;}
+@Hash::WithDefaults::lower::ISA = qw(Hash::WithDefaults::preserve);
+sub _DATA () {0}
+sub _DEFAULTS () {1}
+sub _ACTDEFAULT () {2}
+sub _SEEN () {3}
+
+sub STORE {
+ $_[0]->[_DATA]->{lc $_[1]} = $_[2];
+}
+
+sub FETCH {
+ return $_[0]->[_DATA]->{lc $_[1]}
+ if exists $_[0]->[_DATA]->{lc $_[1]};
+
+ foreach my $default (@{$_[0]->[_DEFAULTS]}) {
+ return $default->{$_[1]}
+ if exists($default->{$_[1]});
+ }
+
+ return;
+}
+
+sub EXISTS {
+ return 1
+ if exists $_[0]->[_DATA]->{lc $_[1]};
+
+ foreach my $default (@{$_[0]->[_DEFAULTS]}) {
+ return 1
+ if exists($default->{$_[1]});
+ }
+
+ return;
+}
+
+sub DELETE {
+ delete $_[0]->[_DATA]->{lc $_[1]}
+}
+
+sub FIRSTKEY {
+ my $self = $_[0];
+ $self->[_ACTDEFAULT] = -1;
+ $self->[_SEEN] = {};
+ keys %{$self->[_DATA]};
+ my ($key,$val);
+ if (($key,$val) = each %{$self->[_DATA]}) {
+ $self->[_SEEN]->{$key}=1;
+ return wantarray ? ($key, $val) : $key;
+ } elsif (@{$self->[_DEFAULTS]}) {
+ return $self->NEXTKEY();
+ } else {
+ return;
+ }
+}
+
+sub NEXTKEY {
+ my $self = $_[0];
+ my $seen = $self->[_SEEN];
+ my $defaults = $self->[_DEFAULTS];
+ my ($key,$val);
+ if ($self->[_ACTDEFAULT] == -1) {
+ # processing the base hash
+ if (($key,$val) = each %{$self->[_DATA]}) {
+ $seen->{$key}=1;
+ return wantarray ? ($key, $val) : $key;
+ } else {
+ # base hash done
+ $self->[_ACTDEFAULT]=0;
+ if (! @$defaults) {
+ # no defaults
+ return;
+ } else {
+ # reset the first default
+ keys %{$defaults->[0]};
+ }
+ }
+ }
+ while (exists $defaults->[$self->[_ACTDEFAULT]]) {
+ while (($key,$val) = each %{$defaults->[$self->[_ACTDEFAULT]]}) {
+ return wantarray ? ($key, $val) : $key
+ unless $seen->{lc $key}++;
+ }
+
+ $self->[_ACTDEFAULT]++;
+ keys %{$defaults->[$self->[_ACTDEFAULT]]}
+ if exists $defaults->[$self->[_ACTDEFAULT]];
+ }
+
+ # all hashes done. Cleanup
+ undef $self->[_SEEN];
+ undef $self->[_ACTDEFAULT];
+ return;
+}
+
+#############################
+
+package Hash::WithDefaults::upper;
+BEGIN {*Hash::WithDefaults::Upper:: = \%Hash::WithDefaults::upper::;}
+@Hash::WithDefaults::upper::ISA = qw(Hash::WithDefaults::preserve);
+sub _DATA () {0}
+sub _DEFAULTS () {1}
+sub _ACTDEFAULT () {2}
+sub _SEEN () {3}
+
+sub STORE {
+ $_[0]->[_DATA]->{uc $_[1]} = $_[2];
+}
+
+sub FETCH {
+ return $_[0]->[_DATA]->{uc $_[1]}
+ if exists $_[0]->[_DATA]->{uc $_[1]};
+
+ foreach my $default (@{$_[0]->[_DEFAULTS]}) {
+ return $default->{$_[1]}
+ if exists($default->{$_[1]});
+ }
+
+ return;
+}
+
+sub EXISTS {
+ return 1
+ if exists $_[0]->[_DATA]->{uc $_[1]};
+
+ foreach my $default (@{$_[0]->[_DEFAULTS]}) {
+ return 1
+ if exists($default->{$_[1]});
+ }
+
+ return;
+}
+
+sub DELETE {
+ delete $_[0]->[_DATA]->{uc $_[1]}
+}
+
+sub FIRSTKEY {
+ my $self = $_[0];
+ $self->[_ACTDEFAULT] = -1;
+ $self->[_SEEN] = {};
+ keys %{$self->[_DATA]};
+ my ($key,$val);
+ if (($key,$val) = each %{$self->[_DATA]}) {
+ $self->[_SEEN]->{$key}=1;
+ return wantarray ? ($key, $val) : $key;
+ } elsif (@{$self->[_DEFAULTS]}) {
+ return $self->NEXTKEY();
+ } else {
+ return;
+ }
+}
+
+sub NEXTKEY {
+ my $self = $_[0];
+ my $seen = $self->[_SEEN];
+ my $defaults = $self->[_DEFAULTS];
+ my ($key,$val);
+ if ($self->[_ACTDEFAULT] == -1) {
+ # processing the base hash
+ if (($key,$val) = each %{$self->[_DATA]}) {
+ $seen->{$key}=1;
+ return wantarray ? ($key, $val) : $key;
+ } else {
+ # base hash done
+ $self->[_ACTDEFAULT]=0;
+ if (! @$defaults) {
+ # no defaults
+ return;
+ } else {
+ # reset the first default
+ keys %{$defaults->[0]};
+ }
+ }
+ }
+ while (exists $defaults->[$self->[_ACTDEFAULT]]) {
+ while (($key,$val) = each %{$defaults->[$self->[_ACTDEFAULT]]}) {
+ return wantarray ? ($key, $val) : $key
+ unless $seen->{uc $key}++;
+ }
+
+ $self->[_ACTDEFAULT]++;
+ keys %{$defaults->[$self->[_ACTDEFAULT]]}
+ if exists $defaults->[$self->[_ACTDEFAULT]];
+ }
+
+ # all hashes done. Cleanup
+ undef $self->[_SEEN];
+ undef $self->[_ACTDEFAULT];
+ return;
+}
+
+
+#############################
+
+package Hash::WithDefaults::sensitive;
+BEGIN {*Hash::WithDefaults::Sensitive:: = \%Hash::WithDefaults::sensitive::;}
+@Hash::WithDefaults::sensitive::ISA = qw(Hash::WithDefaults);
+sub _DATA () {0}
+sub _DEFAULTS () {1}
+sub _ACTDEFAULT () {2}
+sub _SEEN () {3}
+
+sub STORE {
+ $_[0]->[_DATA]->{$_[1]} = $_[2];
+}
+
+sub FETCH {
+ return $_[0]->[_DATA]->{$_[1]}
+ if exists $_[0]->[_DATA]->{$_[1]};
+
+ foreach my $default (@{$_[0]->[_DEFAULTS]}) {
+ return $default->{$_[1]}
+ if exists($default->{$_[1]});
+ }
+
+ return;
+}
+
+sub EXISTS {
+ return 1
+ if exists $_[0]->[_DATA]->{$_[1]};
+
+ foreach my $default (@{$_[0]->[_DEFAULTS]}) {
+ return 1
+ if exists($default->{$_[1]});
+ }
+
+ return;
+}
+
+sub DELETE {
+ delete $_[0]->[_DATA]->{$_[1]}
+}
+
+sub FIRSTKEY {
+ my $self = $_[0];
+ $self->[_ACTDEFAULT] = -1;
+ $self->[_SEEN] = {};
+ keys %{$self->[_DATA]};
+ my ($key,$val);
+ if (($key,$val) = each %{$self->[_DATA]}) {
+ $self->[_SEEN]->{$key}=1;
+ return wantarray ? ($key, $val) : $key;
+ } elsif (@{$self->[_DEFAULTS]}) {
+ return $self->NEXTKEY();
+ } else {
+ return;
+ }
+}
+
+sub NEXTKEY {
+ my $self = $_[0];
+ my $seen = $self->[_SEEN];
+ my $defaults = $self->[_DEFAULTS];
+ my ($key,$val);
+ if ($self->[_ACTDEFAULT] == -1) {
+ # processing the base hash
+ if (($key,$val) = each %{$self->[_DATA]}) {
+ $seen->{$key}=1;
+ return wantarray ? ($key, $val) : $key;
+ } else {
+ # base hash done
+ $self->[_ACTDEFAULT]=0;
+ if (! @$defaults) {
+ # no defaults
+ return;
+ } else {
+ # reset the first default
+ keys %{$defaults->[0]};
+ }
+ }
+ }
+ while (exists $defaults->[$self->[_ACTDEFAULT]]) {
+ while (($key,$val) = each %{$defaults->[$self->[_ACTDEFAULT]]}) {
+ return wantarray ? ($key, $val) : $key
+ unless $seen->{$key}++;
+ }
+
+ $self->[_ACTDEFAULT]++;
+ keys %{$defaults->[$self->[_ACTDEFAULT]]}
+ if exists $defaults->[$self->[_ACTDEFAULT]];
+ }
+
+ # all hashes done. Cleanup
+ undef $self->[_SEEN];
+ undef $self->[_ACTDEFAULT];
+ return;
+}
+
+
+#############################
+
+package Hash::WithDefaults::toupper;
+BEGIN {*Hash::WithDefaults::Toupper:: = \%Hash::WithDefaults::toupper::;}
+@Hash::WithDefaults::toupper::ISA = qw(Hash::WithDefaults::sensitive);
+sub _DATA () {0}
+sub _DEFAULTS () {1}
+sub _ACTDEFAULT () {2}
+sub _SEEN () {3}
+
+sub STORE {
+ $_[0]->[_DATA]->{uc $_[1]} = $_[2];
+}
+
+#############################
+
+package Hash::WithDefaults::tolower;
+BEGIN {*Hash::WithDefaults::Tolower:: = \%Hash::WithDefaults::tolower::;}
+@Hash::WithDefaults::tolower::ISA = qw(Hash::WithDefaults::sensitive);
+sub _DATA () {0}
+sub _DEFAULTS () {1}
+sub _ACTDEFAULT () {2}
+sub _SEEN () {3}
+
+sub STORE {
+ $_[0]->[_DATA]->{lc $_[1]} = $_[2];
+}
+
+1;
+
+__END__
+=head1 NAME
+
+Hash::WithDefaults
+
+ - class for hashes with key-casing requirements supporting defaults
+
+version 0.05
+
+=head1 SYNOPSIS
+
+ use Hash::WithDefaults;
+
+ %main = ( ... );
+ tie %h1, 'Hash::WithDefaults', {...};
+ tied(%h1)->AddDefault(\%main);
+ tie %h2, 'Hash::WithDefaults', [...];
+ tied(%h2)->AddDefault(\%main);
+
+ # now if you use $h1{$key}, the value is looked up first
+ # in %h1, then in %main.
+
+=head1 DESCRIPTION
+
+This module implements hashes that support "defaults". That is you may specify
+several more hashes in which the data will be looked up in case it is not found in
+the current hash.
+
+=head2 Object creation
+
+ tie %hash, 'Hash::WithDefault', [$case_option], [\%values];
+ tie %hash, 'Hash::WithDefault', [$case_option], [\@values];
+ tie %hash, 'Hash::WithDefault', [$case_option], [%values];
+
+The optional $case_option may be one of these values:
+
+ Sensitive - the hash will be case sensitive
+ Tolower - the hash will be case sensitive, all keys are made lowercase
+ Toupper - the hash will be case sensitive, all keys are made uppercase
+ Preserve - the hash will be case insensitive, the case is preserved
+ Lower - the hash will be case insensitive, all keys are made lowercase
+ Upper - the hash will be case insensitive, all keys are made uppercase
+
+If you pass a hash or array reference or an even list of keys and values to the tie() function,
+those keys and values will be COPIED to the resulting magical hash!
+
+After you tie() the hash, you use it just like any other hash.
+
+=head2 Functions
+
+=head3 AddDefault
+
+ tied(%hash)->AddDefault(\%defaults);
+
+This instructs the object to include the %defaults in the search for values.
+After this the value will be looked up first in %hash itself and then in %defaults.
+
+You may keep modifying the %defaults and your changes WILL be visible through %hash!
+
+You may add as many defaults to one Hash::WithDefaults object as you like, they will be searched
+in the order you add them.
+
+If you delete a key from the tied hash, it's only deleted from the list of specific keys, the defaults
+are never modified through the tied hash. This means that you may get a default value for a key
+after you deletethe key from the tied hash!
+
+=head3 GetDefaults
+
+ $defaults = tied(%hash)->GetDefaults();
+ push @$defaults, \%another_default;
+
+Returns a reference to the array that stores the defaults.
+You may delete or insert hash references into the array, but make sure you
+NEVER EVER insert anything else than a hash reference into the array!
+
+=head2 Config::IniHash example
+
+ use Config::IniHash;
+ $config = ReadIni $inifile, withdefaults => 1, case => 'preserve';
+
+ if (exists $config->{':default'}) {
+ my $default = $config->{':default'};
+ foreach my $section (keys %$config) {
+ next if $section =~ /^:/;
+ tied(%{$config->{$section}})->AddDefault($default)
+ }
+ }
+
+And now all normal sections will get the default values from [:default] section ;-)
+
+=head1 AUTHOR
+
+Jan Krynicky <Jenda@Krynicky.cz>
+http://Jenda.Krynicky.cz
+
+=head1 COPYRIGHT
+
+Copyright (c) 2002-2009 Jan Krynicky <Jenda@Krynicky.cz>. All rights reserved.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
@@ -0,0 +1,395 @@
+#!perl -T
+use strict;
+use Test::More tests => 1+6*26;
+use Data::Dumper;
+
+BEGIN {
+ use_ok( 'Hash::WithDefaults' );
+}
+
+diag( "Testing Hash::WithDefaults $Hash::WithDefaults::VERSION, Perl $], $^X" );
+
+{ # lower
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'lower'),
+ "Tied with case=lower"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::lower', "Tied to the right class");
+
+ $h{low} = 'value';
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ $h{Mix} = 'other';
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ $h{HI} = 'Some';
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(hi low mix);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('hi=Some', 'low=value', 'mix=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(a b)], "There are two keys");
+
+}
+
+{ # upper
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'upper'),
+ "Tied with case=upper"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::upper', "Tied to the right class");
+
+ $h{low} = 'value';
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ $h{Mix} = 'other';
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ $h{HI} = 'Some';
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI LOW MIX);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'LOW=value', 'MIX=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(A B)], "There are two keys");
+
+}
+
+{ # preserve
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'preserve'),
+ "Tied with case=preserve"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::preserve', "Tied to the right class");
+
+ $h{low} = 'value';
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ $h{Mix} = 'other';
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ $h{HI} = 'Some';
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI Mix low);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'Mix=other', 'low=value');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(B a)], "There are two keys");
+
+}
+
+
+{ # tolower
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'tolower'),
+ "Tied with case=tolower"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::tolower', "Tied to the right class");
+
+ $h{low} = 'value';
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ $h{Mix} = 'other';
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ $h{HI} = 'Some';
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, undef, '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(hi low mix);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('hi=Some', 'low=value', 'mix=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(a b)], "There are two keys");
+
+}
+
+{ # toupper
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'toupper'),
+ "Tied with case=toupper"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::toupper', "Tied to the right class");
+
+ $h{low} = 'value';
+
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ $h{Mix} = 'other';
+
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ $h{HI} = 'Some';
+
+ is( $h{hi}, undef, '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI LOW MIX);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'LOW=value', 'MIX=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{LOW};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(A B)], "There are two keys");
+
+}
+
+{ # sensitive
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'sensitive'),
+ "Tied with case=sensitive"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::sensitive', "Tied to the right class");
+
+ $h{low} = 'value';
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ $h{Mix} = 'other';
+
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ $h{HI} = 'Some';
+
+ is( $h{hi}, undef, '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI Mix low);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'Mix=other', 'low=value');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{MIX};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(B a)], "There are two keys");
+
+}
@@ -0,0 +1,1116 @@
+#!perl -T
+use strict;
+use Test::More tests => 1+6*26*3+26;
+use Data::Dumper;
+
+BEGIN {
+ use_ok( 'Hash::WithDefaults' );
+}
+
+diag( "Testing Hash::WithDefaults $Hash::WithDefaults::VERSION, Perl $], $^X" );
+
+{ # lower (ARRAYREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'lower', [low => 'value', Mix => 'other', HI => 'Some']),
+ "Tied with case=lower"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::lower', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(hi low mix);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('hi=Some', 'low=value', 'mix=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(a b)], "There are two keys");
+
+}
+
+{ # lower (HASHREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'lower', {low => 'value', Mix => 'other', HI => 'Some'}),
+ "Tied with case=lower"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::lower', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(hi low mix);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('hi=Some', 'low=value', 'mix=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(a b)], "There are two keys");
+
+}
+
+{ # lower (LIST)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'lower', low => 'value', Mix => 'other', HI => 'Some'),
+ "Tied with case=lower"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::lower', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(hi low mix);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('hi=Some', 'low=value', 'mix=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(a b)], "There are two keys");
+
+}
+
+{ # lower (LIST), direct
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults::lower', low => 'value', Mix => 'other', HI => 'Some'),
+ "Tied with case=lower"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::lower', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(hi low mix);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('hi=Some', 'low=value', 'mix=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(a b)], "There are two keys");
+
+}
+
+{ # upper (ARRAYREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'upper', [low => 'value', Mix => 'other', HI => 'Some']),
+ "Tied with case=upper"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::upper', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI LOW MIX);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'LOW=value', 'MIX=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(A B)], "There are two keys");
+
+}
+
+{ # upper (HASHREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'upper', {low => 'value', Mix => 'other', HI => 'Some'}),
+ "Tied with case=upper"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::upper', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI LOW MIX);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'LOW=value', 'MIX=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(A B)], "There are two keys");
+
+}
+
+{ # upper (LIST)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'upper', low => 'value', Mix => 'other', HI => 'Some'),
+ "Tied with case=upper"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::upper', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI LOW MIX);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'LOW=value', 'MIX=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(A B)], "There are two keys");
+
+}
+
+
+{ # preserve (ARRAYREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'preserve', [low => 'value', Mix => 'other', HI => 'Some']),
+ "Tied with case=preserve"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::preserve', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI Mix low);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'Mix=other', 'low=value');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(B a)], "There are two keys");
+
+}
+
+{ # preserve (HASHREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'preserve', {low => 'value', Mix => 'other', HI => 'Some'}),
+ "Tied with case=preserve"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::preserve', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI Mix low);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'Mix=other', 'low=value');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(B a)], "There are two keys");
+
+}
+
+{ # preserve (LIST)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'preserve', low => 'value', Mix => 'other', HI => 'Some'),
+ "Tied with case=preserve"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::preserve', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, 'value', '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, 'Some', '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI Mix low);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'Mix=other', 'low=value');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{Low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 1, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(B a)], "There are two keys");
+
+}
+
+
+{ # tolower (ARRAYREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'tolower', [low => 'value', Mix => 'other', HI => 'Some']),
+ "Tied with case=tolower"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::tolower', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, undef, '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(hi low mix);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('hi=Some', 'low=value', 'mix=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(a b)], "There are two keys");
+
+}
+
+{ # tolower (HASHREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'tolower', {low => 'value', Mix => 'other', HI => 'Some'}),
+ "Tied with case=tolower"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::tolower', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, undef, '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(hi low mix);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('hi=Some', 'low=value', 'mix=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(a b)], "There are two keys");
+
+}
+
+{ # tolower (LIST)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'tolower', low => 'value', Mix => 'other', HI => 'Some'),
+ "Tied with case=tolower"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::tolower', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ is( $h{hi}, 'Some', '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, undef, '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(hi low mix);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('hi=Some', 'low=value', 'mix=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, 'other', '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(a b)], "There are two keys");
+
+}
+
+
+{ # toupper (ARRAYREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'toupper', [low => 'value', Mix => 'other', HI => 'Some']),
+ "Tied with case=toupper"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::toupper', "Tied to the right class");
+
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, undef, '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI LOW MIX);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'LOW=value', 'MIX=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{LOW};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(A B)], "There are two keys");
+
+}
+
+{ # toupper (HASHREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'toupper', {low => 'value', Mix => 'other', HI => 'Some'}),
+ "Tied with case=toupper"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::toupper', "Tied to the right class");
+
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, undef, '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI LOW MIX);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'LOW=value', 'MIX=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{LOW};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(A B)], "There are two keys");
+
+}
+
+{ # toupper (LIST)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'toupper', low => 'value', Mix => 'other', HI => 'Some'),
+ "Tied with case=toupper"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::toupper', "Tied to the right class");
+
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, 'value', '$h{LOW}');
+
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ is( $h{hi}, undef, '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI LOW MIX);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'LOW=value', 'MIX=other');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{LOW};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, 'other', '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(A B)], "There are two keys");
+
+}
+
+
+{ # sensitive (ARRAYREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'sensitive', [low => 'value', Mix => 'other', HI => 'Some']),
+ "Tied with case=sensitive"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::sensitive', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ is( $h{hi}, undef, '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI Mix low);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'Mix=other', 'low=value');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{MIX};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(B a)], "There are two keys");
+
+}
+
+{ # sensitive (HASHREF)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'sensitive', {low => 'value', Mix => 'other', HI => 'Some'}),
+ "Tied with case=sensitive"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::sensitive', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ is( $h{hi}, undef, '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI Mix low);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'Mix=other', 'low=value');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{MIX};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(B a)], "There are two keys");
+
+}
+
+{ # sensitive (LIST)
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'sensitive', low => 'value', Mix => 'other', HI => 'Some'),
+ "Tied with case=sensitive"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::sensitive', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ is( $h{hi}, undef, '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI Mix low);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'Mix=other', 'low=value');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 3, "Number of keys");
+
+ delete $h{low};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{low}, undef, '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{MIX};
+ is( scalar( keys %h), 2, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(B a)], "There are two keys");
+
+}
@@ -0,0 +1,81 @@
+#!perl -T
+use strict;
+use Test::More tests => 1+30;
+use Data::Dumper;
+
+BEGIN {
+ use_ok( 'Hash::WithDefaults' );
+}
+
+diag( "Testing Hash::WithDefaults $Hash::WithDefaults::VERSION, Perl $], $^X" );
+
+{
+ my %h;
+ ok(
+ tie( %h, 'Hash::WithDefaults', 'sensitive', low => 'value', Mix => 'other', HI => 'Some'),
+ "Tied with case=sensitive"
+ );
+
+ my %def = (
+ low => 'masked',
+ def => 'default',
+ );
+ ok(
+ tied(%h)->AddDefault( \%def ),
+ "added some defaults"
+ );
+
+ is( ref(tied %h), 'Hash::WithDefaults::sensitive', "Tied to the right class");
+
+ is( $h{low}, 'value', '$h{low}');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, 'other', '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ is( $h{hi}, undef, '$h{hi}');
+ is( $h{Hi}, undef, '$h{Hi}');
+ is( $h{HI}, 'Some', '$h{HI}');
+
+ is( $h{def}, 'default', '$h{def}');
+ is( $h{Def}, undef, '$h{Def}');
+ is( $h{DEF}, undef, '$h{DEF}');
+
+ my @got = sort keys %h;
+ my @good = qw(HI Mix def low);
+
+ is_deeply(\@got, \@good, "List of keys");
+
+ @got = ();
+ while (my ($key, $val) = each %h) {
+ push @got, "$key=$val";
+ }
+ @got = sort @got;
+ @good = ('HI=Some', 'Mix=other', 'def=default', 'low=value');
+ is_deeply(\@got, \@good, "each() returns both keys and values");
+
+ is( scalar( keys %h), 4, "Number of keys");
+
+ delete $h{low};
+ is( scalar( keys %h), 4, "Number of keys after delete \$h{low}");
+ is( $h{low}, 'masked', '$h{low} eq "masked" after the delete');
+ is( $h{Low}, undef, '$h{Low}');
+ is( $h{LOW}, undef, '$h{LOW}');
+
+ delete $h{Mix};
+ is( scalar( keys %h), 3, "Number of keys after delete");
+ is( $h{mix}, undef, '$h{mix}');
+ is( $h{Mix}, undef, '$h{Mix}');
+ is( $h{MIX}, undef, '$h{MIX}');
+
+ %h = ();
+ is( scalar( keys %h), 0, "Number of keys after clear");
+ is_deeply( [keys %h], [], "There are no keys");
+
+ $h{a} = 1; $h{B} = 2;
+ is( scalar( keys %h), 2, "Number of keys after refil");
+ is_deeply( [sort keys %h], [qw(B a)], "There are two keys");
+
+}
@@ -0,0 +1,18 @@
+use strict;
+use warnings;
+use Test::More;
+
+# Ensure a recent version of Test::Pod::Coverage
+my $min_tpc = 1.08;
+eval "use Test::Pod::Coverage $min_tpc";
+plan skip_all => "Test::Pod::Coverage $min_tpc required for testing POD coverage"
+ if $@;
+
+# Test::Pod::Coverage doesn't require a minimum Pod::Coverage version,
+# but older versions don't recognize some common documentation styles
+my $min_pc = 0.18;
+eval "use Pod::Coverage $min_pc";
+plan skip_all => "Pod::Coverage $min_pc required for testing POD coverage"
+ if $@;
+
+all_pod_coverage_ok();
@@ -0,0 +1,12 @@
+#!perl -T
+
+use strict;
+use warnings;
+use Test::More;
+
+# Ensure a recent version of Test::Pod
+my $min_tp = 1.22;
+eval "use Test::Pod $min_tp";
+plan skip_all => "Test::Pod $min_tp required for testing POD" if $@;
+
+all_pod_files_ok();
@@ -1,17 +0,0 @@
-# Before `make install' is performed this script should be runnable with
-# `make test'. After `make install' it should work as `perl test.pl'
-
-#########################
-
-# change 'tests => 1' to 'tests => last_test_to_print';
-
-use Test;
-BEGIN { plan tests => 1 };
-use Hash::WithDefaults;
-ok(1); # If we made it this far, we're ok.
-
-#########################
-
-# Insert your test code below, the Test module is use()ed here so read
-# its man page ( perldoc Test ) for help writing this test script.
-