Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Maintaining state in modules

by cLive ;-) (Prior)
on Sep 05, 2002 at 20:25 UTC ( [id://195489]=perlquestion: print w/replies, xml ) Need Help??

cLive ;-) has asked for the wisdom of the Perl Monks concerning the following question:

I want a module I'm writing to maintain state - ie keep track of when it's called and supply output based on how it was previously used. How should I go about storing this data?

My idea was to use a directory, using the following rules:

  • if user supplies a directory for data when the module is called, use that.
  • if not, try to create a data dir in the current directory called .mod_data - or something
  • otherwise die stating that data dir is needed

Is this a valid approach, or should I try something else? (bearing in mind I want it to be cross platform, so dbm is probably out :)

Thoughts welcomed.

cLive ;-)

--
seek(JOB,$$LA,0);

Replies are listed 'Best First'.
Re: Maintaining state in modules
by perrin (Chancellor) on Sep 05, 2002 at 20:33 UTC
    SDBM_File is installed with Perl on most systems. A flat file is fine though if it's a small amount of data. Just make sure you document it in the POD.
Re: Maintaining state in modules
by VSarkiss (Monsignor) on Sep 05, 2002 at 21:26 UTC

    I second perrin's suggestion above regarding using flat files if the data is small enough.

    Another option to consider is to let the caller hand you an open file handle (or an IO::File object). That gives the caller full control over where to put the data, so your modules becomes portable to platforms you don't know about yet. Furthermore, it would allow passing in a tie'd filehandle to play games you haven't thought of.

Re: Maintaining state in modules
by KM (Priest) on Sep 05, 2002 at 20:47 UTC
    Is it a CGI or non-CGI script? Look on the CPAN for 'session' to find ways to keep a session going, and store the info based on the session.

    Why not make a base class and subclass it with a way to do it with dbm's. Then, subclass to use MySQL (or whatever). People can subclass to use with whatever data store they wish to use (a DB, flat file, directory structure, etc...) that way your design will make it more portable.

    Also, look on the CPAN, and search Google for ways other are maintaining state, so you don't re-invent any wheels.

    Cheers,
    KM

Re: Maintaining state in modules
by mojotoad (Monsignor) on Sep 06, 2002 at 05:18 UTC
    If the lifetime of the configuration information is relatively short, you might consider using temp directories for the file homes.

    Otherwise, something like File::HomeDir might assist in homesteading your files.

    Simply assuming "current directory" is asking for trouble if you ask me, whether it be from inconsistencies, security issues, or permission problems.

    Matt

      I agree with Matt in that perm problems will cause errs on your scripts. You could get around them by installing with uid 0, but that would be bad. What about letting them specify a state config file? Maybe /etc/myApp.state?
Re: Maintaining state in modules
by Theseus (Pilgrim) on Sep 06, 2002 at 12:26 UTC
    You should look into Data::Dumper if you aren't a fan of it already. After I learned of its existence and how to use it, it solved any data persistence problems I ever had. You can even store instantiated objects and it will save their state for the next time. Once you work out a way to store the output(text file, in a database record, etc), you're all set.
Re: Maintaining state in modules
by Anonymous Monk on Sep 06, 2002 at 08:32 UTC
    I use Storable for saving state, and usually write the file to the home directory as .something-meaningful
Re: Maintaining state in modules
by John M. Dlugosz (Monsignor) on Sep 06, 2002 at 19:12 UTC
    You got a lot of replies about DBM and ways to actually do the saving. I have a comment on the file part. For portability, names beginning with a dot may be not allowed on a file system; and the "current directory" is a shaky concept.

    I'd make the location and/or filename more explicit to the module user, and the filename at least in one constant somewhere so it can be changed trivially if needed.

    In fact, isolating the save/restore logic is a good idea in general, so the whole thing could be replaced without affecting the rest of the module.

Re: Maintaining state in modules
by hiseldl (Priest) on Sep 06, 2002 at 19:50 UTC
    If you just need to save the last state you could use Config::IniFiles to store the state. This gives you a recognizable file format, a portable module and a flexible interface to your data. I have used this method on both Linux and Win2k boxes, without changing my code.

    Here is an example that should give you an idea of how this works. I prefer using the tied method because IMHO it is easier to work with an HoH than a bunch of method calls.

    use Config::IniFiles; # my $cfg = new Config::IniFiles( -file => "configfile.ini" ); # or my %ini tie %ini, 'Config::IniFiles', ( -file => "configfile.ini" ); # do stuff with %ini # create a new section and add values $ini{new_section} = {}; $ini{new_section}{new_param1} = $val; $ini{new_section}{new_param2} = $val2; # add a multiline value $ini{new_section}{new_param2} = [$value1, $value2, ...]; # save with the TIED hash # overwrite the current ini file tied( %ini )->RewriteConfig(); # or you can write to a different file #tied( %ini )->WriteConfig ($NewFilename); # save with object ref # overwrite the current ini file #$cfg->RewriteConfig(); # or you can write to a different file #$cfg->WriteConfig ($NewFilename);
    Even though it is tied to a hash you will still have to call RewriteConfig() or WriteConfig($file) in order to save it.

    This is portable and human readable! :)

    --
    hiseldl

Re: Maintaining state in modules
by blssu (Pilgrim) on Sep 06, 2002 at 19:56 UTC

    You should probably use the operating system's normal per-user configuration solution because (1) you want to build on what the user already knows, and (2) you don't want one user of the module screwing up other users.

    On a Windows box, the right answer is almost always the registry. Just check $^O and then eval Windows-specific versions of your history module. The registry is really easy to use with the Win32::TieRegistry module:

    use Win32::TieRegistry ( Delimiter => '/' ); my $key = $Registry->{'HKEY_CURRENT_USER/Software/MyModule/History'}; my $dir = ($key ? $key->GetValue('Cwd') : 'C:/';

    On a Unix box, the right answer is almost always a dot file in $HOME. Make sure the home directory is really the user's home if you execute things from your history file. (You probably want to do the same checks if you use Data::Dumper because that can eval code.)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (4)
As of 2024-04-26 05:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found