0

I am trying to create some scripts for web testing and I use the following piece of code to set up variables from a config file:

package setVariables;
sub readConfig{
  open(FH, "workflows.config") or die $!;
  while(<FH>)
  {
    ($s_var, $s_val) = split("=", $_);
    chomp($s_var);
    chomp($s_val);
    $args{$s_var} = $s_val;
    print "set $s_var = $s_val\n";
  } 
  close(FH);
}

for example: var1=val1 var2=val2 var3=val3 etc...

I want to be able to pass the values set by this subroutine to a subroutine in another package. This is what I have for the package I want it passed into. package startTest; use setVariables;

sub startTest{
my %args = %setVariables::args;
my $s_var = $setVariables::s_var;
my $s_val = $setVariables::s_var;

setVariables::readConfig(); #runs the readConfig sub to set variables

my $sel = Test::WWW::Selenium->new( host => "localhost",
                                    port => 4444, 
                                    browser => $args{"browser"}, 
                                    browser_url => $args{"url"} );


$sel->open_ok("/index.aspx");
$sel->set_speed($args{"speed"});
$sel->type_ok("userid", $args{"usrname"});
$sel->type_ok("password", $args{"passwd"});
$sel->click_ok("//button[\@value='Submit']");
$sel->wait_for_page_to_load_ok("30000");
sleep($args{"sleep"});
}

Unfortunately its not holding on to the variables as is and I don't know how to reference them. Thank you for any help.

4 Answers4

3

Your code has some problems. Let's fix those first.

# Package names should start with upper case unless they are pragmas.
package SetVariables;

# Do this EVERYWHERE.  It will save you hours of debugging.
use strict;
use warnings;

sub readConfig{

  # Use the three argument form of open()
  open( my $fh, '<', "workflows.config") 
    or die "Error opening config file: $!\n";

  my %config;

  # Use an explicit variable rather than $_
  while( my $line = <$fh> )
  {
    chomp $line;    # One chomp of the line is sufficient.
    ($s_var, $s_val) = split "=", $line;

    $config{$s_var} = $s_val;
    print "set $s_var = $s_val\n";
  }

  close $fh;

  return \%config;
}

Then use like so:

use SetVariables;

my $config = SetVariables::readConfig();

print "$_ is $config->{$_}\n" 
  for keys %$config;

But rather than do all this yourself, check out the many, many config file modules on CPAN. Consider Config::Any, Config::IniFiles, Config::JSON.


You note in your comment that you are trying to work with multiple files, your main code and a couple of packages.

One pattern that is common is to load your config in your main code and pass it (or select elements of it) to consuming code:

package LoadConfig;

sub read_config {
    my $file = shift;

    my $config;
    # Do stuff to read a file into your config object;

   return $config;
}

1;

Meanwhile in another file:

package DoStuff;

sub run_some_tests {
    my $foo = shift;
    my $bar = shift;

    # Do stuff here

    return;
}

sub do_junk {
    my $config;

    my $foo = $config->{foo};

    # Do junk

    return;
}

1;

And in your main script:

use DoStuff;
use LoadConfig;


my $config = LoadConfig::read_config('my_config_file.cfg');

run_some_tests( $config->{foo}, $config->{bar} );
do_junk( $config );

So in run_some_tests() I extract a couple elements from the config and pass them in individually. In do_junk() I just pass in the whole config variable.

daotoad
  • 26,689
  • 7
  • 59
  • 100
  • 2
    I like using the [`autodie`](http://perldoc.perl.org/autodie.html) pragma, for example code I post to StackOverflow, rather than using `open ... or die ...`. There are a few quirks which may prevent using it in production code, but for example code it helps to reduce the number of *incantations* required to have *bullet-proof* code. – Brad Gilbert Apr 06 '11 at 03:56
  • 1
    @DVK - for one, it has problem with [global encoding set for open](http://stackoverflow.com/questions/4959384/does-the-autodie-pragma-have-influence-on-the-encoding). But it does it consistently, so hard to call it quirk. – bvr Apr 06 '11 at 11:29
  • 1
    @bvr, @Brad - duh. Indubitably, SO had to already have an answer to my question :) http://stackoverflow.com/questions/3941632/are-there-disadvantages-to-autodie – DVK Apr 06 '11 at 13:34
  • Thank you for the improved code. I still can't get it to work however. My issue still appears to be scoping, I'm sure there's something I'm doing wrong. When I run it I get "Use of uninitialized value in concatenation (.) or string at StartLogin.pm line 20." I'm still having scoping issues. To give a little more information, the 2 bits of code I gave are both packages wherein one script is calling sub startTest from one package which is in turn calling sub readconfig from another package. I'm not sure if perl can handle this (obviously I'm very new to perl). Thank you for your help. – William Tarver Apr 06 '11 at 17:07
  • @William Tarver, don't try to use global variables to pass your data around. Instead, explicitly pass your config variable around. I'll update the body of my response above with your use case. – daotoad Apr 06 '11 at 18:46
0

all you need to do is collect the variable in a hash and return a reference to it in readConfig:

my %vars = ( var1 => val1,
             var2 => val2,
             var3 => val3,
           );

return \%vars;

and in startTest:

my $set_vars = setVariables::readConfig();
ennuikiller
  • 46,381
  • 14
  • 112
  • 137
0

I would suggest using a regular format, such as YAML, to store the configuration data. You can then use YAML::LoadFile to read back a hash reference of the configuration data and then use it.

Alternatively, if you don't want to use YAML or some other configuration format with pre-written modules, you'll need for your reading routine to actually return either a hash or a a hashref.
If you need some more background information, check out perlref, perlreftut and perlintro.

Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
BadFileMagic
  • 701
  • 3
  • 7
0

Are your users going to see the configuration file or just programmers? If it's just programmers, put your configuration in a Perl module, then use use to import it.

The only reason to use a configuration file for only programmers if you are compiling the program. Since Perl programs are scripts, don't bother with the overhead of parsing a configuration file; just do it as Perl.

Unless it's for your users and its format is simpler than Perl.

PS: There's already a module called Config. Call yours My_config and load it like this:

use FindBin '$RealBin';
use lib $RealBin;
use My_config;

See: perldoc FindBin perldoc Config

shawnhcorey
  • 3,545
  • 1
  • 15
  • 17