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

I am working on a project, which involves many different script files. I would like to be able to have a file that is required (or of some sorts to make it work) so that it is basically a list of scalars, arrays and hashes (all of the basic built-ins) that allows me to setup a 'Configuration' of the system I am working on. I have read the document on Lexical Scoping and partially through have found that the part where requiring lextut1.pl which has $foo defined in another file is partially incorrect. I have in cases used this sort of require to do exactly what I am talking about.

The problem? Well the problem is this. When I use strict to make sure that I am not doing something utterly ignorant, it complains about $foo not being declared. Here is a basic code example.

# file: conf.pl $foo = 'bar'; # file: script.cgi #!/usr/bin/perl use strict; require 'conf.pl'; { ... print $foo; ... } #
Simple I know, but this is the sort of usage that I am looking for. The only problem, is strict screams about the variable not being declared. Although, if you actually remove strict, this works.

However, I would like to use strict. Has anyone else considered this type of problem? Has there ever been a good solution to this?

Any help in this matter would be greatly appreciated.
Thanks,
Matt (mhorner)

Replies are listed 'Best First'.
Re: Require Centralized Variables
by broquaint (Abbot) on Nov 20, 2002 at 14:47 UTC
    The only problem, is strict screams about the variable not being declared.
    That's because strict requries variables to be declared or fully qualified. So your script will work if you qualify $foo as being in the main package e.g
    shell> cat > tmp.pl $foo = "a string"; 1; ^D shell> perl -e 'use strict; require "tmp.pl"; print $::foo, "\n"' a string
    There we qualified it with the preceding double colon (which is a shorter way of saying main::).

    As for lexical variables declared in another file, they will fall out of scope at the end of a require, as they will no longer be in the file scope as demonstrated in the lexical scoping tutorial. You might also want to check out the first half of the <plug>symbol tables and globs tutorial</plug> for more info on package variables.
    HTH

    _________
    broquaint

Re: Require Centralized Variables
by joealba (Hermit) on Nov 20, 2002 at 14:50 UTC
    Exporting the variables from another package is probably a better way to go about this, rather than using a require. (And, exporting a hash of the variables is even cleaner.)
    # file: MyConf.pm package MyConf; use strict; use vars qw( @ISA @EXPORT_OK @EXPORT %Conf ); require Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw( %Conf ); @EXPORT = @EXPORT_OK; $Conf{'foo'} = 'bar'; $Conf{'this guy walks into a'} = 'bar'; # file: test.pl use strict; use MyConf; print "$Conf{'foo'}\n";
Re: Require Centralized Variables
by mirod (Canon) on Nov 20, 2002 at 15:21 UTC

    Instead of require-ing the variables from conf.pl why don't you use one of the many modules that let you store and retrieve variables, such as Storable, FreezeThaw, Data::Denter, Data::DumpXML, XML::Simple... or just use your own module, which would then let you export variable as well as functions.

    In any case you should pay extra attention to where the data file is located (outside of the web tree is a good idea) and what its permissions are (probaly not writeable by the web server user).

      Let me second this! As usual, mirod knows well what he is saying.

      I worked on a project earlier this year that had URIs and paths hardcoded throughout the programs. Whenever one program was moved from testing to production, the original coder had spent several minutes manually editing the paths, as the testing and production environments were different. (They should have been the same, but that is a story for another time.)

      One of the first things I did was to write a small module based on Data::Denter. It looked in the same location on the production and testing boxes for a configuration file. It loaded all of the configuration values into a hash and made them available. Then, I removed all of the paths and URIs and put them in the configuration file. Finally, I defined constants in all of the programs, and added code to load the configuration module and to populate the important constants.

      This turned out to be an even bigger win in one circumstance. I wanted to do some profiling of some detailed code, so I added debugging sections. Because I didn't want to slow things down in general, I used the if (0) {} trick -- and I could control whether or not the debugging code was stripped by the optimizer simply by changing one value in the configuration file.

      YAML would be another one I would add to mirod's list.

      You might also want to consider one of the Config:: modules as an alternative.


      (hmmm... just realised that this was my 100th post...)

Re: Require Centralized Variables
by DamnDirtyApe (Curate) on Nov 20, 2002 at 14:49 UTC

    In your script.cgi:

    #! /usr/bin/perl -w use strict ; use vars qw( $foo ) ; do "conf.pl" ; print "foo is $foo\n" ;

    _______________
    DamnDirtyApe
    Those who know that they are profound strive for clarity. Those who
    would like to seem profound to the crowd strive for obscurity.
                --Friedrich Nietzsche
Re: Require Centralized Variables
by Abigail-II (Bishop) on Nov 20, 2002 at 15:47 UTC
    So, why do you want to use strict? Using strict is just a tool, not a goal. In this case, it's obstructing what you want to do, so why use it? You shouldn't use something if you don't know what it does.

    Using strict this way requires that all variables are either lexical, fully qualified, or been introduced with use vars. You do neither So, if you insist on using strict, you should obey the rules that are imposed. Also, if you prefer to use strict, why aren't you using it in your conf.pl file?

    Abigail

      I understand that strict is a tool and using it helps to make sure that I am not doing something that is a violation of reasonably good coding. Therefore using strict helps in saving me extra time trying to debug stupid problems. Now, if you can tell me that you don't spend time trying to debug a stupid error without using strict, then please tell me your secret. Also, the reason I am not using strict in the conf.pl is to allow the requiring of the conf.pl file without strict complaining about the undeclared variables in the conf.pl file. There I am usually certain that the code that is included there is just a list of scalars, arrays and/or hashes.

      It wasn't my intention to have the conf.pl file be the issue at hand, but the file that is requiring the conf.pl and using the conf.pl in making the changes to my scripts easier when moving to a new system/rebuild that may not exactly replicate the system that it was previously running on.

      Thanks for the criticism,
      Matt (mhorner)
Re: Require Centralized Variables
by YuckFoo (Abbot) on Nov 20, 2002 at 20:12 UTC
    When I have a set of config values to be shared by many programs, I put them in a module and 'use' it. I manually export the variables into the main package as described by Dominus here.

    YuckFoo

    ==== MyConfig.pm ==== package MyConfig; my $CONFIG = { color => 'blue', animal => 'camel' }; *{"::CONFIG"} = \$CONFIG; 1; ==== testit.pl ==== #!/usr/bin/perl use strict; use MyConfig; print "$CONFIG->{color} $CONFIG->{animal}\n";
Re: Require Centralized Variables
by axelrose (Scribe) on Dec 05, 2002 at 09:47 UTC
    Another possible solution I prefer is to avoid having variables in the required script
    # main script require "conf.pl"; my $conf = get_conf(); print $conf->{foo}; ... # conf.pl sub get_conf { { foo => "bar", color => "red" } } 1;