📄 perltie.pod
字号:
sub DELETE { my $self = shift; my $index = shift; return $self->STORE( $index, '' ); }=item CLEAR thisClear (remove, delete, ...) all values from the tied array associated withobject I<this>. For example: sub CLEAR { my $self = shift; return $self->{ARRAY} = []; }=item PUSH this, LIST Append elements of I<LIST> to the array. For example: sub PUSH { my $self = shift; my @list = @_; my $last = $self->FETCHSIZE(); $self->STORE( $last + $_, $list[$_] ) foreach 0 .. $#list; return $self->FETCHSIZE(); } =item POP thisRemove last element of the array and return it. For example: sub POP { my $self = shift; return pop @{$self->{ARRAY}}; }=item SHIFT thisRemove the first element of the array (shifting other elements down)and return it. For example: sub SHIFT { my $self = shift; return shift @{$self->{ARRAY}}; }=item UNSHIFT this, LIST Insert LIST elements at the beginning of the array, moving existing elementsup to make room. For example: sub UNSHIFT { my $self = shift; my @list = @_; my $size = scalar( @list ); # make room for our list @{$self->{ARRAY}}[ $size .. $#{$self->{ARRAY}} + $size ] = @{$self->{ARRAY}}; $self->STORE( $_, $list[$_] ) foreach 0 .. $#list; }=item SPLICE this, offset, length, LISTPerform the equivalent of C<splice> on the array. I<offset> is optional and defaults to zero, negative values count back from the end of the array. I<length> is optional and defaults to rest of the array.I<LIST> may be empty.Returns a list of the original I<length> elements at I<offset>.In our example, we'll use a little shortcut if there is a I<LIST>: sub SPLICE { my $self = shift; my $offset = shift || 0; my $length = shift || $self->FETCHSIZE() - $offset; my @list = (); if ( @_ ) { tie @list, __PACKAGE__, $self->{ELEMSIZE}; @list = @_; } return splice @{$self->{ARRAY}}, $offset, $length, @list; }=item UNTIE thisWill be called when C<untie> happens. (See below.)=item DESTROY thisThis method will be triggered when the tied variable needs to be destructed.As with the scalar tie class, this is almost never needed in alanguage that does its own garbage collection, so this time we'lljust leave it out.=back=head2 Tying HashesHashes were the first Perl data type to be tied (see dbmopen()). A classimplementing a tied hash should define the following methods: TIEHASH isthe constructor. FETCH and STORE access the key and value pairs. EXISTSreports whether a key is present in the hash, and DELETE deletes one.CLEAR empties the hash by deleting all the key and value pairs. FIRSTKEYand NEXTKEY implement the keys() and each() functions to iterate over allthe keys. UNTIE is called when C<untie> happens, and DESTROY is called whenthe tied variable is garbage collected.If this seems like a lot, then feel free to inherit from merely thestandard Tie::Hash module for most of your methods, redefining only theinteresting ones. See L<Tie::Hash> for details.Remember that Perl distinguishes between a key not existing in the hash,and the key existing in the hash but having a corresponding value ofC<undef>. The two possibilities can be tested with the C<exists()> andC<defined()> functions.Here's an example of a somewhat interesting tied hash class: it gives youa hash representing a particular user's dot files. You index into the hashwith the name of the file (minus the dot) and you get back that dot file'scontents. For example: use DotFiles; tie %dot, 'DotFiles'; if ( $dot{profile} =~ /MANPATH/ || $dot{login} =~ /MANPATH/ || $dot{cshrc} =~ /MANPATH/ ) { print "you seem to set your MANPATH\n"; }Or here's another sample of using our tied class: tie %him, 'DotFiles', 'daemon'; foreach $f ( keys %him ) { printf "daemon dot file %s is size %d\n", $f, length $him{$f}; }In our tied hash DotFiles example, we use a regularhash for the object containing several importantfields, of which only the C<{LIST}> field will be what theuser thinks of as the real hash.=over 5=item USERwhose dot files this object represents=item HOMEwhere those dot files live=item CLOBBERwhether we should try to change or remove those dot files=item LISTthe hash of dot file names and content mappings=backHere's the start of F<Dotfiles.pm>: package DotFiles; use Carp; sub whowasi { (caller(1))[3] . '()' } my $DEBUG = 0; sub debug { $DEBUG = @_ ? shift : 1 }For our example, we want to be able to emit debugging info to help in tracingduring development. We keep also one convenience function aroundinternally to help print out warnings; whowasi() returns the function namethat calls it.Here are the methods for the DotFiles tied hash.=over 4=item TIEHASH classname, LISTThis is the constructor for the class. That means it is expected toreturn a blessed reference through which the new object (probably but notnecessarily an anonymous hash) will be accessed.Here's the constructor: sub TIEHASH { my $self = shift; my $user = shift || $>; my $dotdir = shift || ''; croak "usage: @{[&whowasi]} [USER [DOTDIR]]" if @_; $user = getpwuid($user) if $user =~ /^\d+$/; my $dir = (getpwnam($user))[7] || croak "@{[&whowasi]}: no user $user"; $dir .= "/$dotdir" if $dotdir; my $node = { USER => $user, HOME => $dir, LIST => {}, CLOBBER => 0, }; opendir(DIR, $dir) || croak "@{[&whowasi]}: can't opendir $dir: $!"; foreach $dot ( grep /^\./ && -f "$dir/$_", readdir(DIR)) { $dot =~ s/^\.//; $node->{LIST}{$dot} = undef; } closedir DIR; return bless $node, $self; }It's probably worth mentioning that if you're going to filetest thereturn values out of a readdir, you'd better prepend the directoryin question. Otherwise, because we didn't chdir() there, it wouldhave been testing the wrong file.=item FETCH this, keyThis method will be triggered every time an element in the tied hash isaccessed (read). It takes one argument beyond its self reference: the keywhose value we're trying to fetch.Here's the fetch for our DotFiles example. sub FETCH { carp &whowasi if $DEBUG; my $self = shift; my $dot = shift; my $dir = $self->{HOME}; my $file = "$dir/.$dot"; unless (exists $self->{LIST}->{$dot} || -f $file) { carp "@{[&whowasi]}: no $dot file" if $DEBUG; return undef; } if (defined $self->{LIST}->{$dot}) { return $self->{LIST}->{$dot}; } else { return $self->{LIST}->{$dot} = `cat $dir/.$dot`; } }It was easy to write by having it call the Unix cat(1) command, but itwould probably be more portable to open the file manually (and somewhatmore efficient). Of course, because dot files are a Unixy concept, we'renot that concerned.=item STORE this, key, valueThis method will be triggered every time an element in the tied hash is set(written). It takes two arguments beyond its self reference: the index atwhich we're trying to store something, and the value we're trying to putthere.Here in our DotFiles example, we'll be careful not to letthem try to overwrite the file unless they've called the clobber()method on the original object reference returned by tie(). sub STORE { carp &whowasi if $DEBUG; my $self = shift; my $dot = shift; my $value = shift; my $file = $self->{HOME} . "/.$dot"; my $user = $self->{USER}; croak "@{[&whowasi]}: $file not clobberable" unless $self->{CLOBBER}; open(F, "> $file") || croak "can't open $file: $!"; print F $value; close(F); }If they wanted to clobber something, they might say: $ob = tie %daemon_dots, 'daemon'; $ob->clobber(1); $daemon_dots{signature} = "A true daemon\n";Another way to lay hands on a reference to the underlying object is touse the tied() function, so they might alternately have set clobberusing: tie %daemon_dots, 'daemon'; tied(%daemon_dots)->clobber(1);The clobber method is simply: sub clobber { my $self = shift; $self->{CLOBBER} = @_ ? shift : 1; }=item DELETE this, keyThis method is triggered when we remove an element from the hash,typically by using the delete() function. Again, we'llbe careful to check whether they really want to clobber files. 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; }The value returned by DELETE becomes the return value of the callto delete(). If you want to emulate the normal behavior of delete(),you should return whatever FETCH would have returned for this key.In this example, we have chosen instead to return a value which tellsthe caller whether the file was successfully deleted.=item CLEAR thisThis method is triggered when the whole hash is to be cleared, usually byassigning the empty list to it.In our example, that would remove all the user's dot files! It's such adangerous thing that they'll have to set CLOBBER to something higher than1 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); } }=item EXISTS this, keyThis method is triggered when the user uses the exists() functionon a particular hash. In our example, we'll look at the C<{LIST}>hash element for this: sub EXISTS { carp &whowasi if $DEBUG; my $self = shift; my $dot = shift;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -