[21798] in Perl-Users-Digest
Perl-Users Digest, Issue: 4002 Volume: 10
daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Sun Oct 20 14:10:30 2002
Date: Sun, 20 Oct 2002 11:10:09 -0700 (PDT)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)
Perl-Users Digest Sun, 20 Oct 2002 Volume: 10 Number: 4002
Today's topics:
RFC:MLDBM_Handler.pm - Long <d.adamkiewicz@i7.com.pl>
Digest Administrivia (Last modified: 6 Apr 01) (Perl-Users-Digest Admin)
----------------------------------------------------------------------
Date: Sun, 20 Oct 2002 18:03:18 +0200
From: Darek Adamkiewicz <d.adamkiewicz@i7.com.pl>
Subject: RFC:MLDBM_Handler.pm - Long
Message-Id: <aoujh4$g2f$1@news.tpi.pl>
Hello folks
<I appologize for poor English>
I wrote module. This is MLDBM based module which allow
to define/store/manipulate related tables' records.
It requires Storable, MLDBM, SDBM_File, Tie::IxHash.
Belows are two examples from POD - they show how it works,
the second uses Data::Dumper.
Any comments welcome.
Regards
Darek
=============
EXAMPLE1
=============
## DEFINE
perl -e"use MLDBM_Handler;$tree=[qw/f a
b/];$it=MLDBM_Handler->init(q/f/,$tree);"
## ADD
perl -e"use
MLDBM_Handler;$it=MLDBM_Handler->init(q/f/);$it->set_rows([{a=>11,b=>12},{a=>12,b=>13}]);"
## GET
perl -e"use
MLDBM_Handler;$it=MLDBM_Handler->init(q/f/);$g=$it->get_rows;for(@$g){print
qq/@{[%$_]}\n/}"
===============
EXAMPLE2
===============
use MLDBM_Handler;
@common = qw/created updated/; ## option
$tree = [qw/filename1 field1/,
[qw/filename2 field2/,[qw/filename3 field3/]]
];
MLDBM_Handler::add_common($tree,\@common); ## option
%obj = ();
$obj{filename1} = MLDBM_Handler->init("filename1", $tree);
$obj{filename2} = MLDBM_Handler::db("filename2");
$obj{filename3} = MLDBM_Handler::db("filename3");
foreach (qw/33331 33332 33333/) {
my $href;
$href->{field3} = $_;
push(@$aref, $href);
}
## NOTE: order of following statements is crucial to set all information
## needed about relations between those rows
@set = $obj{filename3}->set_rows($aref); ## append three rows
print "@set\n";
$href->{filename3} = [@set]; ## store indices of those rows
$href->{field2} = "22222";
@set = $obj{filename2}->set_rows([$href]);
$href->{filename2} = [@set];
$href->{field1} = "11111";
$obj{filename1}->set_rows([$href]);
$aref1 = $obj{filename1}->get_ext_rows; ## get everything
use Data::Dumper;
print Dumper($aref1);
$obj{filename3}->delete(0, -1); ## first and last row
$aref2 = $obj{filename2}->get_ext_rows; ##
print Dumper($aref2);
@flds = $obj{filename3}->flds;
print "@flds\n";
__END__
===============================================
package MLDBM_Handler;
use vars qw/$VERSION/;
$VERSION = '0.13';#
use strict;
use MLDBM qw/SDBM_File Storable/;
use MLDBM::Serializer::Storable; ##
use Storable qw/dclone/;
use SDBM_File; ##
use Fcntl;
use Carp::Heavy; ##
use Tie::IxHash;
our %db;
sub db {
my $file = shift;
if (ref($db{$file}) =~ /MLDBM_Handler/) {
return $db{$file};
} elsif (ref($db{$file}) =~ /ARRAY/) {
return init(__PACKAGE__,$file, @{ $db{$file} });
} else {
return undef;#Carp?
}
}
sub init {
my $this = shift;
my $class = ref($this)||$this;
my ($file, $tree, $branch, $mode, $perms) = @_;
my $self = {};
$self->{FILE} = $file;
$mode ||= (O_CREAT|O_RDWR);
$perms ||= 0666;
tie %{$self->{TIEHASH}}, 'MLDBM', $file, $mode, $perms or die $!;
my $proc;## to be processed unless $branch
unless ($proc = ${$self->{TIEHASH}}{tree}) {
## save
${$self->{TIEHASH}}{tree} = $tree;
$proc = $tree;
}
return $proc if !defined($proc);
my %tables;
unless ($branch) {
my $clone = dclone($proc);
set_tables_data(\%tables, $proc);
my @extfiles = grep !/^$file$/, keys %tables;
if ( @extfiles>0 ) {
## so there is at least one file connected
foreach (@extfiles) {
$db{$_} = [$clone, $tables{$_} ];
}
}
@{$self->{FLDS}} = @{ $tables{$file}{FLDS} };
@{$self->{DOWN}} = @{ $tables{$file}{DOWN} };
$self->{UP} = $tables{$file}{UP};
} else {
@{$self->{FLDS}} = @{ $branch->{FLDS} };
@{$self->{DOWN}} = @{ $branch->{DOWN} };
$self->{UP} = $branch->{UP};
}
## IMPLICITLY ADD FIELD IF EXISTS SUPERIOR FILE - FIELD IS NOT CONTAINED
IN $tree!!!
## IT'S FOR delete
unshift(@{$self->{FLDS}}, "nodes")
if defined $self->{UP};
my @numkeys = map {$_, undef} sort {$a<=>$b} grep /^\d+$/ && $_, keys
%{$self->{TIEHASH}};
$self->{NUMKEYS} = Tie::IxHash->new( @numkeys );
bless $self, $class;
$db{$file} = $self;
return $self;
}
sub set_tables_data {
my ($tables, $reft, $up) = @_;
my $first = shift @$reft;
$tables->{$first}{UP} = $up;
@{$tables->{$first}{DOWN}} = ();
foreach (@$reft) {
if (ref($_) =~ /ARRAY/) {
push(@{$tables->{$first}{FLDS}}, $_->[0]);
## array of ref
push(@{$tables->{$first}{DOWN}}, $tables->{$first}{FLDS}[-1]);
set_tables_data($tables, $_, $first);
} else {
push(@{$tables->{$first}{FLDS}}, $_);
}
}
}
## ultility
sub add_common {
my ($reft, $common) = @_;
my $first = shift @$reft;
unshift(@$reft, $first, @$common);
foreach (@$reft) {
if (ref($_) =~ /ARRAY/) {
add_common($_, $common);
}
}
}
sub _get_rows {
## ext:true - get external values, false - don't
my ($self, $ext, @list) = @_;
my @indices = ();
my $ret = [];
@list = grep /^\-?\d+$/, @list;
@list = $self->{NUMKEYS}->Indices($self->{NUMKEYS}->Keys) if @list == 0;
my @spec = $self->{NUMKEYS}->Keys( @list );
if ( defined($self->{UP}) ) {
if (ref($db{$self->{UP}}) =~ /ARRAY/) {
init(__PACKAGE__, $self->{UP}, @{ $db{$self->{UP}} });
}
die "hash element \"$self->{UP}\" exists while superior file object
doesn't"
unless defined $db{$self->{UP}};
}
for(my $i=0; $i<=$#spec; $i++) {
if (defined $spec[$i]) {
my $href = {}; ##-
@{$href}{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };
##+ 0.09
if ( exists($href->{nodes}) ) {## && defined($href->{nodes})
if (defined $db{$self->{UP}}) {
my @temp = unpack "n*", $href->{nodes};
shift @temp;
$href->{nodes} = [@temp];
@{$href->{nodes}} = grep defined($_),
$db{$self->{UP}}->{NUMKEYS}->Indices( @{$href->{nodes}} )
if @temp>0;
} else {
die "hash element \"nodes\" exists and isn't empty while superior
file object doesn't exist";
}
} ##+ 0.09
foreach my $e (@{$self->{DOWN}}) {
my @temp = unpack "n*", $href->{$e};
shift @temp;
$href->{$e} = [@temp];
if (@temp) {
if (ref($db{$e}) =~ /ARRAY/) {
init(__PACKAGE__, $e, @{ $db{$e} });
}
@{$href->{$e}} = grep defined($_), $db{$e}->{NUMKEYS}->Indices(
@{$href->{$e}} );
if ($ext && @{$href->{$e}}>0) {
@{$href->{$e}} = _get_rows($db{$e}, $ext, @{$href->{$e}});
}
}
}
push(@$ret, $href);
push(@indices, $list[$i]);
}
}
return wantarray?($ret, @indices):$ret;
}
## obj->get_rows(-1); obj->get_rows; obj->get_rows(0,3,5);
## get whole rows data
sub get_ext_rows {
my ($self, @list) = @_;
return _get_rows($self,1,@list);
}
## obj->get_rows(-1); obj->get_rows; obj->get_rows(0,3,5);
## get rows data
sub get_rows {
my ($self, @list) = @_;
return _get_rows($self,0,@list);
}
## obj->set_rows(to); append
## obj->set_rows(to, -1)
## if LIST supplied it sets every existed element for list
## if LIST not supplied it sets every element supplied
sub set_rows {
my ($self, $to, @list) = @_;
## you should check wheter it is non-duplicate elements list
my @set = ();
@list = grep /^\-?\d+$/,@list;#+0.12
if (@list == 0) {
my $next = $self->{NUMKEYS}->Length;
@list = ($next..$next+$#{$to});
}
my @spec = $self->{NUMKEYS}->Keys( @list );
if ( defined($self->{UP}) ) {
if (ref($db{$self->{UP}}) =~ /ARRAY/) {
init(__PACKAGE__, $self->{UP}, @{ $db{$self->{UP}} });
}
die "hash element \"$self->{UP}\" exists while superior file object
doesn't"
unless defined $db{$self->{UP}};
}
my %ext_set;
my %ext_del;
my ($created, $updated) = k2i($self->{FLDS},[qw/created updated/]);
for(my $i=0; $i<@spec; $i++) {
my $aref = [];
if (defined $to->[$i]) {
if (!defined $spec[$i]) {
my ($last) = $self->{NUMKEYS}->Keys(-1);
$last = 0 unless defined $last;
my $last_index = $self->{NUMKEYS}->Length-1;
$spec[$i] = $last+($list[$i]<1?0:$list[$i])-$last_index;
##print "\$last+(\$list[\$i]<1?0:\$list[\$i])-\$last_index\n";
##print $last,"\+",($list[$i]<1?0:$list[$i]),"\-",$last_index,"\n";
foreach ($last+1..$spec[$i]-1) {
## AUTOVIVIFICATION IF GAP!!!
${ $self->{TIEHASH} }{$_} = [];
$self->{NUMKEYS}->Push($_=>undef);
}
$self->{NUMKEYS}->Push($spec[$i]=>undef);
$to->[$i]->{created} = time if defined $created;
$to->[$i]->{updated} = undef if defined $updated;#?
## $to->[$i]->{nodes} = undef if exists $to->[$i]->{nodes};#?
#print "not defined created:$to->[$i]->{created}
updated:$to->[$i]->{updated}\n"
} else {
if (@{$self->{DOWN}}) {
## CLEAN external "nodes"
my $href = {};##+
@{$href}{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };##+
foreach my $e (@{$self->{DOWN}}) {
if ( defined($href->{$e}) ) {
my @temp = unpack "n*", $href->{$e};
shift @temp;
foreach my $el ( @temp ) {
push(@{ $ext_del{$e} }, [ $el, $spec[$i] ]);
}
}
}
}
$to->[$i]->{updated} = time if defined $updated;
#print "defined created:$to->[$i]->{created}
updated:$to->[$i]->{updated}\n"
}
if (@{$self->{DOWN}}) {
foreach my $e (@{$self->{DOWN}}) {
my @temp;
if (!defined($to->[$i]->{$e})) {
## implictly accept 'undef'
## array of indices of external rows
} elsif (ref($to->[$i]->{$e}) =~ /ARRAY/) {
shift @{ $to->[$i]->{$e} }
if ref($to->[$i]->{$e}->[0]) =~ /ARRAY/;
if (ref($db{$e}) =~ /ARRAY/) {
init(__PACKAGE__, $e, @{ $db{$e} });
}
if (defined $db{$e}) {
## get numkeys of supplied indices
@temp = $db{$e}->{NUMKEYS}->Keys( @{$to->[$i]->{$e}} );#0.12
} else {
die "hash element \"$e\" exists and isn't empty while superior
file object doesn't exist";
}
foreach my $el ( @temp ) {
## external row numkey, row numkey
push(@{ $ext_set{$e} }, [ $el, $spec[$i] ]);
}
} else {
die "hash $e element should be array ref!!!";
}
#push(@temp, 0) if @temp==0;
@temp = grep $_, @temp;
unshift(@temp,0);
$to->[$i]->{$e} = pack "n*", @temp;
}
}
##+ 0.09
if (defined $self->{UP}) {
my @temp;
if (!defined($to->[$i]->{nodes})) {
## implicitly accept 'undef'
} elsif ( ref($to->[$i]->{nodes}) =~ /ARRAY/ ) {
@temp = $db{$self->{UP}}->{NUMKEYS}->Keys( @{$to->[$i]->{nodes}} );
} else {
die "hash \"nodes\" element should be array ref!!!";
}
@temp = grep $_, @temp;
unshift(@temp,0);
$to->[$i]->{nodes} = pack "n*", @temp;
} ##+ 0.09
@$aref = @{$to->[$i]}{ @{$self->{FLDS}} };
} else {
last;
}
${ $self->{TIEHASH} }{$spec[$i]} = $aref;
push(@set, $list[$i]);
}
ch_nodes(\%ext_del, 1); ## DELETE
ch_nodes(\%ext_set); ## SET
## RETURNS ARRAY OF ROW ELEMENT INDICES
return @set;
}
## DELETE OR SET
sub ch_nodes {
my ($href, $what) = @_;
ch_field($href, $what, "nodes");
}
## DELETE OR SET
sub ch_field {
my $href = shift;
my $what = shift; ## false - SET, true - DELETE
my $field = shift;
my @files = keys %$href;
if (@files>0) {
foreach my $f (@files) {
if (ref($db{$f}) =~ /ARRAY/) {
init(__PACKAGE__, $f, @{ $db{$f} });
}
my $idx = k2i($db{$f}->{FLDS},[$field]);
foreach my $el ( @{$href->{$f}} ) {
my $temp = ${ $db{$f}->{TIEHASH} }{$el->[0]};
my @temp = unpack "n*", $temp->[$idx];
@temp = grep $_!=$el->[1], @temp
if $what; ## DELETE
push(@temp, $el->[1])
unless $what; ## SET
@temp = grep /^\d+/ && $_, @temp;##+0.11
unshift(@temp, 0);
$temp->[$idx] = pack "n*", @temp;
${ $db{$f}->{TIEHASH} }{$el->[0]} = $temp;
}
}
}
}
sub delete {
my ($self, @list) = @_;
my @indices; ##+$aref
@list = grep /^\-?\d+$/, @list;#+0.12
@list = $self->{NUMKEYS}->Indices($self->{NUMKEYS}->Keys) if @list == 0;
my @spec = $self->{NUMKEYS}->Keys( @list );
my %up_del;
my %down_del;
for(my $i=0; $i<@spec; $i++) {
if (defined $spec[$i]) {
my $href = {}; ##-
@{$href}{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };
if (defined $self->{UP}) {
if ( exists($href->{nodes}) ) {#&& defined($href->{nodes})
## fetch numkeys from pack'ed read structure
my @temp = unpack "n*", $href->{nodes};
shift @temp;
$href->{nodes} = [@temp];
foreach my $el ( @{$href->{nodes}} ) {
## external rows indentification keys, key to delete
push(@{ $up_del{$self->{UP}} }, [ $el, $spec[$i] ]);
}
}
}
if (@{$self->{DOWN}}) {
## CLEAN "nodes"
foreach my $e (@{$self->{DOWN}}) {
my @temp = ();
if (defined $db{$e}) {
@temp = unpack "n*", $href->{$e};
shift @temp;
} else {
die "hash element \"$e\" exists while superior file object doesn't";
}
foreach my $el ( @temp ) {
push(@{ $down_del{$e} }, [ $el, $spec[$i] ]);
}
}
}
delete ${$self->{TIEHASH}}{$spec[$i]}; ## DELETE
$self->{NUMKEYS}->Delete( $spec[$i] ); ## 0.12
push(@indices, $list[$i]);
}
}
ch_field(\%up_del, 1, $self->{FILE}); ## DELETE
ch_nodes(\%down_del, 1); ## DELETE
return @indices;
}
sub key2idx {
my ($self, @args) = @_;
return k2i($self->{NUMKEYS},\@args);
}
sub k2i {
my ($keys, $args) = @_;
my %conv = ();
@conv{ @$keys } = (0..$#{$keys});
return wantarray ? @conv{@$args} : $conv{$args->[0]};
}
sub idx2key {
my ($self, @indices) = @_;
return grep /^\d+/ && $_, @{$self->{NUMKEYS}}[@indices];
}
sub file {
my $self = shift;
return $self->{FILE};
}
sub flds {
my $self = shift;
return @{$self->{FLDS}};
}
sub up {
my $self = shift;
return $self->{UP};
}
sub down {
my $self = shift;
return @{$self->{DOWN}};
}
sub numkeys {
my $self = shift;
return $self->{NUMKEYS}->Keys;
}
sub last {
my $self = shift;
return $self->{NUMKEYS}->Length-1;
}
sub name {
my $self = shift;
if (@_) {
$self->{NAME} = shift;
}
return $self->{NAME};
}
1;
__END__
=head1 NAME
MLDBM_Handler - create and mainpulate structured MLDBM tied hash references
=head1 SYNOPSIS
use MLDBM_Handler;
@common = qw/created updated/; ## optional
$tree = [FILENAME, FIELD_NAMES_LIST,
[FILENAME1, FIELD_NAMES_LIST1,
[FILENAME2, FIELD_NAMES_LIST2],
...
],
...
];
MLDBM_Handler::add_common($tree,\@common); ## optional
%obj = ();
$obj{FILENAME} = MLDBM_Handler->init(FILENAME, $tree);
## or
$obj{FILENAME} =
MLDBM_Handler->init(FILENAME, $tree, undef, $mode, $perms);
## or
$obj{FILENAME} = MLDBM_Handler->init(FILENAME); ## NEVER FIRST TIME
@down = $obj{FILENAME}->down; ## (FILENAME1)
$obj{FILENAME1} = MLDBM_Handler::db(FILENAME1);
$file = $obj{FILENAME}->file; ## FILENAME
@down = $obj{FILENAME1}->down; ## (FILENAME2)
$obj{FILENAME2} = MLDBM_Handler::db(FILENAME2);
@set_rows_indices =
$obj{FILENAMEn}->set_rows(ARRAYREF_OF_HASHREF,[LIST]);
$up = $obj{FILENAME2}->up; ## FILENAME1
$aref_of_href = $obj{FILENAME}->get_ext_rows;
## or
($aref_of_href, @get_rows_indices) = $obj{FILENAME}->get_ext_rows;
$aref_of_href1 = $obj{FILENAME}->get_rows; ## NOT THE SAME AS ABOVE
## or
($aref_of_href1, @get_rows_indices1) = $obj{FILENAME}->get_rows;
$obj{FILENAMEn}->delete([LIST]);
$obj{FILENAMEn}->last;
=head1 DESCRIPTION
MLDBM_Handler is MLDBM module wrapper which allow to create/manipulate
associated
files' structure. For each file (table) is defined set of field's names
which
comprises row (record). Set of fields is the same for all rows. C<nodes>
is restricted
field's name and shouldn't be specified explicitly, C<created> and
C<updated> fields
are handled internally - if they are specified then: 1)on I<append row>
operation C<time>
function value is set to C<created> row field in file 2)on I<write to
existing row> operation
C<time> function value is set to C<updated> row field in file. Data get
from and set to
rows are in form of I<array reference of hash references> where hash
keys are fields' names.
There are fields' names that are FILENAMES of interior files. Those
fields contain
array reference of indices (similar to elements' array indices)
identifying particular row
in interior file. The fields MUST be set to proper values (indices)
before write rows
C<set_rows> operation.
=head2 UTILITY
=over 4
=item MLDBM_Handler::add_common
Utility sub - allow to arbitrary field's names (except C<nodes>) i.e.
C<created, updated, blahblah> to be added as next after first element
(filename) of all
arrays pointed by C<$tree> data structure before C<$tree> will be
processed by
C<init> method.
=back
=head2 CONSTRUCTOR(S)
=over 4
=item init
This method creates file data structures in file FILENAME according to
passed
array reference C<$tree> if the structures don't exists - in that case you
may change default mode C<O_CREAT|O_RDWR> or perms C<0666> if you
specify them.
Afterwards C<init> read these structures and builds object from them.
C<$tree>
defines hierarchical structure of associated files.
=item MLDBM_Handler::db
Returns object reference of interior file FILENAME. If underlaying data
structure in
file doesn't exist then it's created. Returns C<undef> on failure. Must
be invoked
after C<init>.
=back
=head2 METHODS
The following methods may be applied to object references returned by
both C<init> and
C<MLDBM_Handler::db> CONSTRUCTORS
=item flds
Returns array of all field's names of row on which operate object.
=item last
Returns last row's index or -1 if there are no rows.
=item down
Returns field's names that are FILENAMES of interior files or empty
array otherwise.
=item up
Returns field's name of superior file or C<undef> otherwise.
=item set_rows
Sets array reference of hash references as data rows in corresponding
file according
to indices list if supplied or at the end of file otherwise. If LIST is
supplied then
it sets every existed element for LIST. If LIST is NOT supplied then it
sets every
element supplied. May cause autovivification effect - adds rows - if
there is a gap between
last row's index and supplied index of unexisted row. i.e. while last
index (1) if
supplied (3) then it will add (2, 3) rows. Returns array of set rows
indices.
=item get_ext_rows
Gets data rows specified by indices list (or all row if list is not
supplied) and returns
array reference of hash references. If row field's names comprises
FILENAMES of interior
files then corresponding hash value will contain array reference - first
element of array
will be array reference of hash refrences (if that hash keys contain
FILENAMES of interior
files then it'll contain appropriate array reference and so on) and the
rest of elements
will be list of appropriate external file rows indices.
=item get_rows
Gets data rows specified by indices list (or all row if list is not
supplied) and returns
array reference of hash references. If row field's names comprises
FILENAMES of interior
files then corresponding hash value will contain array reference - the
array will contain
external file rows indices.
=item delete
Deletes rows of specified indices or all rows if no arguments. If for
row to be deleted
exists field C<nodes> and it contains array of numeric values then those
values are
indices identifying particular external file rows and data in those
external file rows
pointing to that row will be deleted too.
=item file
Returns FILENAME of file associated with object.
=item name
Sets/gets name of object.
=head1 EXAMPLE1
## DEFINE
perl -e"use MLDBM_Handler;$tree=[qw/f a
b/];$it=MLDBM_Handler->init(q/f/,$tree);"
## ADD
perl -e"use
MLDBM_Handler;$it=MLDBM_Handler->init(q/f/);$it->set_rows([{a=>11,b=>12},{a=>12,b=>13}]);"
## GET
perl -e"use
MLDBM_Handler;$it=MLDBM_Handler->init(q/f/);$g=$it->get_rows;for(@$g){print
qq/@{[%$_]}\n/}"
=head1 EXAMPLE2
use MLDBM_Handler;
@common = qw/created updated/; ## option
$tree = [qw/filename1 field1/,
[qw/filename2 field2/,[qw/filename3 field3/]]
];
MLDBM_Handler::add_common($tree,\@common); ## option
%obj = ();
$obj{filename1} = MLDBM_Handler->init("filename1", $tree);
$obj{filename2} = MLDBM_Handler::db("filename2");
$obj{filename3} = MLDBM_Handler::db("filename3");
foreach (qw/33331 33332 33333/) {
my $href;
$href->{field3} = $_;
push(@$aref, $href);
}
## NOTE: order of follownig statements is crucial to set all information
## needed about relations between those rows
@set = $obj{filename3}->set_rows($aref); ## append three rows
print "@set\n";
$href->{filename3} = [@set]; ## store indices of those rows
$href->{field2} = "22222";
@set = $obj{filename2}->set_rows([$href]);
$href->{filename2} = [@set];
$href->{field1} = "11111";
$obj{filename1}->set_rows([$href]);
$aref1 = $obj{filename1}->get_ext_rows; ## get everything
use Data::Dumper;
print Dumper($aref1);
$obj{filename3}->delete(0, -1); ## first and last row
$aref2 = $obj{filename2}->get_ext_rows; ##
print Dumper($aref2);
@flds = $obj{filename3}->flds;
print "@flds\n";
=head1 CAVEATS
Slow, slow, slow.
=head1 AUTHOR
Darek Adamkiewicz E<lt>d.adamkiewicz@i7.com.plE<gt>
=head1 COPYRIGHT
Copyright (c) Darek Adamkiewicz. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
Please feel free to e-mail me if it concerns this module.
=head1 VERSION
Version 0.13 12 OCT 2002
=head1 SEE ALSO
MLDBM, SDBM_File, Storable
=cut
------------------------------
Date: 6 Apr 2001 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin)
Subject: Digest Administrivia (Last modified: 6 Apr 01)
Message-Id: <null>
Administrivia:
The Perl-Users Digest is a retransmission of the USENET newsgroup
comp.lang.perl.misc. For subscription or unsubscription requests, send
the single line:
subscribe perl-users
or:
unsubscribe perl-users
to almanac@ruby.oce.orst.edu.
To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.
To request back copies (available for a week or so), send your request
to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
where x is the volume number and y is the issue number.
For other requests pertaining to the digest, send mail to
perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
sending perl questions to the -request address, I don't have time to
answer them even if I did know the answer.
------------------------------
End of Perl-Users Digest V10 Issue 4002
***************************************