NAME

Method::Lexical - private methods and lexical method overrides

SYNOPSIS

my $test = Test::Lexical->new();

$test->call_private(); # OK
$test->call_dump();    # OK

eval { $test->private() };
warn $@; # Can't locate object method "private" via package "Test::Lexical"

eval { $test->dump() };
warn $@; # Can't locate object method "dump" via package "Test::Lexical"

{
    package Test::Lexical;

    use feature qw(:5.10);

    sub new { bless {} }

    use Method::Lexical
         private          => sub { 'private' },
        'UNIVERSAL::dump' => '+Data::Dump::dump'
    ;

    sub call_private {
        my $self = shift;
        say $self->private();
    }

    sub call_dump {
        my $self = shift;
        say $self->dump();
    }
}

DESCRIPTION

Method::Lexical is a lexically-scoped pragma that implements lexical methods i.e. methods whose use is restricted to the lexical scope in which they are defined.

The use Method::Lexical statement takes a list of key/value pairs in which the keys are method names and the values are subroutine references or strings containing the package-qualified name of the method to be called. The following example summarizes the type of keys and values that can be supplied.

use Method::Lexical
  foo              => sub { print "foo", $/ }, # anonymous sub value
  bar              => \&bar,                   # code ref value
  new              => 'main::new',             # sub name value
  dump             => '+Data::Dump::dump',     # autoload Data::Dump
 'My::foo'         => \&foo,                   # override/define My::foo
 'UNIVERSAL::dump' => \&Data::Dump::dump,      # define UNIVERSAL::dump
 'UNIVERSAL::isa'  => \&my_isa,                # override UNIVERSAL::isa
 -autoload         => 1,                       # autoload all subs passed by name
 -debug            => 1;                       # show diagnostic messages

In addition, the following options are supported.

OPTIONS

Method::Lexical options are prefixed with a - to distinguish them from method names.

-autoload

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

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

use MyFoo;
use MyBaz;

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

-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.

Tracing can be enabled globally by defining METHOD_LEXICAL_DEBUG as an environment variable

e.g.

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

METHODS

import

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

package Universal::Dump;

use base qw(Method::Lexical);

use Data::Dump qw(dump);

sub import { shift->SUPER::import('UNIVERSAL::dump' => \&dump) }

1;

Client code can then import lexical methods from the module:

#!/usr/bin/env perl

use feature qw(:5.10);

use FileHandle;

{
    use Universal::Dump;

    say FileHandle->new->dump; # OK
}

eval { FileHandle->new->dump };
warn $@; # Can't locate object method "dump" via package "FileHandle"

unimport

Method::Lexical::unimport removes the specified lexical methods from the current scope, or all lexical methods if no arguments are supplied.

use Foo;
use Method::Lexical foo => \&foo;

{
    use Method::Lexical
         bar => sub { ... },
        'UNIVERSAL::baz' => sub { ... }

    my $self = bless {};

    $self->foo(...); # OK
    main->bar(...);  # OK
    Foo->new->baz(); # OK

    no Method::Lexical qw(foo);

    eval { $self->foo() };
    warn $@; # Can't locate object method "foo" via package "main"

    $self->bar(...); # OK
    Foo->new->baz(); # OK

    no Method::Lexical;

    eval { $self->bar(...) };
    warn $@; # Can't locate object method "bar" via package "main"

    eval { Foo->new->baz() };
    warn $@; # Can't locate object method "baz" via package "Foo"
}

$self->foo(); # OK

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

{
    use MyPragma qw(foo bar baz);

    use Method::Lexical quux => \&quux;

    $self->foo(...); # OK
    main->quux(...); # OK

    no MyPragma qw(foo); # unimports foo
    no MyPragma;         # unimports bar and baz
    no Method::Lexical;  # unimports quux
}

CAVEATS

Lexical methods must be defined before any invocations of those methods are compiled, otherwise those invocations will be compiled as ordinary method calls. This won't work:

sub public {
    my $self = shift;
    $self->private(); # not a private method; compiled as an ordinary (public) method call
}

use Method::Lexical private => sub { ... };

This works:

use Method::Lexical private => sub { ... };

sub public {
    my $self = shift;
    $self->private(); # OK
}

Calls to fully-qualified method names are interpreted as normal (public) method calls. So the following are not interpreted as lexical method calls:

my $method = 'Foo::Bar::baz';

$self->Foo::Bar::baz();
$self->SUPER::foo();
$self->$method();

Likewise, method calls on glob or filehandle invocants are interpreted as ordinary method calls.

VERSION

0.01

SEE ALSO

AUTHOR

chocolateboy <chocolate@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2009 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.