Re: Sharing Namespaces
by davido (Cardinal) on Jan 27, 2006 at 07:28 UTC
|
Perl comes prepackaged with Exporter, which is what you need. It allows for exporting none, some, or all variables, functions, ...whatever. Its documentation goes into better and more accurate detail than I can offer. Exporter (and other namespace issues) is also discussed in depth in perlmod. Good stuff there!
| [reply] |
|
Well, I understand how Exporter exports stuff from a module, but how would I basically, /import/ a namespace into another module? That's basically what I'm trying to figure out.
Sort of the reverse.
-justin simoni
skazat me
<script language="JavaScript" src="http://quotes.prolix.nu/cgi-bin/random_quote_js.pl"> </script>
| [reply] |
|
A namespace is not a data structure, so you wouldn't want to do that :)
| [reply] |
Re: Sharing Namespaces
by duff (Parson) on Jan 27, 2006 at 07:35 UTC
|
Perl will not use or require the same file twice without some prodding, so you're not saving anything in your attempted optimization.
Aside from the excellent advice to use Exporter, if your Config.pm file (not a good name BTW) has a package declaration and the variables are package variables, then you can access those variables by their full name (i.e. $Config::foobar) from within your main program and any modules that use your module. It sounds like this is what you're doing, but I wanted to be sure.
| [reply] [d/l] [select] |
|
This is basically what I'm doing - but let me get something straight -
Perl will not use or require the same file twice without some prodding, so you're not saving anything in your attempted optimization.
Does that mean, that under the hood, Perl is only loading up the code in say, Config.pm once and every other call is just being directed to the address in memory where this code is?
Cause that would make my problem moot.
| [reply] |
|
Yes, on use/require perl checks whether $INC{<modulepath>} exists (<modulepath> being e.g. "My/Module/Namespace") and if so does not attempt to load the module again. This behaviour can be conveniently exploited when mocking modules (see chromatic's MockObject tutorial for more on this).
Update: note, this does not mean that the original module's code only gets run once, so e.g. if your Config module loads a configuration file it will still reload that file every time the module is called. It just means that the module's .pm file only gets loaded once and the code isn't duplicated in memory.
There are ten types of people: those that understand binary and those that don't.
| [reply] [d/l] |
|
|
Re: Sharing Namespaces
by tirwhan (Abbot) on Jan 27, 2006 at 07:36 UTC
|
package Config;
require Exporter;
our @ISA=qw(Exporter);
our @EXPORT_OK=qw(read_config);
sub read_config {
my %data;
# read configuration file in and
# put values into a hash
return \%data;
}
In the modules that use Config:
package One;
use Config qw(read_config);
my $conf = read_config();
Granted, you then have your configuration data in a hash and need to call it with e.g. $conf->{logfile} instead of $logfile but IMO that's cleaner anyway.
There are ten types of people: those that understand binary and those that don't.
| [reply] [d/l] [select] |
|
Yeah, I agree with the hashref idea is cleaner, I'm just a little committed to the current interface - which is just a namespace within Config.pm that gets exported to the script that's use()ing it.
And actually, I don't see how you're idea would be any better - each module would still have to use() Config, and then go through the whole process of loading up the variables from the outside file, etc.
Actually, this is almost exactly what I"m doing :) Understood, I can just pass $conf as a paramater for say, Two.pm's new() constructer.
| [reply] |
|
That's the way I'd normally go, load your configuration once during system initialisation and then just pass the hashref/object holding this information around to other modules.
Another way would be to use a Singleton (see for example Class::Singleton or Class:StrongSingleton). You'd still have to use and call the Config module in every other module, but Config would only load the configuration file once and just return the same instance of itself on every other call (note: this will and can not work with forked processes).
There are ten types of people: those that understand binary and those that don't.
| [reply] [d/l] |
Re: Sharing Namespaces
by brian_d_foy (Abbot) on Jan 27, 2006 at 14:31 UTC
|
Ideally, you want all of your namespaces to share the config data without having to copy it, and you also want them to use the config data in the same way so that you remember they are the same thing when you look at your different namespaces.
This is a good candidate for the Singleton Pattern, which I cover in the issue 0.1 of The Perl Review or Scott Walter's wiki page on Singletons. Basically, your Config class creates an object that everyone can use at the same time in different places without knowing about all the other places that want to use it, and it only ever makes one object so you don't waste space on a bunch of copies.
Since you encapsulate your config information in this object, you only have one config variable in each namespace. That makes maintenance much easier if you decide to change things later.
Good luck!
| [reply] |
Re: Sharing Namespaces
by gloryhack (Deacon) on Jan 27, 2006 at 07:32 UTC
|
use One;
use Config;
my $config = Config -> new();
my $one = One -> new();
if ($one -> can('config') {
$one -> config($config);
}
There's one. | [reply] [d/l] |
|
erm, ok, what's $config? A reference to a variable? A typeglob... what? At the moment, the Config.pm module isn't an OO bit of code, it's just a list of variables, basically - that's why I was interested in exporting the entire namespace (sorry if that wasn't clear - my bad)
| [reply] |
|
| [reply] |
Re: Sharing Namespaces
by glasswalk3r (Friar) on Jan 27, 2006 at 11:19 UTC
|
I'm not sure how many classes do you have that depends on Config class, so this may not help.
I think that, instead of having to pollute the namespace of your classes somehow, you should make Config an abstract class and make the the parent classes (in the top of hierarchy) to inherity it. As Perl supports multiple inheritance you shouldn't have any problem with that if you take care with the names that you're going to use for the variables. Creating them with use constant looks like a good idea too.
Of course, this will require that you change a lot of code, so you must consider if this is applicable for you.
Alceu Rodrigues de Freitas Junior
---------------------------------
"You have enemies? Good. That means you've stood up for something, sometime in your life." - Sir Winston Churchill
| [reply] [d/l] |
Re: Sharing Namespaces
by Anonymous Monk on Jan 27, 2006 at 19:50 UTC
|
perl -le 'BEGIN { $Foo::bar = "Hello"; %Baz:: = %Foo::; } print $Baz::
+bar'
The namespace copy has to happen at compile-time. Perl won't respect runtime namespace replacement, since it optimizes away global variable lookups into static addressing at runtime.... | [reply] [d/l] |
|
perl -le '$Foo::bar = "Hello"; *Baz::bar = *Foo::bar; print $Baz::bar
+'
Works if you iterate over the namespace instead of trying to do it in one shot.
For slinging around globs, you might find this snippet illustrative. Basically a very small exporter.
Why not just use set up the module to by default, export everything you're interested in. Then it's a matter of just adding the "use" statement to each module/script, (but they're already using it right?).
| [reply] [d/l] |