The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

mysubs - lexical subroutines

SYNOPSIS

    package MyPragma;

    use base qw(mysubs);

    sub import {
        my $class = shift;

        $class->SUPER::import(
             foo   => sub { ... },
             chomp => \&mychomp
        );
    }
    #!/usr/bin/env perl

    {
        use MyPragma;

        foo(...);
        chomp ...;
    }

    foo(...);  # error: Undefined subroutine &main::foo
    chomp ...; # builtin

DESCRIPTION

mysubs is a lexically-scoped pragma that implements lexical subroutines i.e. subroutines whose use is restricted to the lexical scope in which they are imported or declared.

The use mysubs statement takes a list of key/value pairs in which the keys are subroutine names and the values are subroutine references or strings containing the package-qualified names of the subroutines. In addition, mysubs options may be passed.

The following example summarizes the type of keys and values that can be supplied.

    {
        use mysubs
            foo      => sub ($) { ... },     # anonymous sub value
            bar      => \&bar,               # code ref value
            chomp    => 'main::mychomp',     # sub name value
            dump     => '+Data::Dump::dump', # load Data::Dump
           'My::foo' => \&foo,               # package-qualified sub name
           -autoload => 1,                   # load modules for all sub name values
           -debug    => 1                    # show diagnostic messages
        ;

        foo(...);                            # OK
        prototype('foo')                     # '$'
        My::foo(...);                        # OK
        bar;                                 # OK
        chomp ...;                           # override builtin
        dump ...;                            # override builtin
    }

    foo(...);                                # error: Undefined subroutine &main::foo
    My::foo(...);                            # error: Undefined subroutine &My::foo
    prototype('foo')                         # undef
    chomp ...;                               # builtin
    dump ...;                                # builtin

OPTIONS

mysubs options are prefixed with a hyphen to distinguish them from subroutine names. The following options are supported:

-autoload

If the value is a package-qualified subroutine name, then the module can be automatically loaded. This can either be done on a per-subroutine basis by prefixing the name with a +, or for all named values by supplying the -autoload option with a true value e.g.

    use mysubs
         foo      => 'MyFoo::foo',
         bar      => 'MyBar::bar',
         baz      => 'MyBaz::baz',
        -autoload => 1;
or

    use MyFoo;
    use MyBaz;

    use mysubs
         foo =>  'MyFoo::foo',
         bar => '+MyBar::bar', # autoload MyBar
         baz =>  'MyBaz::baz';

The -autoload option should not be confused with lexical AUTOLOAD subroutines, which are also supported. e.g.

    use mysubs AUTOLOAD => sub { ... };

    foo(); # OK - AUTOLOAD
    bar(); # ditto
    baz(); # ditto

-debug

A trace of the module's actions can be enabled or disabled lexically by supplying the -debug option with a true or false value. The trace is printed to STDERR.

e.g.

    use mysubs
         foo   => \&foo,
         bar   => sub { ... },
        -debug => 1;

METHODS

import

mysubs::import can be called indirectly via use mysubs or can be overridden by subclasses to create lexically-scoped pragmas that export subroutines whose use is restricted to the calling scope e.g.

    package MyPragma;

    use base qw(mysubs);

    sub import {
        my $class = shift;

        $class->SUPER::import(
             foo   => sub { ... },
             chomp => \&mychomp
        );
    }

Client code can then import lexical subs from the module:

    #!/usr/bin/env perl

    {
        use MyPragma;

        foo(...);
        chomp ...;
    }

    foo(...);  # error: Undefined subroutine &main::foo
    chomp ...; # builtin

The import method is implemented as a wrapper around import_for.

import_for

mysubs methods are installed and uninstalled for a particular client of the mysubs library. Typically, this client is identified by its class name i.e. the first argument passed to the mysubs::import method. Note: if mysubs->import is called implicitly (via use mysubs ...) or explicitly, then the client identifier is "mysubs" i.e. mysubs can function as a client of itself.

The import_for method allows an identifier to be specified explicitly without subclassing mysubs e.g.

    package MyPragma;

    use base qw(Whatever); # we can't/don't want to subclass mysubs

    use mysubs (); # don't import anything

    sub import {
        my $class = shift;
        $class->SUPER::import(...); # call Whatever::import
        mysubs->import_for($class, foo => sub { ... }, ...);
    }

The installed subs can then be uninstalled by passing the same identifier to the unimport_for method.

Note that the import_for identifier has nothing to do with the package the lexical subs will be installed into. Lexical subs are always installed into the package specified in the package-qualified sub name, or the package of the currently-compiling scope.

mysubs->import is implemented as a call to mysubs->import_for i.e.

    package MyPragma;

    use base qw(mysubs);

    sub import {
        my $class = shift;
        $class->SUPER::import(foo => sub { ... });
    }

- is equivalent to:

    package MyPragma;

    use mysubs ();

    sub import {
        my $class = shift;
        mysubs->import_for($class, foo => sub { ... });
    }

unimport

mysubs::unimport removes the specified lexical subs from the current scope, or all lexical subs if no arguments are supplied.

    use mysubs foo => \&foo;

    {
        use mysubs
            bar => sub { ... },
            baz => 'Baz::baz';

        foo ...;
        bar(...);
        baz;

        no mysubs qw(foo);

        foo ...;  # error: Undefined subroutine &main::foo

        no mysubs;

        bar(...); # error: Undefined subroutine &main::bar
        baz;      # error: Undefined subroutine &main::baz
    }

    foo ...; # ok

Unimports are specific to the class supplied in the no statement, so pragmas that subclass mysubs inherit an unimport method that only removes the subs they installed e.g.

    {
        use MyPragma qw(foo bar baz);

        use mysubs quux => \&quux;

        foo;
        quux(...);

        no MyPragma qw(foo); # unimports foo
        no MyPragma;         # unimports bar and baz
        no mysubs;           # unimports quux
    }

As with the import method, unimport is implemented as a wrapper around unimport_for.

unimport_for

This method complements the import_for method. i.e. it allows the identifier for a group of lexical subs to be specified explicitly. The identifier should match the one supplied in the corresponding import_for method e.g.

    package MyPragma;

    use mysubs ();

    sub import {
        my $class = shift;
        mysubs->import_for($class, foo => sub { ... });
    }

    sub unimport {
        my $class = shift;
        mysubs->unimport_for($class, @_);
    }

As with the import_for method, the identifier is used to refer to a group of lexical subs, and has nothing to do with the package from which those subs will be uninstalled. As with the import methods, the unimport methods always operate on (i.e. uninstall lexical subs from) the package in the package-qualified sub name, or the package of the currently-compiling scope.

CAVEATS

Lexical subs cannot be called by symbolic reference e.g.

This works:

    use mysubs
        foo      => sub { ... }, 
        AUTOLOAD => sub { ... }
    ;

    my $foo = \&foo;

    foo();    # OK - named
    bar();    # OK - AUTOLOAD
    $foo->(); # OK - reference

This doesn't work:

    use mysubs
        foo      => sub { ... }, 
        AUTOLOAD => sub { ... }
    ;

    my $foo = 'foo';
    my $bar = 'bar';

    no strict 'refs';

    &{$foo}(); # not foo
    &{$bar}(); # not AUTOLOAD

VERSION

1.14

SEE ALSO

AUTHOR

chocolateboy <chocolate@cpan.org>, with thanks to mst (Matt S Trout), phaylon (Robert Sedlacek), and Paul Fenwick for the idea.

COPYRIGHT AND LICENSE

Copyright (C) 2008-2011 by chocolateboy

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.