An interesting question.
Firstly, let's discount exporting package variables. It's easy enough to do, and while they can't be lexically scoped, you can provide a dynamic-scoped value (similar to the effects of local). You'd just set up the variable in your import method, and use B::Hooks::EndOfScope to restore the old value at the end of the scope that imported you...
use strict;
use warnings;
BEGIN {
package MyVars;
use Exporter::Shiny;
use B::Hooks::EndOfScope;
sub import {
no strict "refs";
my $caller = caller;
my $old_value = ${"$caller\::pi"};
*{"$caller\::pi"} = do { my $new_value = 3.14159; \$new_value
+};
on_scope_end {
*{"$caller\::pi"} = \$old_value;
}
}
};
use Data::Dumper;
{
use MyVars;
BEGIN { print Dumper($pi) }
}
BEGIN { print Dumper($pi) }
However, note that the print statements in the importing package need to happen at compile time; this is because our dynamic definition of the variable only happens at compile time; by run time it's gone.
So that's a useless idea. On to lexical variables.
The tricky part is actually declaring the lexical variable in the caller's scope so that when they use the variable, it doesn't result in a compile-time error. This requires using parser hooks. B::Hooks::Parser is pretty reliable, and works on Perl 5.8+.
use strict;
use warnings;
BEGIN {
package MyVars;
use Exporter::Shiny;
use B::Hooks::Parser;
our $pi = 3.14195;
sub import {
B::Hooks::Parser::inject(sprintf('my $pi; BEGIN { $pi = $%s::p
+i };', __PACKAGE__));
}
};
use Data::Dumper;
my $pi = 3;
{
use MyVars;
print Dumper($pi);
}
print Dumper($pi);
With a little extra work (and Data::Alias), you could make the "exported" $pi into an alias for the $MyVars::pi package variable. Or you could make it read-only. Or a tied variable, or an overloaded object, or whatever.
Update: I've packaged up this solution as Exporter::LexicalVars. I'll probably release a stable version in a few days.
use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
|