punkish has asked for the wisdom of the Perl Monks concerning the following question:

I am at my wit's end, so please tell me where I am being stupid. Given a directory of files, I am trying to create the following multi-level hash.

my %o = ( $yyyy => {$mm => {$dd => ['file_1'..'file_n']}} );

Here is my code for doing so

use strict; use File::Find; use Fcntl; # to get 'em constants use MLDBM qw(DB_File Storable); our $dir = '/home/punkish/stuff'; our $db = '/home/punkish/data/files_by_dates.bdb'; our %o; createDatesDb(); sub createDatesDb { # delete existing db, and create a new one unlink "$db"; tie %o, 'MLDBM', "$db", O_CREAT|O_RDWR, 0640 or die $! +; find(\&_buildDatesDb, ("$dir") ); untie %o; } sub _buildDatesDb { if (-f $_) { my @t = localtime( (stat("$_"))[9] ); my $yyyy = $t[5] + 1900; my $mm = sprintf("%02d", $t[4] + 1); my $dd = sprintf("%02d", $t[3]); if (exists $o{$yyyy}) { if (exists $o{$yyyy}->{$mm}) { # year, month, and day exist, so push the file # into the day's array if (exists $o{$yyyy}->{$mm}->{$dd}) { my $aref = $o{$yyyy}->{$mm}->{$dd}; push(@$aref, $_); } # year exists, and month exists, but day doesn't yet exist, # so add it and all other info else { $o{$yyyy}{$mm}{$dd} = [$_]; } } # year exists, but month doesn't yet exist, # so add it and all other info else { $o{$yyyy}{$mm} = {$dd => [$_]}; } } # year doesn't yet exist, so add it and all other info else { $o{$yyyy} = {$mm => {$dd => [$_]}}; } } }

Pretty, simple. Except, it doesn't work, and I can't figure out why. If I Dumper \%o, I get the entire structure only one level deep. That is, I get all the years, but for each year, I get only one month, and for each month, I get only one day, and for each day, I get only one file in the array.

Here is the kicker. If I don't tie the hash, that is, I comment the unlink ..; tie ..; untie ..; lines in createDatesDb then Dumper \%o the untied hash, it shows up just the way I want it... that is, the hash is populated with all the files. Obviously, my logic is working, but the tie-ing is not.

What am I overlooking?

--

when small people start casting long shadows, it is time to go to bed

Replies are listed 'Best First'.
Re: tie oddity
by perrin (Chancellor) on May 21, 2006 at 18:57 UTC
    Sounds like you missed this in the docs. It's easy to get around, by setting the top-level value, or you can use DBM::Deep.
      punkish-- for not reading the docs carefully.
      perrin++ for pointing out the problem, and saving me from committing crimes to my Dell.

      DBM::Deep is a great module because of its portability. It has two problems for now that prevent me from using it. I was unable to install it cleanly on my Mac (I think Module::Build was causing it to throw up). But, really, DBM::Deep is way too slow for some of the functions I need. Once I figure out a way around those, I will look back at DBM::Deep, and probably migrate to it.

      --

      when small people start casting long shadows, it is time to go to bed
        What problems are you having? I'm surprised that it's throwing up on the Mac because I am developing DBM::Deep on a Mac.

        What kind of functions are too slow? I'm currently rewriting the engine code from the ground up and would like to know where your speed requirements are.

        And, dbm-deep is a great module for another major reason - it's Perl's datastructures tied to disk in a multi-process fashion. This allows you to think in Perl's datastructures without having to worry about how to store stuff until later (if ever).


        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: tie oddity
by merlyn (Sage) on May 21, 2006 at 18:56 UTC
Re: tie oddity
by japhy (Canon) on May 22, 2006 at 03:02 UTC
    There is also MLDBM::Easy which I wrote to get around the particular bug in MLDBM that's vexing you.

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: tie oddity
by Cody Pendant (Prior) on May 22, 2006 at 09:56 UTC
    Just a note, nothing to do with your problem, but are you checking whether the hash values exist because of the tied db? Auto-vivification means you don't have to, under normal circumstances.


    ($_='kkvvttuu bbooppuuiiffss qqffssmm iibbddllffss')
    =~y~b-v~a-z~s; print