expected to return a blessed reference to a new scalar
(probably anonymous) that it's creating. For example:
- sub TIESCALAR {
- my $class = shift;
- my $pid = shift || $$; # 0 means me
+ sub TIESCALAR {
+ my $class = shift;
+ my $pid = shift || $$; # 0 means me
- if ($pid !~ /^\d+$/) {
- carp "Nice::Tie::Scalar got non-numeric pid $pid" if $^W;
- return undef;
- }
+ if ($pid !~ /^\d+$/) {
+ carp "Nice::Tie::Scalar got non-numeric pid $pid" if $^W;
+ return undef;
+ }
- unless (kill 0, $pid) { # EPERM or ERSCH, no doubt
- carp "Nice::Tie::Scalar got bad pid $pid: $!" if $^W;
- return undef;
- }
+ unless (kill 0, $pid) { # EPERM or ERSCH, no doubt
+ carp "Nice::Tie::Scalar got bad pid $pid: $!" if $^W;
+ return undef;
+ }
- return bless \$pid, $class;
- }
+ return bless \$pid, $class;
+ }
This tie class has chosen to return an error rather than raising an
exception if its constructor should fail. While this is how dbmopen() works,
This method will be triggered every time the tied variable is set
(assigned). Beyond its self reference, it also expects one (and only one)
-argument--the new value the user is trying to assign. Don't worry about
-returning a value from STORE -- the semantic of assignment returning the
+argument: the new value the user is trying to assign. Don't worry about
+returning a value from STORE; the semantic of assignment returning the
assigned value is implemented with FETCH.
- sub STORE {
- my $self = shift;
- confess "wrong type" unless ref $self;
- my $new_nicety = shift;
- croak "usage error" if @_;
-
- if ($new_nicety < PRIO_MIN) {
- carp sprintf
- "WARNING: priority %d less than minimum system priority %d",
- $new_nicety, PRIO_MIN if $^W;
- $new_nicety = PRIO_MIN;
- }
-
- if ($new_nicety > PRIO_MAX) {
- carp sprintf
- "WARNING: priority %d greater than maximum system priority %d",
- $new_nicety, PRIO_MAX if $^W;
- $new_nicety = PRIO_MAX;
- }
-
- unless (defined setpriority(PRIO_PROCESS, $$self, $new_nicety)) {
- confess "setpriority failed: $!";
- }
- }
+ sub STORE {
+ my $self = shift;
+ confess "wrong type" unless ref $self;
+ my $new_nicety = shift;
+ croak "usage error" if @_;
+
+ if ($new_nicety < PRIO_MIN) {
+ carp sprintf
+ "WARNING: priority %d less than minimum system priority %d",
+ $new_nicety, PRIO_MIN if $^W;
+ $new_nicety = PRIO_MIN;
+ }
+
+ if ($new_nicety > PRIO_MAX) {
+ carp sprintf
+ "WARNING: priority %d greater than maximum system priority %d",
+ $new_nicety, PRIO_MAX if $^W;
+ $new_nicety = PRIO_MAX;
+ }
+
+ unless (defined setpriority(PRIO_PROCESS,
+ $$self,
+ $new_nicety))
+ {
+ confess "setpriority failed: $!";
+ }
+ }
=item UNTIE this
X<UNTIE>
This method will be triggered when the C<untie> occurs. This can be useful
if the class needs to know when no further calls will be made. (Except DESTROY
-of course.) See L<The C<untie> Gotcha> below for more details.
+of course.) See L</The C<untie> Gotcha> below for more details.
=item DESTROY this
X<DESTROY>
X<array, tying>
A class implementing a tied ordinary array should define the following
-methods: TIEARRAY, FETCH, STORE, FETCHSIZE, STORESIZE and perhaps UNTIE and/or DESTROY.
+methods: TIEARRAY, FETCH, STORE, FETCHSIZE, STORESIZE, CLEAR
+and perhaps UNTIE and/or DESTROY.
FETCHSIZE and STORESIZE are used to provide C<$#array> and
equivalent C<scalar(@array)> access.
In our example, C<undef> is really C<$self-E<gt>{ELEMSIZE}> number of
spaces so we have a little more work to do here:
- sub STORE {
- my $self = shift;
- my( $index, $value ) = @_;
- if ( length $value > $self->{ELEMSIZE} ) {
- croak "length of $value is greater than $self->{ELEMSIZE}";
- }
- # fill in the blanks
- $self->EXTEND( $index ) if $index > $self->FETCHSIZE();
- # right justify to keep element size for smaller elements
- $self->{ARRAY}->[$index] = sprintf "%$self->{ELEMSIZE}s", $value;
- }
+ sub STORE {
+ my $self = shift;
+ my( $index, $value ) = @_;
+ if ( length $value > $self->{ELEMSIZE} ) {
+ croak "length of $value is greater than $self->{ELEMSIZE}";
+ }
+ # fill in the blanks
+ $self->EXTEND( $index ) if $index > $self->FETCHSIZE();
+ # right justify to keep element size for smaller elements
+ $self->{ARRAY}->[$index] = sprintf "%$self->{ELEMSIZE}s", $value;
+ }
Negative indexes are treated the same as with FETCH.
In our example, we will determine that if an element consists of
C<$self-E<gt>{ELEMSIZE}> spaces only, it does not exist:
- sub EXISTS {
- my $self = shift;
- my $index = shift;
- return 0 if ! defined $self->{ARRAY}->[$index] ||
- $self->{ARRAY}->[$index] eq ' ' x $self->{ELEMSIZE};
- return 1;
- }
+ sub EXISTS {
+ my $self = shift;
+ my $index = shift;
+ return 0 if ! defined $self->{ARRAY}->[$index] ||
+ $self->{ARRAY}->[$index] eq ' ' x $self->{ELEMSIZE};
+ return 1;
+ }
=item DELETE this, key
X<DELETE>
=item UNTIE this
X<UNTIE>
-Will be called when C<untie> happens. (See L<The C<untie> Gotcha> below.)
+Will be called when C<untie> happens. (See L</The C<untie> Gotcha> below.)
=item DESTROY this
X<DESTROY>
CLEAR empties the hash by deleting all the key and value pairs. FIRSTKEY
and NEXTKEY implement the keys() and each() functions to iterate over all
the keys. SCALAR is triggered when the tied hash is evaluated in scalar
-context. UNTIE is called when C<untie> happens, and DESTROY is called when
-the tied variable is garbage collected.
+context, and in 5.28 onwards, by C<keys> in boolean context. UNTIE is
+called when C<untie> happens, and DESTROY is called when the tied variable
+is garbage collected.
If this seems like a lot, then feel free to inherit from merely the
standard Tie::StdHash module for most of your methods, redefining only the
croak "@{[&whowasi]}: $file not clobberable"
unless $self->{CLOBBER};
- open(F, "> $file") || croak "can't open $file: $!";
- print F $value;
- close(F);
+ open(my $f, '>', $file) || croak "can't open $file: $!";
+ print $f $value;
+ close($f);
}
If they wanted to clobber something, they might say:
typically by using the delete() function. Again, we'll
be careful to check whether they really want to clobber files.
- sub DELETE {
- carp &whowasi if $DEBUG;
+ sub DELETE {
+ carp &whowasi if $DEBUG;
- my $self = shift;
- my $dot = shift;
- my $file = $self->{HOME} . "/.$dot";
- croak "@{[&whowasi]}: won't remove file $file"
- unless $self->{CLOBBER};
- delete $self->{LIST}->{$dot};
- my $success = unlink($file);
- carp "@{[&whowasi]}: can't unlink $file: $!" unless $success;
- $success;
- }
+ my $self = shift;
+ my $dot = shift;
+ my $file = $self->{HOME} . "/.$dot";
+ croak "@{[&whowasi]}: won't remove file $file"
+ unless $self->{CLOBBER};
+ delete $self->{LIST}->{$dot};
+ my $success = unlink($file);
+ carp "@{[&whowasi]}: can't unlink $file: $!" unless $success;
+ $success;
+ }
The value returned by DELETE becomes the return value of the call
to delete(). If you want to emulate the normal behavior of delete(),
dangerous thing that they'll have to set CLOBBER to something higher than
1 to make it happen.
- sub CLEAR {
- carp &whowasi if $DEBUG;
- my $self = shift;
- croak "@{[&whowasi]}: won't remove all dot files for $self->{USER}"
- unless $self->{CLOBBER} > 1;
- my $dot;
- foreach $dot ( keys %{$self->{LIST}}) {
- $self->DELETE($dot);
- }
- }
+ sub CLEAR {
+ carp &whowasi if $DEBUG;
+ my $self = shift;
+ croak "@{[&whowasi]}: won't remove all dot files for $self->{USER}"
+ unless $self->{CLOBBER} > 1;
+ my $dot;
+ foreach $dot ( keys %{$self->{LIST}}) {
+ $self->DELETE($dot);
+ }
+ }
=item EXISTS this, key
X<EXISTS>
X<FIRSTKEY>
This method will be triggered when the user is going
-to iterate through the hash, such as via a keys() or each()
-call.
+to iterate through the hash, such as via a keys(), values(), or each() call.
sub FIRSTKEY {
carp &whowasi if $DEBUG;
my $self = shift;
- my $a = keys %{$self->{LIST}}; # reset each() iterator
+ my $a = keys %{$self->{LIST}}; # reset each() iterator
each %{$self->{LIST}}
}
+FIRSTKEY is always called in scalar context and it should just
+return the first key. values(), and each() in list context,
+will call FETCH for the returned keys.
+
=item NEXTKEY this, lastkey
X<NEXTKEY>
-This method gets triggered during a keys() or each() iteration. It has a
+This method gets triggered during a keys(), values(), or each() iteration. It has a
second argument which is the last key that had been accessed. This is
-useful if you're carrying about ordering or calling the iterator from more
+useful if you're caring about ordering or calling the iterator from more
than one sequence, or not really storing things in a hash anywhere.
+NEXTKEY is always called in scalar context and it should just
+return the next key. values(), and each() in list context,
+will call FETCH for the returned keys.
+
For our example, we're using a real hash so we'll do just the simple
thing, but we'll have to go through the LIST field indirectly.
=item SCALAR this
X<SCALAR>
-This is called when the hash is evaluated in scalar context. In order
-to mimic the behaviour of untied hashes, this method should return a
-false value when the tied hash is considered empty. If this method does
+This is called when the hash is evaluated in scalar context, and in 5.28
+onwards, by C<keys> in boolean context. In order to mimic the behaviour of
+untied hashes, this method must return a value which when used as boolean,
+indicates whether the tied hash is considered empty. If this method does
not exist, perl will make some educated guesses and return true when
the hash is inside an iteration. If this isn't the case, FIRSTKEY is
called, and the result will be a false value if FIRSTKEY returns the empty
return scalar %{ $self->{LIST} }
}
+NOTE: In perl 5.25 the behavior of scalar %hash on an untied hash changed
+to return the count of keys. Prior to this it returned a string containing
+information about the bucket setup of the hash. See
+L<Hash::Util/bucket_ratio> for a backwards compatibility path.
+
=item UNTIE this
X<UNTIE>
-This is called when C<untie> occurs. See L<The C<untie> Gotcha> below.
+This is called when C<untie> occurs. See L</The C<untie> Gotcha> below.
=item DESTROY this
X<DESTROY>
program, where output to STDOUT and STDERR may have to be redirected
in some special way. See nvi and the Apache module for examples.
+When tying a handle, the first argument to C<tie> should begin with an
+asterisk. So, if you are tying STDOUT, use C<*STDOUT>. If you have
+assigned it to a scalar variable, say C<$handle>, use C<*$handle>.
+C<tie $handle> ties the scalar variable C<$handle>, not the handle inside
+it.
+
In our example we're going to create a shouting handle.
package Shout;
This method will be called when the handle is written to via the
C<syswrite> function.
- sub WRITE {
- $r = shift;
- my($buf,$len,$offset) = @_;
- print "WRITE called, \$buf=$buf, \$len=$len, \$offset=$offset";
- }
+ sub WRITE {
+ $r = shift;
+ my($buf,$len,$offset) = @_;
+ print "WRITE called, \$buf=$buf, \$len=$len, \$offset=$offset";
+ }
=item PRINT this, LIST
X<PRINT>
This method will be triggered every time the tied handle is printed to
-with the C<print()> function.
-Beyond its self reference it also expects the list that was passed to
-the print function.
+with the C<print()> or C<say()> functions. Beyond its self reference
+it also expects the list that was passed to the print function.
- sub PRINT { $r = shift; $$r++; print join($,,map(uc($_),@_)),$\ }
+ sub PRINT { $r = shift; $$r++; print join($,,map(uc($_),@_)),$\ }
+
+C<say()> acts just like C<print()> except $\ will be localized to C<\n> so
+you need do nothing special to handle C<say()> in C<PRINT()>.
=item PRINTF this, LIST
X<PRINTF>
This method will be called when the handle is read from via the C<read>
or C<sysread> functions.
- sub READ {
- my $self = shift;
- my $bufref = \$_[0];
- my(undef,$len,$offset) = @_;
- print "READ called, \$buf=$bufref, \$len=$len, \$offset=$offset";
- # add to $$bufref, set $len to number of characters read
- $len;
- }
+ sub READ {
+ my $self = shift;
+ my $bufref = \$_[0];
+ my(undef,$len,$offset) = @_;
+ print "READ called, \$buf=$bufref, \$len=$len, \$offset=$offset";
+ # add to $$bufref, set $len to number of characters read
+ $len;
+ }
=item READLINE this
X<READLINE>
-This method will be called when the handle is read from via <HANDLE>.
-The method should return undef when there is no more data.
-
- sub READLINE { $r = shift; "READLINE called $$r times\n"; }
+This method is called when the handle is read via C<E<lt>HANDLEE<gt>>
+or C<readline HANDLE>.
+
+As per L<C<readline>|perlfunc/readline>, in scalar context it should return
+the next line, or C<undef> for no more data. In list context it should
+return all remaining lines, or an empty list for no more data. The strings
+returned should include the input record separator C<$/> (see L<perlvar>),
+unless it is C<undef> (which means "slurp" mode).
+
+ sub READLINE {
+ my $r = shift;
+ if (wantarray) {
+ return ("all remaining\n",
+ "lines up\n",
+ "to eof\n");
+ } else {
+ return "READLINE called " . ++$$r . " times\n";
+ }
+ }
=item GETC this
X<GETC>
sub GETC { print "Don't GETC, Get Perl"; return "a"; }
+=item EOF this
+X<EOF>
+
+This method will be called when the C<eof> function is called.
+
+Starting with Perl 5.12, an additional integer parameter will be passed. It
+will be zero if C<eof> is called without parameter; C<1> if C<eof> is given
+a filehandle as a parameter, e.g. C<eof(FH)>; and C<2> in the very special
+case that the tied filehandle is C<ARGV> and C<eof> is called with an empty
+parameter list, e.g. C<eof()>.
+
+ sub EOF { not length $stringbuf }
+
=item CLOSE this
X<CLOSE>
As with the other types of ties, this method will be called when C<untie> happens.
It may be appropriate to "auto CLOSE" when this occurs. See
-L<The C<untie> Gotcha> below.
+L</The C<untie> Gotcha> below.
=item DESTROY this
X<DESTROY>
X<UNTIE>
You can define for all tie types an UNTIE method that will be called
-at untie(). See L<The C<untie> Gotcha> below.
+at untie(). See L</The C<untie> Gotcha> below.
=head2 The C<untie> Gotcha
X<untie>
sub TIESCALAR {
my $class = shift;
my $filename = shift;
- my $handle = new IO::File "> $filename"
+ my $handle = IO::File->new( "> $filename" )
or die "Cannot open $filename: $!\n";
print $handle "The Start\n";
So far so good. Those of you who have been paying attention will have
spotted that the tied object hasn't been used so far. So lets add an
extra method to the Remember class to allow comments to be included in
-the file -- say, something like this:
+the file; say, something like this:
sub comment {
my $self = shift;
warning if appropriate. e.g. to replicate the no UNTIE case this method can
be used:
- sub UNTIE
- {
- my ($obj,$count) = @_;
- carp "untie attempted while $count inner references still exist" if $count;
- }
+ sub UNTIE
+ {
+ my ($obj,$count) = @_;
+ carp "untie attempted while $count inner references still exist"
+ if $count;
+ }
=head1 SEE ALSO
=head1 BUGS
-The bucket usage information provided by C<scalar(%hash)> is not
+The normal return provided by C<scalar(%hash)> is not
available. What this means is that using %tied_hash in boolean
context doesn't work right (currently this always tests false,
regardless of whether the hash is empty or hash elements).
+[ This paragraph needs review in light of changes in 5.25 ]
Localizing tied arrays or hashes does not work. After exiting the
scope the arrays or the hashes are not restored.
You cannot easily tie a multilevel data structure (such as a hash of
hashes) to a dbm file. The first problem is that all but GDBM and
Berkeley DB have size limitations, but beyond that, you also have problems
-with how references are to be represented on disk. One experimental
+with how references are to be represented on disk. One
module that does attempt to address this need is DBM::Deep. Check your
nearest CPAN site as described in L<perlmodlib> for source code. Note
that despite its name, DBM::Deep does not use dbm. Another earlier attempt