summaryrefslogtreecommitdiffstats
path: root/lib/Exporter/Lexical.pm
blob: 633da524fa838267b33fca3d9f5c9e6f424e9bca (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package Exporter::Lexical;
use strict;
use warnings;
use 5.018;
# ABSTRACT: exporter for lexical subs

=head1 SYNOPSIS

  package My::Exporter;
  use Exporter::Lexical -exports => [ 'foo' ]
  sub foo { "FOO" }

  package MyApp;

  {
      use My::Exporter;
      warn foo(); # FOO
  }
  warn foo(); # Undefined subroutine &main::foo called

=head1 DESCRIPTION

This module allows you to export lexical subs from your exporter module. It is
implemented using the new C<lexical_subs> feature in perl 5.18, so the
functions truly are lexical (unlike some of the previous attempts).

This module is quite experimental, and may change a lot in the future as I
figure out how it should work. It is very much a proof of concept for the
moment.

=cut

use XSLoader;
XSLoader::load(
    __PACKAGE__,
    # we need to be careful not to touch $VERSION at compile time, otherwise
    # DynaLoader will assume it's set and check against it, which will cause
    # fail when being run in the checkout without dzil having set the actual
    # $VERSION
    exists $Exporter::Lexical::{VERSION}
        ? ${ $Exporter::Lexical::{VERSION} } : (),
);

sub import {
    my $package = shift;
    my %opts = @_;

    my $caller = caller;

    my $import = build_exporter(\%opts, $caller);

    {
        no strict 'refs';
        *{ $caller . '::import' } = $import;
    }
}

sub build_exporter {
    my ($opts, $caller) = @_;
    $caller //= caller;

    return sub {
        my $caller_stash = do {
            no strict 'refs';
            \%{ $caller . '::' };
        };
        my @exports = @{ $opts->{'-exports'} };
        my %exports = map { $_ => \&{ $caller_stash->{$_} } } @exports;

        for my $export (keys %exports) {
            lexical_import($export, $exports{$export});
        }

        # XXX there is a bug with lexical_import where the pad entry sequence
        # numbers are incorrect when used with 'use', so the first statement
        # after the 'use' statement doesn't see the lexical. hack around this
        # for now by injecting a dummy statement right after the 'use'.
        _lex_stuff(";1;");
    };
}

=head1 BUGS

No known bugs.

Please report any bugs through RT: email
C<bug-exporter-lexical at rt.cpan.org>, or browse to
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Exporter-Lexical>.

=head1 SEE ALSO

L<Sub::Exporter::Lexical>

L<Lexical::Import>

L<feature/The 'lexical_subs' feature>

=head1 SUPPORT

You can find this documentation for this module with the perldoc command.

    perldoc Exporter::Lexical

You can also look for information at:

=over 4

=item * MetaCPAN

L<https://metacpan.org/release/Exporter-Lexical>

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Exporter-Lexical>

=item * Github

L<https://github.com/doy/exporter-lexical>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/Exporter-Lexical>

=back

=begin Pod::Coverage

  lexical_import

=end Pod::Coverage

=cut

1;