http://qs321.pair.com?node_id=701224

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

I need to separate out some routines that I reuse on several perl programs. I want to put them all in an external .pl file that I can by some method include in others. For the sake of clarity I'll call the file with the separate routines the "Library" and the programs that need to call it "Client".

In the Library I want to have something like this.

$variable1 = #SOME CALCULATION

and I want the Client to do something like this...

my $variable1; require "./Library.pl"; print "$variable1\n";
When I try this, $variable1 doesn't get set properly in the Client program.
I know that the assignment in the Library works because if I print the variable in it, the value is correct.
I am not sure what I'm doing wrong.
Any suggestions?

Replies are listed 'Best First'.
Re: use, require, do or what?
by massa (Hermit) on Jul 30, 2008 at 18:57 UTC
    Just two suggestions:
    1. Don't use loose .pl files. Make proper modules, with their own namespaces. perlmod is your friend.
    2. Don't make assignment to variables inside your modules. Return the value of the calculation from a function, and use that.
    What you have will be something like:
    use strict; package Module1; use Exporter 'import'; our @EXPORT_OK = qw(compute_value); sub compute_value { # do the computation } 1; # this is required, see perldoc perlmod
    in the file "Module1.pm" and something like:
    use strict; use Module1; my $variable1 = Module1::compute_value();
    or:
    use strict; use Module1 qw(compute_value); my $variable1 = compute_value();
    in your main script.
    []s, HTH, Massa (κς,πμ,πλ)
      Creating a proper module isn't an option. I have to work within the constraints of my employer's dev environment.

      The whole purpose of the code is to assign values to variables. I over-simplified in my examples.

      Basically, the code is to take ARGV and convert it into a date, and if there is no ARGV it creates the date based upon localtime.
        Could you please explain to me exactly _how_ your employer's dev env precludes you from making proper modules and subroutines instead of loose .pl files? Modules can be put in the current dir, just like your .pl file in your example...
        []s, HTH, Massa (κς,πμ,πλ)
        Wait, so then why are you trying to put the variables in another file?
        -Actualize
        A reply falls below the community's threshold of quality. You may see it by logging in.
Re: use, require, do or what?
by ysth (Canon) on Jul 30, 2008 at 19:59 UTC
    Disclaimer: please heed those who suggest wrapping the Library code into one or more subroutines that return the desired values. Or failing that, use our() variables. Do not do the following.

    The "what" you are looking for is the mystical map{eval(readline!open(!((*{!$_},$/)=\$_)))} operator. Example (given $variable1 = "SOME CALCULATION"; in Library.pl):

    $ perl -w my $variable1; map{eval(readline!open(!((*{!$_},$/)=\$_)))} "Library.pl"; print "$variable1\n"; __END__ SOME CALCULATION
    (based on theDamian evilness, improved by ysth)

      Truly evil. It makes my head hurt. Did I say that that is truly evil?

      Unfortunately, I don't have 6 or 7 free hours to figure it out for myself. Would you be willing to explain how it works to the slow among us? Or do you have a link that does?

      Update: I just occurred to me that the perfect name for this 'operator' is the "Scanners operator", in reference to the movie Scanners, especially for the infamous head exploding scene--WARNING!!! that link leads to a clip of the gruesome and truly infamous scene.


      TGI says moo

Re: use, require, do or what?
by moritz (Cardinal) on Jul 30, 2008 at 18:52 UTC
    It doesn't work because $variable1 is only known in your client file, not in the library.

    The solution is to encapsulate the code in the library into a subroutine, and call that:

    require "./Library.pl"; my $variable1 = sub_from_library(); print "$variable1\n";

    Even better: make the library a module, and then use it.

Re: use, require, do or what?
by pc88mxer (Vicar) on Jul 30, 2008 at 18:57 UTC
    When you declare a variable with my it won't be accessible in require-d code. One alternative is to use our instead of my:
    our $var; require 'library.pl'; # library.pl contains: # $var = ... print $var, "\n";
    However, modifying variables this way in not a great idea. Think about what the purpose of the module is. For instance, if you are using it to compute a function, make the module define a subroutine which is called by your program when it's needed. If is being used to define constants, then consider putting it in its own namespace and exporting the values.
Re: use, require, do or what?
by actualize (Monk) on Jul 30, 2008 at 19:08 UTC
  • First of all, you don't need the './' before your file. @INC should contain your current directory. (this is an array that contains all of the places where perl expects to find code.)
  • Secondly, name the file Library.pm not Library.pl.
  • Thirdly, if you are going to reuse this library you might want to use package instead of require. Then you can use $Library::variable to reference the variable in your library and it is perfectly safe for you to reuse variable names in your code without messing with the Library namespace.
  • happy variable calling from Library!

    -Actualize
Re: use, require, do or what?
by educated_foo (Vicar) on Jul 31, 2008 at 02:38 UTC
    "my" means "lexical," and "lexical" means "can be used within the set of curlies (or file) containing the declaration. You don't want to use "my" in this case.
Re: use, require, do or what?
by almut (Canon) on Jul 30, 2008 at 19:56 UTC

    I'm not recommending this approach, but if you really need to get it working, you can eval Library.pl's content. That's similar to do, but differs in that lexical variables in the enclosing scope are visible in the eval.

    my $variable1; open my $lib, "<", "./Library.pl" or die $!; { local $/; eval <$lib>; } close $lib; print "$variable1\n";
Re: use, require, do or what?
by actualize (Monk) on Jul 30, 2008 at 21:15 UTC

    Yeah, pass through a subroutine. So that you can get the return value from your Library.pm code

    mainfile.pl
    package Library.pm $output = Library::subroutine($variable)
    Library.pm
    sub subroutine { $variable = shift $variable = changingthedata($variable) return $variable }
    -Actualize