Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Accessing module variables

by talexb (Chancellor)
on Apr 19, 2018 at 15:04 UTC ( [id://1213173]=perlquestion: print w/replies, xml ) Need Help??

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

I want to cycle through a bunch of modules that have credentials and site URLs .. I have this working OK, but it seems that I'm doing it in a much complicated way than I should. Feedback would be appreciated.

This script illustrates how I plan to cycle through the credential modules:

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; { my @variables = qw/User Password Url Prefix/; foreach my $module ( qw/Foo Bar/ ) { eval "use ABCXYZ::$module"; # Foreach loop for illustration only .. could be replaced # with a map .. my %values; foreach my $var ( @variables ) { $values{ $var } = eval '$' . join ( '::', 'ABCXYZ', $module, $var ); } # Call subroutine with values hash here .. } }

The goal is to be able to call a routine with individual site credentials for order processing. Is there a more Perl-ish way of accomplishing this? Credential modules look like this:

package ABCXYZ::Foo; use Exporter; our @Export = ( $User $Password $Url $Prefix ); our $User = 'Joe'; our $Password = 'Secret123'; our $Url = 'www.example.com'; our $Prefix = 'EX'; 1;
The credentials are stored like this so that the processing scripts can be checked into github without credentials leaving the customer site.

Alex / talexb / Toronto

Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Replies are listed 'Best First'.
Re: Accessing module variables
by Eily (Monsignor) on Apr 19, 2018 at 15:24 UTC

    The credentials are stored like this so that the processing scripts can be checked into github without credentials leaving the customer site.
    "like this" meaning? In separate files, in .pm files, in exported package scalars? Depending on how much you can change, it might be easier to store the values in a hash in the first place:
    our @Export = ( %credentials ); our %credentials = ( User => 'Joe', Password => 'Secret123' ...); # or: (User => $User, Password => $Password ...); if you want to still + define the scalars
    Or even better, store them as proper configuration files with whatever format you want.

    It looks like your modules are supposed to export all their variables (although you used @Export rather than @EXPORT). If that's the case, you should use require rather than use, so that you don't import each time and overwrite the $User, $Password... in your calling package.

      If that's the case, you should use require rather than use, so that you don't import each time and overwrite the $User, $Password... in your calling package.

      Or else leverage this to your advantage, import them each time through the loop and just refer to them by their local symbol names.

      Although I agree that it would be better not to start from here and go with config files instead.

        It looks like your modules are supposed to export all their variables (although you used @Export rather than @EXPORT) ..

      Oh dear. What a rookie mistake. Yes, I think I meant to use EXPORT.

      In any case, clearly the credentials should be stored in configuration files and not modules .. that would make it easier for external control .. these processes are currently being handled by a crontab setup, which works well, but isn't ideal.

      Thanks for the feedback!

      Alex / talexb / Toronto

      Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Re: Accessing module variables
by Discipulus (Canon) on Apr 19, 2018 at 17:35 UTC
    Hello talexb,

    If you have many modules with such data (really password in modules? I'm sure you are aware already of this..) I'd consider a radical change: parse everything with PPI and produce many distinct modules with a lonely accessor, or better put everything in a db.. anyway..

    cat Varz.pm package Varz; use Exporter; our @EXPORT = ( $User, $Password, $Url, $Prefix ); our $User = 'Joe'; our $Password = 'Secret123'; our $Url = 'www.example.com'; our $Prefix = 'EX'; 1;

    You can just copying vaules from one package to your current one as in:

    perl -Mstrict -MVarz -we "our($User, $Password, $Url, $Prefix); map{ $ +main::{$_} = $Varz::{$_} } keys %Varz:: ; print join qq(\n),$User, $ +Password, $Url, $Prefix" Joe Secret123 www.example.com EX

    If you want to get a bit mad about symbol table, I recently moved my library

    L*

    PS you may want to grep out unwanted elements: grep{$_ !~/export|begin/i}keys %Varz::

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
        If you have many modules with such data (really password in modules? I'm sure you are aware already of this..)

      I wanted something quick that wouldn't involve me putting credentials into the scripts themselves .. and would also allow the credentials to be shared between multiple scripts. Putting them in a module that wasn't covered by version control seemed to be the easy solution.

      In hindsight, a better way would have been to create a credentials module that would do a lookup in a JSON configuration file .. just so I don't have to copy the four lines of code to open, read and transform JSON into a Perl data structure. That's for the future, I guess.

      Anyway, I have a solution that works fine right now. Thanks for the feedback.

      Alex / talexb / Toronto

      Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Re: Accessing module variables
by LanX (Saint) on Apr 19, 2018 at 15:17 UTC
    Well you could inspect the package stash(es) instead of using eval.

    It would be faster but not necessarily clearer.

    Another approach without eval is using symbolic refs, you need to locally no strict 'refs'; for that.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Wikisyntax for the Monastery

      Some code for introspection.

      Used strict to demonstrate clean approaches

      DB<80> package ABC::Foo; our $User='talexb'

      > Well you could inspect the package stash(es) instead of using eval. *

      DB<81> use strict;print ${ $main::{"ABC::"}{"Foo::"}{User} } talexb

      > Another approach without eval is using symbolic refs, you need to locally no strict 'refs'; for that.

      DB<82> use strict; no strict 'refs'; print ${ 'ABC::Foo::User' } talexb

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Wikisyntax for the Monastery

      *) NB: you could also avoid the main:: stash and hardcode

      DB<99> use strict;print ${ $ABC::{"Foo::"}{User} } talexb

      if ABC is static in your code.

Re: Accessing module variables
by karlgoethebier (Abbot) on Apr 20, 2018 at 07:46 UTC

    It might be better to use a config file:

    talexb.pl

    #!/usr/bin/env perl use strict; use warnings; use Config::Tiny; use Data::Dump; my $config = Config::Tiny->read(q(talexb.cfg)); dd $config; __END__

    talexb.cfg

    [credentials] user = 'Joe'; password = 'Secret123'; url = 'www.example.com'; prefix = 'EX';

    Quite easy and untested. If this is what you wanted. See also Config::Tiny.

    Best regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

      Thanks for your contribution -- as usual, my situation is a bit more complicated.

      I have a master configuration file with a list of sites. Each entry has a name, whether they're enabled, and the name of the file that contains that last order number. From the name (Foo, in my original post), I'm able to find the module with the credentials. And, although I wasn't crazy about the idea, a database is starting to make sense (especially for the last order number), but I really like the low maintenance feel of just editing a text file, compared to fiddling with a database.

      Alex / talexb / Toronto

      Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Re: Accessing module variables
by Anonymous Monk on Apr 19, 2018 at 18:15 UTC
    I wonder why you don't just use a database instead – say, an SQLite database file? No server required, and now you simply look-up the credentials and URLs that you need for each host.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1213173]
Approved by stevieb
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (2)
As of 2024-04-26 04:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found