package Tie::Plural::Scalar; use 5.006; use strict; use warnings; use Carp; our $VERSION = '0.01'; # Preloaded methods go here. sub TIESCALAR { my $class = shift; my $obj = {}; for (qw/varref singular plural zero/){ $obj->{$_} = shift; } ${$obj->{varref}} = 0 unless defined ${$obj->{varref}}; bless $obj, $class; $obj->_set_defaults(); $obj; } sub FETCH { my $obj = shift; ${$obj->{varref}} = 0 unless defined ${$obj->{varref}}; if (${$obj->{varref}} == 0){ $obj->{zero}; } elsif (${$obj->{varref}} == 1){ $obj->{singular}; } else { $obj->{plural}; } } sub STORE { my $obj = shift; my $newval = shift; if (ref $newval eq 'ARRAY'){ #new value is an array of values for (qw/singular plural zero/){ $obj->{$_} = shift @$newval; } } elsif (!ref $newval) { #user only passed the singular $obj->{singular} = $newval; undef $obj->{$_} for qw/plural zero/; } else { croak "Unknown new value type for $obj->{singular}"; } $obj->_set_defaults(); } #Private utility subroutines sub _set_defaults { my $obj = shift; $obj->{plural} = $obj->{singular} . 's' unless defined $obj->{plural}; $obj->{zero} = $obj->{plural} unless defined $obj->{zero}; } 1; __END__ =head1 NAME Tie::Plural::Scalar - Perl extension for auto-creating Plural vs Singular values based on another 'count' variable. =head1 SYNOPSIS use Tie::Plural::Scalar; my $count; tie my $thing, Tie::Plural::Scalar, \$count, $single_value; tie my $thing, Tie::Plural::Scalar, \$count, $single_value, $plural_value; tie my $thing, Tie::Plural::Scalar, \$count, $single_value, $plural_value, $zero_value; $count = 2; print "I have $count $thing\n"; #prints $thing's plural value =head1 VERSION This document describes version 0.01 of Tie::Plural::Scalar =head1 DESCRIPTION This module enables you to associate a variable with both the singular and plural form of the desired string. The variable will also be associated with a separate "counting" variable. The tied variable will return its singular or plural version based on the current value of the counting variable whenever it is read. This is useful for those times when you want to print out status messages with some semblance of gramattical correctness, without resorting to the ugly "Copied 1 file(s)". =head2 USAGE my $count; tie my $thing, Tie::Plural::Scalar, \$count, $singular, $plural, $zero; If $zero is omitted from the constructor call, the zero value will be the same as $plural. If $plural is also omitted, both the zero value and the plural value will be defined as C<$singular . 's'> After the above constructor, whenever $thing is read, $count will be polled. If $count is 1, $singular is returned. If $count is greater than 1, $plural is returned. If $count is zero, $zero is returned. To change the "thing" after the variable has been tied, you can assign a new array reference to it. This array reference should contain the new singular, plural, and zero values. (Again, singular is required, zero defaults to plural, and plural defaults to singular followed by 's'). If you wish to accept the defaults for both zero and plural, you can simply assign the tied variable to the new singular value, without using an array reference. It is not currently possible to change which counter variable a tied variable polls when read. (without untying and retying, of course) =head2 EXAMPLES tie my $file, 'Tie::Plural::Scalar', \my $num_files, 'file'; opendir my $dh, '.' or die "Serious Dainbramage: $!"; while ($_ = readdir $dh){ $num_files++ if -f and /\.p[lm]$/; } print "We found $num_files Perl $file"; #Depending on how many .pl and .pm files found, will print one of: # We found 0 Perl files # We found 1 Perl file # We found 2 Perl files # We found 3 Perl files # Note that if the counter variable is still undefined when the tied variable is read, the counter variable will be set to the value C<0>. tie my $animal, 'Tie::Plural::Scalar, \my $critters, 'ox', 'oxen'; for my $zoo ('Catskills', 'San Diego', 'Bronx'){ $critters = how_many_oxen($zoo); print "The $zoo zoo has $critters $animal\n"; } #change which animal we want to talk about $animal = [qw/mouse mice/]; for my $zoo ('Catskills', 'San Diego', 'Los Angeles') { $critters = how_many_mice($zoo); print "The $zoo zoo has $critters $animal\n"; } =head2 EXPORT None by default. =head2 TRAPS Be very weary of Perl creating a new variable without your knowledge. Remember that the loop variable in a foreach-loop is implicitly C'ed. This will B do what you want: tie my $object, 'Tie::Plural::Scalar', \my $count, 'desk'; for $count (0..2) { #this $count is NOT the $count that $object looks at! print "I have $count $object.\n"; } This prints: I have 0 desks. I have 1 desks. I have 2 desks. The problem is that the C<$count> from the constructor is masked by the loop control variable C<$count>, and is therefore never changed, retaining its original undefined value (which was coerced into C<0> the first time $object was read). =head1 AUTHOR Paul D. Lalli < lallip AT cs DOT rpi DOT edu > =head1 SEE ALSO L - an alternative implementation that uses tied hashes, L - A module to automatically create Plurals based on the Oxford English Dictionary L - for information on tieing variables. =cut