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

Newbie alert. I am writing a program to help me learn Perl a little better. I have many computer books which I let people borrow. I decided I needed to do was make a program that would list all of my books with their author (i.e. Larry Wall - Programming Perl). I have the program open up a simple database separated by ":". From there it organizes the information. I am working on the borrow section of the database. I want the user to be able to enter in a books name, see if I have it and if it is available. If it is, the program will ask for their name and put the information into a hash. This part works well, but what is happening is it is not reading it back out to the file when it is done, instead it erases anything that is borrowed (including other authors) and erases the other books written by that author as well. Here is the borrow section of the code. Any suggestions would be greatly appreciated.
print "What Book would you like to borrow? "; my $book_to_borrow =<STDIN>; chomp $book_to_borrow; if (exists($borrowed_DB{$book_to_borrow})) { if (defined($borrowed_DB{$book_to_borrow})) { print "This book is not available for checkout\n"; } else { print "This book is available for checkout. \nPlease type your name: "; my $borrower = <STDIN>; $borrowed_DB{$book_to_borrow} = $borrower; } } else { print "Sorry. Not Available.\n"; }

Replies are listed 'Best First'.
Re: Hashes/ Simple Database
by repson (Chaplain) on Dec 04, 2000 at 12:03 UTC
    You haven't told us how it's supposed to be writing it out to file. One way to do it would be to build your data structure then output it to file with Data::Dumper and then recreate the struture in you file with require 'file'. This is a simple way of storing data from a hash. Alternativly have a look at a database such as DBD::CSV which is a backend for DBI allowing you to use a plain text file like a full database.

    For the code you are showing you may want to eithier display a list of books ie. print(join "\n",keys %borrowed_DB) or use inexact matching, maybe grepping the keys for a book title that contains the specifed text.

      I am not using any module for this program. I wanted to be able to hand code the entire thing. The written out file looks like this Author's Name:Book:Book:Book/Borrower:Book Where the colon separates the Books and author and the slash separates the particular book from the borrowee.

        Well, if you're saving the database as a flat file, you'll want to chomp $borrower before you use it in an assignment, otherwise you're file will look like:

             Author's Name:Book/Borrower
             :Book:Book:Book 
        

        rather than

             Author's Name:Book/Borrower:Book:Book:Book 
        

        This would also explain why it looks like the author's other books seem to have been erased.

        How are you building your hash?
        If I was doing this I might use a hash of hashes such as:
        $book{author}{book_name} = $borrower; which you could output all in one swoop with
        for my $author (keys %book) { print FILE $author; while (my ($book,$borrow) = each %{$book{$author}}) { print FILE ':' . $book; print FILE '/' . $borrow if $borrow; } print FILE "\n"; }
        The input is of course comparable.
        If you are using (as you seem to be) keys which are the author's name joined to the book title I would say you are making trouble for yourself and making the output code harder than it should be.

        Note: since this is homework I probably should not have given you that code, but well I did anyway....

        I think what is meant is that the standard approach is to have your own "hand-coded" module of subroutines for your system, which, in particular, should have two subroutines, say getF and putF, which handle the writing to a file, for example:

        sub getF { # warning: untested "dreamware" ... I'll test later and # (if necessary) repost a correction # General routine to read any file into a hash # (key-indexed) whose targets are anonymous hashes # (indexed by your column names) my ( $hashAdr, # reference of hash to write back to - this on +e $fileHandle, # best not to hard-code these around the place # but to have one subroutine per system # that allocates unique ones, which would # therefore get called in the main program $fileName, $fieldDelim, # best use only one per PROJECT # and if in doubt use "$;" $colNamArrAdr, # address of array of the column names - # best to use all upper or all lower case # if possible. $indexPosn # can be e.g. "3" . $; . "4" to say # that the index should be composed of columns # 4 and 5 (surpri-ise!). ) = @_; %$hashAdr = (); # initialise the hash while( <$fileHandle> ) { chop; # you know exactly one <CR> is there. my @cols = split( $fieldDelim, $_ ); my $index = join( "", split( $;, $cols[ $indexPosn ] ) ); # above is designed to handle 1 or more index columns foreach ( @$colNamArrAdr ) { $$hashadr{ $index }{ $_ } = shift( @cols ); } } return; } # the corresponding put routine is obvious from this, but # I'll just mention the important loop: foreach my $key ( sort( keys( %$hashAdr ) ) ) { my @output = (); foreach ( @$colNamArrAdr ) { push( @output, $$hashAdr{ $key }{ $_ } ); } print $fileHandle join( $fileDelim, @output ), "\n"; }
Re: Hashes/ Simple Database
by merlyn (Sage) on Dec 04, 2000 at 11:40 UTC
      I am in a Perl Class at school. We were assigned to come up with a project. I decided this was practical and useful. Plus it was a great way to learn how to use a simple read in/read out file handle. This assgnment does not have to be fully working, but I would like it to be so that I can put it to good use with my books.