views:

94

answers:

2

I'm having some problems writing data into a file using Perl.

    sub startNewOrder{
    my $name = makeUniqueFileName();
    open (ORDER, ">$name.txt") or die "can't open file: $!\n";
    format ORDER_TOP = 
    PRODUCT<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<CODE<<<<<<<<AANTAL<<<<EENHEIDSPRIJS<<<<<<TOTAAL<<<<<<<
.
    format ORDER =
    @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<< @<<<< @<<<<<< @<<<<<
    $title,                              $code,    $amount, $price, $total
.
    close (ORDER);
}

This is the sub I use to make the file. (I translated most of it.) The makeUniqueFileName method makes a fileName based upon current time("minuteshoursdayOrder"). The problem now is that I have to write to this file in another sub.

sub addToOrder{
print "give productcode:";
$code = <STDIN>;
chop $code;
print "Give amount:";
$amount = <STDIN>;
chop $amount;
if($inventory{$code} eq undef){ #Does the product exist?
    print "This product does not exist";
}elsif($inventory{$code}[2] < $amount && !defined($inventaris{$code}[2]) ){ #Is there enough in the inventory?
    print "There is not enough in stock"
}else{
    $inventory{$code}[2] -= $amount;
    #write in order file
    open (ORDER ">>$naam.txt") or die "can't open file: $!\n";
    $title = $inventory{$code}[0];
    $code = $code;
    $amount = $inventory{$code}[2];
    $price = $inventory{$code}[1];
    $total = $inventory{$code}[1];
    write;
    close(ORDER);
}

%inventory is a hashtable that has the productcode as key and an array with the title, price and amount as value. There are two problems here: when I enter an invalid product number, I still have to enter an amount even while my code says it should print the error directly after checking if there is a product with the given code.

The second problem is that the writing doesn't seem to work. It always give's a "No such file or directory" error. Is there a way to open the ORDER file I made in the first sub without having to make $name not local? Or just a way to write in this file? I really don't know how to start here. I can't really find much info on writing a file that has been closed before, and in a different sub.

Any help is appreciated,

Harm

+4  A: 

You should start by adding these lines to your code:

use strict;
use warnings;

They will catch potential typos. For example, $inventaris is a different variable from $inventory. Did you really mean to have two variables? It is hard to tell from your code. Similarly, do you really have a variable named $naam?

Yes, it is possible to write to a file from 2 separate subs. Currently, $name is local to your startNewOrder sub. One way to make it visible to your other sub is to declare it at the start of your code, making it global to your code file. Can you move your format into the same sub as your write?

In your code, it is more appropriate to use chomp instead of chop.

It is better to check for the existence of a hash key using exists than to compare it against the value returned by undef.

use strict;
use warnings;

my $name = makeUniqueFileName();

# Sample data
my %inventory = (
    c1 => [ 1 .. 3 ],
    c2 => [ 4 .. 6 ]
);

addToOrder();

sub addToOrder { 
    print "give productcode:\n"; 
    my $code = <STDIN>; 
    chomp $code; 
    print "Give amount:\n"; 
    my $amount = <STDIN>;
    chomp $amount;
    if (not exists $inventory{$code}) {
        print "This product does not exist\n"; 
    }
    # etc...
}

I realize I did not answer all of your questions. Perhaps you could focus on one question at a time, and provide a self-contained, runnable example with a small sample of actual data. I often solve my own problems by reducing my code to a minimal example which still reproduces the problem.

toolic
+2  A: 

Subroutines should do as little work as possible and keep the the smallest scope as possible. In your case, you don't want to have to open a file in every subroutine. Open the file once and pass around the opened filehandle. You don't have to close and re-open the file every time.

Since you want to use formats, you have to use bareword filehandles:

 my $name = makeUniqueFileName();
 open ORDER, '>', $name or die ...;

 start_new_order( \*ORDER );
 add_to_order( \*ORDER );

 sub start_new_order {
      local *ORDER = shift;
      ...
      write ORDER;
      }

 sub add_to_order {
      local *ORDER = shift;
      ...
      write ORDER;
      }

You can define your formats anywhere. You don't have to define them in the subroutine, so just put them by themselves at the end of the file.

brian d foy