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

Esteemed Monks...

What is the best way for config file to contain perl code, for example stub routines, right now I'm usually slurping config file via required

#... require "/etc/myname.cfg"; ..

I tried config file modules but they're usually not flexible enough, and require way more code and awareness then simple require... and such simple method work great for specifying values, arrays, hashes etc... but what about subs?

Back to the point, I would like to specify something as a callback, or generally would like to allow defining perl code in config... my current solution looks like that:

# /etc/myscript.cfg $somehash = { 'Somestuff'=> { #... }, 'Someotherstuff'=> { #.... 'Actions'=> [ "print \"hello world\";", ] }, }
And then I just eval lines from Actions array.

This looks awkward in configfile, because of all this quoting required, and editors won't hilight this correctly, I'm having problems accessing variables from such eval'd code, etc,

to sum this up - code specified in configfile looks extremely ugly and unclear.

Are there better ways to do that?

UPDATE: Based on feedback I updated my method to something like this:

package Scriptname; require "/etc/scriptname.cfg"
package Scriptname; $somehash=> { 'Something'=> { #.. stuff .. 'Sub' => sub { print "Hello world, "; print "here is my local var: $var\n"; }; } };
This one is a little easier on the eyes, instead of eval I use
my $sub=$somehash->{'Something'}->{'Sub'}; &$sub() if defined($sub);

Still not perfect, but it's a serious improvement over the mess I used to create... thanks.

Replies are listed 'Best First'.
Re: What's the best way to put perl code in config file?
by dave_the_m (Monsignor) on Sep 21, 2004 at 10:51 UTC
    'Actions'=> [ "print \"hello world\";", ]
    I'd suggest using anonymous subs:
    'Actions'=> sub { print "hello world"; ...; }

    Dave.

•Re: What's the best way to put perl code in config file?
by merlyn (Sage) on Sep 21, 2004 at 10:52 UTC
    For me, the best way is not to do any of that. Create a class that either uses callbacks (passed in as coderefs during instance creation) or subclassing. Then your code gets defined and designed properly, and can be tested as well. "include files" for configuration is soooo 90s. {grin}

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      Personally creating a class would be my method of choice.

      Depending on how you read them, plain config files can lead to all sorts of messy namespace pollution with incautious Exporting. Keeping things in a class tightens things up a bit and keeps it all clean. Much easier to keep things under the obligatory use strict as well :)

      Hmm, how exactly am I supposed to pass coderef to a script?

      And what is the naughties way of dealing with config files?

        And what is the naughties way of dealing with config files?

        Tongue in cheek: clearly it must be XML-derived, have well-defined DTDs, written up as a RFC, have provable and hashed content to avoid contaminations, and signed by a trusted certificate authority. Being able to fetch an initial local config from an https repository is a plus.

        I think things are often over-designed, even in the Perl world. Think of effective design, not capable design.

        It's not bad to use something simple and "old-fashioned" that works, as long as you isolate your design decisions so they can be improved later. Keep a mind on the possible security implications (such as how someone can inject new code into a string that gets eval treatment).

        P.S. -- this is my 600th post on perlmonks.org
        --
        [ e d @ h a l l e y . c c ]

        If you can trust your users (or if you can trust them to secure their machines properly), a clean way to do this is to let your application have a "plugins" directory full of simple Perl modules all adhering to a common interface, and then require each of these modules. Each plugin module could have a method called "make_callback" (or equivalent), and they would be all properly namespaced and sorted.

        Then you will need some way to instantiate them and add them to a list of active plugins, but this should be left as an exercise to the reader (it's simple enough).

        But in general, unless you are writing something like the GIMP or PhotoShop or an Application Server, it might be best to not have users write code to modify the way your program works. Depends what you are doing, of course, there may be moer usable/friendly ways. Meanwhile, if I'm installing a Wiki or something, I have no problem editing perl config files, it's just horrific if you mess one up because you'd get a syntax error or some obscure runtime error rather than the application telling you what's up as part of a config file verification process. So avoid making users write code if you can help it (some don't even know what '$' means!)

Re: What's the best way to put perl code in config file?
by gothic_mallard (Pilgrim) on Sep 21, 2004 at 10:54 UTC

    If you're wanting to define sub routines (or stubs) why don't you consider the path of creating it as a module instead of a config file? That'd allow you to use Exporter to do most of the work.

    You can then define your callbacks as anonymous subs such as:

    $printHello = sub{print "Hello world\n"};

    .. which once exporter you can of course invoke with &$printHello() - none of those nasty evals :)

    Does this help or am I on the wrong track here?

Re: What's the best way to put perl code in config file?
by TedPride (Priest) on Sep 21, 2004 at 11:20 UTC
    I like the anonymous referenced subs method myself.