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

Hi Monks!

I'm playing around with "use constant" to better understand the pragma, and I ran into a curiosity question. Here's the scenario:

MyObject.pm defines and exports constants as follows:

use Exporter; our @ISA = qw(Exporter); use constant { LOG_DEBUG => 0, LOG_INFO => 1, LOG_WARN => 2, LOG_ERROR => 3, }; our @EXPORT = qw(LOG_DEBUG LOG_INFO LOG_WARN LOG_ERROR);
and the calling script uses these variables to instantiate an object of type MyObject like this:
my $obj = MyObject->new(level=>LOG_DEBUG);

What I can't figure out how to do is specify the parameter in an XML config file, as <Level>LOG_DEBUG</Level>. I'm using XML::Simple to parse the config file, and I wind up with a hash that holds the string "LOG_DEBUG", which is quite different from the constant function LOG_DEBUG.

Is there an easy way to make this work?

I know it's not good practice to export stuff by default, but I'm just playing with a contrived scenario to explore the pragma.



PCS

Replies are listed 'Best First'.
Re: Trying to understand the 'use constant' pragma
by Zaxo (Archbishop) on Sep 06, 2005 at 23:58 UTC

    XML::Simple (or any of the XML:: family modules) will treat xml files as text. There is no attempt to evaluate perl expressions within that text.

    You may be able to handle this as a special case with eval,

    # notional dereference, use whatever is correct for your xml struct $xml->{'Level'} = eval $xml->{'Level'};
    Constants from constant.pm are really subs with an empty prototype, so you may need to append '()' or even write ${\LOG_DEBUG()} to get the evaluation done in a quoted string.

    In this case, it might be simpler to do a substitution.

    my %level = { LOG_DEBUG => 0, LOG_INFO => 1, LOG_WARN => 2, LOG_ERROR => 3, ); use constant \%level; # . . . { my $regex = qr/(${\join '|', keys %level})/; s/$regex/$level{$1}/g; }

    After Compline,
    Zaxo

      Thanks Zaxo, I will try this. I probably wouldn't do it in production code, but for the sake of followint through on my exercise I will take a few more whacks at it. Thanks to everyone who responded!
      PCS
Re: Trying to understand the 'use constant' pragma
by GrandFather (Saint) on Sep 06, 2005 at 23:43 UTC

    Assuming that you have control over MyObject.pm, perhaps the easiest solution is to use your constants internally to the module and accept a string in the constructor:

    my $obj = MyObject->new(level=>'LOG_DEBUG');

    You can use a hash to translate the level string to your internal code as required.


    Perl is Huffman encoded by design.
      This is a reasonable solution, and does what I originally intended. I was just wondering if there is a way of making the "use constant" effect extend further, but since the input from the xml file is text strings, this doesn't appear to be possible. Thanks!
      PCS
Re: Trying to understand the 'use constant' pragma
by runrig (Abbot) on Sep 06, 2005 at 23:44 UTC
    You could use symbolic references, but don't do that. I'd probably use a hash array instead of constant if I were going to store this sort of stuff in a config file.

    An alternative is to use the string as a method to the package where the constants are defined, e.g.:

    package Foo; use constant LOG_DEBUG => 0; package main; my $log_level = 'LOG_DEBUG'; print Foo->$log_level, "\n";
Re: Trying to understand the 'use constant' pragma
by phaylon (Curate) on Sep 06, 2005 at 23:46 UTC
    Well, I'm on my way to bed, but maybe this helps:

    You should use "strict" and "warnings" (see perldoc for more information) to point out common errors. The constant pragma basically defines a sub with an empty prototype, so adding () to the LOG_DEBUG in the object creation may tell if the export works.

    hth & good night

    Ordinary morality is for ordinary people. -- Aleister Crowley