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

Hey Perl Monks... well, I am asking a three-part question, firstly, the code that I have written in here, I want it criticized (not in an acidic way, I am new to Perl - 2 weeks old - and I handled the files for the first time today, in the past 10 minutes, hehe), I am eager to get your feedback secondly, how can I get to save the same sort of data entered through this program in another type of files like spreadsheet .xls instead of the simple .txt file? I tried saving it in .xls, but could not figure out how to make the fields "specialization, name and age" column headers instead of cell members (I don't want them to repeat everytime I run the code, or jump rows over between an entry and another, like from age to name it jumps a line) thirdly, I want to enforce a certain order in the hash values, Perl returns hash keys not the same ordered they have been entered I am aware, but I want the program to give me prompts in this order name -> specialization ->age, instead of specialization -> name -> age..
#!/usr/local/bin/perl use strict; use warnings; my %info = ( 'name' => ' ', 'age' => ' ', 'Specialization' => ' ', ); open FILE, '>>C:\Documents and Settings\m\Desktop\info.txt' or die $!; foreach my $key (keys %info){ print "enter your $key\n"; print FILE "$key: " ,$info{'$key'}=<>, "\n"; }

Replies are listed 'Best First'.
Re: a dynamic program???
by CountZero (Bishop) on Jun 18, 2009 at 18:46 UTC
    Mmmm, where to start?

    ++ for using the strictures use strict; and use warnings;!

    You do know that you do not have to "pre-declare" the keys of your hash? my %info; is enough to make use strict; happy.

    It is considered beter to use as your filehandle a lexical variable, so open my $filehandle, ... would have given you extra points. And when your lexical variable goes out of scope, the file is closed automatically.

    The three argument version of open is again considered a better practice:

    open my $filehandle, '>>', 'C:\Documents and Settings\m\Desktop\info.t +xt'

    ++ for checking the return value of the open.

    You do know that '>>' is opening the file in append mode, i.e. it retains it previous contents? That may be exactly what you want, so I am not criticizing this.

    Finally the loop can be re-written as follows (and it answers your third question):

    foreach my $key (qw/name Specialization age/){ print "enter your $key\n"; $info{$key} = <STDIN>; chomp $info{$key}; # get rid of the EOL print $filehandle "$key: $info{$key}\n"; }
    Do not put single quotes around a variable ($info{$key} rater than $info{'$key'}) as it will be taken as a string literal and not as a variable.

    Unless you want to keep the EOL character at the end of each answer, use chomp to get rid of it.

    Finally, don't use <> unless you know what you are doing. The docs say as follows:

    The null filehandle <> is special: it can be used to emulate the behavior of sed and awk. Input from <> comes either from standard input, or from each file listed on the command line. Here's how it works: the first time <> is evaluated, the @ARGV array is checked, and if it is empty, $ARGV[0] is set to "-", which when opened gives you standard input. The @ARGV array is then processed as a list of filenames. The loop
    while (<>) { ... # code for each line }
    is equivalent to the following Perl-like pseudo code:
    unshift(@ARGV, '-') unless @ARGV; while ($ARGV = shift) { open(ARGV, $ARGV); while (<ARGV>) { ... # code for each line } }
    except that it isn't so cumbersome to say, and will actually work. It really does shift the @ARGV array and put the current filename into the $ARGV variable. It also uses filehandle ARGV internally--<> is just a synonym for <ARGV>, which is magical. (The pseudo code above doesn't work because it treats <ARGV> as non-magical.)
    I bet you didn't know that!

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: a dynamic program???
by toolic (Bishop) on Jun 18, 2009 at 18:09 UTC
    how can I get to save the same sort of data entered through this program in another type of files like spreadsheet .xls instead of the simple .txt file?
    Have you tried using a CPAN module, such as Spreadsheet::WriteExcel?
    I want to enforce a certain order in the hash values
    You could enter the data into an ARRAYS OF HASHES or use Tie::IxHash.
      ohh, I have tried to figure out how to install the CPAN, but I know where to install it in Perl, from the @INC return value directories, but I can not figure out if this CPAN thing comes as a full module to be downloaded at once or if it is like I download whatever I need at the time I need it, I did not find like an organized way to do this, can anyone give me some clues?.. up ahead on the time I think I would need to download BioPerl, I reckon it gotta be the same procedure to downloading CPAN, is that right?

        In addition to what others have said, you can - just in case you are using ActiveState - also use the Active State Package Manager to install additional modules ... just in case you get stuck with cpan and need a quick solution (but in general, it is true that you should get familiar with the cpan utility).

        -- 
        Ronald Fischer <ynnor@mm.st>
Re: a dynamic program???
by jethro (Monsignor) on Jun 18, 2009 at 18:41 UTC
    my @info=('name','Specialization','age'); my %info; #if you want it initialized, add =map { $_,' ' } @info; ... foreach my $key (@info) {
Re: a dynamic program???
by dec (Beadle) on Aug 16, 2009 at 01:02 UTC
    Perl returns hash keys not the same ordered they have been entered I am aware
    So you need to use a second structure which will enforce the order you require. Something like this might be what you're looking for:
    foreach my $key (qw(name specialization age)) { print "enter your $key\n"; print FILE "$key: " ,$info{'$key'}=<>, "\n"; }
    Actually Perl goes further than not guaranteeing that hash keys will be read out in the same order they've been written in. As the second paragraph in my man page for the 'keys' builtin reads:
    The keys are returned in an apparently random order. The actual random order is subject to change in future versions of perl, but it is guaranteed to be the same order as either the "values" or "each" function produces (given that the hash has not been modified). Since Perl 5.8.1 the ordering is different even between different runs of Perl for security reasons (see "Algorithmic Complexity Attacks" in perlsec).
    So if you're running your unmodified code in version 5.8.1 or later different runs will give randomly generated order for the questions. But at least with three input values, you'll get the order you want 1 in 6 times!
      Thanks for explaining the part about retrieving hash keys ordering and the security aspect, I wouldn't be surprised to see that behavior now :)...take care

      Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.