retrieving a constant from a dynamically loaded module

retrieving a constant from a dynamically loaded module

am 26.10.2005 12:29:16 von olivier.grant

Hi All,

I need to be able to dynamically load a module and retrieve a constant
from it. Simply put, i want to allow a user to specify a module
HisModule.pm containing the package HisModule and get
HisModule::VERSION.

in his file :
[code]
package HisModule;
use constant VERSION;
1;
[/code]

in my code :
[code]
$module = shift @ARGV;
print " Using module v".$module::VERSION."\n";
[/code]

I know this is not the right syntax, but I can't seem to find it .. Is
it even possible to do this ?

Thanks,

Olivier

Re: retrieving a constant from a dynamically loaded module

am 26.10.2005 12:36:18 von Gunnar Hjalmarsson

olivier.grant@gmail.com wrote:
> I need to be able to dynamically load a module and retrieve a constant
> from it. Simply put, i want to allow a user to specify a module
> HisModule.pm containing the package HisModule and get
> HisModule::VERSION.
>
> in his file :
> [code]
> package HisModule;
> use constant VERSION;
> 1;
> [/code]
>
> in my code :
> [code]
> $module = shift @ARGV;

chomp $module;
require $module;

> print " Using module v".$module::VERSION."\n";
> [/code]

--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl

Re: retrieving a constant from a dynamically loaded module

am 26.10.2005 14:12:05 von olivier.grant

I got that part, but the problem is that as standard, each module and
script has a constant called "TSD_VERSION", so I need to be able to
specify that the TSD_VERSION constant i'm looking for is the one from
the module specifyed by the user, so the syntax should look something
like this :

$module::TSD_VERSION;

but that doesn't work. wrapping this statement in an eval will work,
but several problems pop in :
the following line of code

eval("print ".$module."::TSD_VERSION;");
eval("print(\"module version
v\".".$ScriptData{'CoreModule'}."::TSD_VERSION);");

will print the correct version number, but if you add a bit more to the
line to output doesn't work :

eval("Logger::Print(\"Using core module \".$ScriptData{'CoreModule'}.\"
v\".".$ScriptData{'CoreModule'}.'::TSD_VERSION'.".\"
(\".".$ScriptData{'CoreModule'}.'::TSD_LAST_UPDATE'.".\")\\n \");");

(sorry for the obscure code)

Re: retrieving a constant from a dynamically loaded module

am 26.10.2005 17:03:01 von unknown

olivier.grant@gmail.com wrote:

[snip!]

> the following line of code
>
> eval("print ".$module."::TSD_VERSION;");
> eval("print(\"module version
> v\".".$ScriptData{'CoreModule'}."::TSD_VERSION);");
>
> will print the correct version number, but if you add a bit more to the
> line to output doesn't work :
>
> eval("Logger::Print(\"Using core module \".$ScriptData{'CoreModule'}.\"
> v\".".$ScriptData{'CoreModule'}.'::TSD_VERSION'.".\"
> (\".".$ScriptData{'CoreModule'}.'::TSD_LAST_UPDATE'.".\")\\n \");");
>
> (sorry for the obscure code)
>

Well, there's something to be said for the K.I.S.S. principle. Why build
a big complicated string if you can call Logger::Print directly, and
just eval() the part that needs eval()-ing? Something like

Logger::Print ("Using core module '$ScriptData{CoreModule}' v" .
eval {"$ScriptData{CoreModule}::TSD_VERSION"} .
eval {"$ScriptData{CoreModule}::TSD_LAST_UPDATE} . "\n");

seems clearer to me.

If you must build a big complicated string, have you printed it before
eval()-ing it, to see what you get? You might also consider using the
"qq{}" construct, so you don't have to escape all the embedded quotes.
Note that in my cold-coded simplification I changed your output by using
the "'" character. If you _must_ have '"', consider Logger::Print
(qq{Using core module "$ScriptData{CoreModule} v" ...

Tom Wyant

Re: retrieving a constant from a dynamically loaded module

am 26.10.2005 17:16:52 von Peter Scott

On Wed, 26 Oct 2005 05:12:05 -0700, olivier.grant wrote:
> I got that part, but the problem is that as standard, each module and
> script has a constant called "TSD_VERSION", so I need to be able to
> specify that the TSD_VERSION constant i'm looking for is the one from
> the module specifyed by the user, so the syntax should look something
> like this :
>
> $module::TSD_VERSION;

In your first posting you claimed that this was defined by the constant
pragma, i.e.,

use constant TSD_VERSION => 42;

In which case it's a subroutine, not a scalar, and the syntax for
retrieving it from outside the package will be

$module->TSD_VERSION()

which isn't going to interpolate (easily) into double quoted strings of
course, but that doesn't matter.

--
Peter Scott
http://www.perlmedic.com/
http://www.perldebugged.com/

Re: retrieving a constant from a dynamically loaded module

am 26.10.2005 18:04:15 von olivier.grant

Thanks alot for your answers.

Tom : I was sure eval just returned a boolean value representing
evaluation success. Now that i think about it, such a limiting output
would have been stupid in Perl (I'm still very new to this language),
and that's why I stuffed everything in the "eval" statement.

Peter : I didn't know that constants were considered as functions, and
was pretty use that the only way to get on from a package if not
exported was to use the '::' syntax. Thanks for the info.

BR,

Olivier

Re: retrieving a constant from a dynamically loaded module

am 26.10.2005 19:33:24 von unknown

olivier.grant@gmail.com wrote:
> Thanks alot for your answers.
>
> Tom : I was sure eval just returned a boolean value representing
> evaluation success. Now that i think about it, such a limiting output
> would have been stupid in Perl (I'm still very new to this language),
> and that's why I stuffed everything in the "eval" statement.

No problem. Perl is a big, sprawling language. Assuming evaluation
succeeds, eval () returns its results. Otherwise it returns undef and
sets "magic" variable $@. Bear in mind that a successful eval () can
also return undef.

> Peter : I didn't know that constants were considered as functions, and
> was pretty use that the only way to get on from a package if not
> exported was to use the '::' syntax. Thanks for the info.
>

I like Peter's suggestion better than mine. He's using object-oriented
syntax, which puts an extra argument on the front of the call list. But
your "constant" subroutines ignore their arguments, so that's OK. Just
beware of doing $module->subroutine () in general.

The unofficial Perl motto is "There's more than one way to do it." I
just thought of another one. Going back to your original example, it's

$subname = "${module}::VERSION";
print " Using module v", &$subname, "\n";

If you have done "use strict;" above this, you will need to have "no
strict ('refs'); just before you call a subroutine this way, and "use
strict ('refs'); after it, to turn it back on. In your actual code you
don't need to enclose the hash value in curly brackets, but in the
original example you do, because Perl thinks $module::VERSION is scalar
variable VERSION in module 'module', and you don't want that.

But I still like Peter's suggestion the best, because it looks to me
like the cleanest code.

Tom Wyant