Export-Lexical

 view release on metacpan or  search on metacpan

lib/Export/Lexical.pm  view on Meta::CPAN

use 5.010;
use strict;
use warnings;
use B;
use Carp;

our $VERSION = '0.0.6';

my %exports_for  = ();
my %modifier_for = ();  # e.g., $modifier_for{$pkg} = 'silent'

sub MODIFY_CODE_ATTRIBUTES {
    my ( $package, $coderef, @attrs ) = @_;

    my @unused_attrs = ();

    while ( my $attr = shift @attrs ) {
        if ( $attr =~ /^Export_?Lexical$/i ) {
            push @{ $exports_for{$package} }, $coderef;
        }
        else {
            push @unused_attrs, $attr;
        }
    }

    return @unused_attrs;
}

sub import {
    my ($class) = @_;

    my $caller = caller;
    my $key    = _get_key($caller);
    my @params = ();

    {
        # Export our subroutines, if necessary.
        no strict 'refs';   ## no critic (ProhibitNoStrict)

        if ( !exists &{ $caller . '::MODIFY_CODE_ATTRIBUTES' } ) {
            *{ $caller . '::MODIFY_CODE_ATTRIBUTES' } = \&MODIFY_CODE_ATTRIBUTES;
        }

        if ( !exists &{ $caller . '::import' } ) {
            *{ $caller . '::import' } = sub {
                my ( $class, @args ) = @_;

                _export_all_to( $caller, scalar caller );

                $^H{$key} = @args ? ( join ',', @args ) : 1;   ## no critic (ProhibitPunctuationVars, RequireLocalizedPunctuationVars)
            };
        }

        if ( !exists &{ $caller . '::unimport' } ) {
            *{ $caller . '::unimport' } = sub {
                my ( $class, @args ) = @_;

                if ( @args ) {
                    # Leave the '1' on the front of the list from a previous 'use
                    # $module', as well as any subs previously imported.
                    $^H{$key} = join ',', $^H{$key}, map { "!$_" } @args;  ## no critic (ProhibitPunctuationVars, RequireLocalizedPunctuationVars)
                }
                else {
                    $^H{$key} = '';    ## no critic (ProhibitPunctuationVars, RequireLocalizedPunctuationVars)
                }
            };
        }
    }

    while ( my $modifier = shift ) {
        if ( $modifier =~ /^:(silent|warn)$/ ) {
            croak qq('$modifier' requested when '$modifier_for{$caller}' already in use)
                if $modifier_for{$caller};

            $modifier_for{$caller} = $modifier;
            next;
        }

        push @params, $modifier;
    }
}

sub _export_all_to {
    my ( $from, $caller ) = @_;

    return if !exists $exports_for{$from};

    for my $ref ( @{ $exports_for{$from} } ) {
        my $obj = B::svref_2object($ref);
        my $pkg = $obj->GV->STASH->NAME;
        my $sub = $obj->GV->NAME;
        my $key = _get_key($pkg);

        no strict 'refs';       ## no critic (ProhibitNoStrict)
        no warnings 'redefine'; ## no critic (ProhibitNoWarnings)

        next if exists &{ $caller . '::' . $sub };

        *{ $caller . '::' . $sub } = sub {
            my $hints = ( caller 0 )[10];

            return _fail( $pkg, $sub ) if $hints->{$key} =~ /(?:^$)|(?:!$sub\b)/; # no $module
                                                                                  # no $module '$sub'

            goto $ref if $hints->{$key} =~ /(?:^1\b)|(?:\b$sub\b)/;               # use $module
                                                                                  # use $module '$sub'
        };
    }
}

sub _fail {
    my ( $pkg, $sub ) = @_;

    if ( defined $modifier_for{$pkg} ) {
        if ( $modifier_for{$pkg} eq ':silent' ) {
            return;
        }

        if ( $modifier_for{$pkg} eq ':warn' ) {
            carp "$pkg\::$sub not allowed here";
            return;



( run in 0.510 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )