April 2018 Archives

Extracting exported variables from a module

Here is a routine from a module I made to extract the variables from a module so they can be put into Perl documentation:

=head2 extract_vars

    extract_vars ('Moby', \%vars);

Extract all the exported variables from the specified module, so if
Moby exports C<$data_dir> then 

    $vars{data_dir} = $Moby::data_dir

This examines C<@EXPORT_OK> in Moby to get the list of variables, and
also evaluates Moby. It assumes that it is being run from a
F<make-pod.pl> which is situated such that Moby is in F<lib/Moby.pm>.

Thus this is strongly dependent on a specific file layout.

Use

    extract_vars ($pm, \%vars, verbose => 1);

for debugging.

=cut

sub extract_vars
{
    my ($module, $vars, %options) = @_;
    if ($module =~ m!/!) {
        warn "$module looks wrong; use \$info->{colon} not \$info->{pm}";
    }
    my $verbose = $options{verbose};
    if ($verbose) {
        print "Module is $module.\n";
    }
    my $evals = "use lib \"$Bin/lib\";use $module ':all';";

    if ($verbose) {
        print "Evaling '$evals'.\n";
    }
    eval $evals;
    if ($verbose) {
        print "Getting exports from $module.\n";
    }
    my @exports = get_exports ($module);
    for my $var (@exports) {
        if ($var =~ /\$(.*)/) {
            if ($verbose) {
                print "Adding $var to variables.\n";
            }
            my $nodollar = $1;
            $vars->{$nodollar} = eval "\$$module::$nodollar";
        }
        elsif ($var =~ /((\@|\%)(.*))/) {
            my $variable = $1;
            my $sigil = $2;
            my $nosigil = $3;
            my $export = "\\$sigil$module::$nosigil";
            if ($verbose) {
                print "Adding $variable as $export.\n";

            }
            $vars->{$nosigil} = eval $export;
        }
    }
}

The documentation is generated from a script called "make-pod.pl" in the top directory using the template toolkit.

The routine "get_exports" here looks like this:

# Helper to get exported variables.

sub get_exports
{
    my ($module) = @_;
    my @exports;
    eval "use lib \"$Bin/lib\";use $module ':all';\@exports = \@${module}::EXPORT_OK";
    if ($@) {
    croak $@;
    }
    return @exports;
}

About Ben Bullock

user-pic Perl user since about 2006, I have also released some CPAN modules.