Make Sub::Exporter an optional dep (which is kinda the whole point)
[p5sagit/Sub-Exporter-Progressive.git] / lib / Sub / Exporter / Progressive.pm
1 package Sub::Exporter::Progressive;
2
3 # ABSTRACT: Only use Sub::Exporter if you need it
4
5 use strict;
6 use warnings;
7
8 # VERSION
9
10 use List::Util 'first';
11
12 sub import {
13    my ($self, @args) = @_;
14
15    my $inner_target = caller(0);
16    my ($TOO_COMPLICATED, $export_data) = sub_export_options(@args);
17
18    if ($TOO_COMPLICATED) {
19       warn <<'WARNING';
20 You are using Sub::Exporter::Progressive, but the features your program uses from
21 Sub::Exporter cannot be implemented without Sub::Exporter, so you might as well
22 just use vanilla Sub::Exporter
23 WARNING
24       require Sub::Exporter;
25       goto \&Sub::Exporter::import;
26    }
27    else {
28       my $full_exporter;
29       no strict;
30       @{"${inner_target}::EXPORT_OK"} = @{$export_data->{exports}};
31       @{"${inner_target}::EXPORT"} = @{$export_data->{defaults}};
32       *{"${inner_target}::import"} = sub {
33          use strict;
34          my ($self, @args) = @_;
35
36          if (first { ref || !m/^\w+$/ } @args) {
37             die 'your usage of Sub::Exporter::Progressive requires Sub::Exporter to be installed'
38                unless eval { require Sub::Exporter };
39             $full_exporter ||=
40                Sub::Exporter::build_exporter($export_data->{original});
41
42             goto $full_exporter;
43          } else {
44             require Exporter;
45             goto \&Exporter::import;
46          }
47       };
48    }
49 }
50
51 sub sub_export_options {
52    my ($setup, $options) = @_;
53
54    my $TOO_COMPLICATED = 0;
55
56    my @exports;
57    my @defaults;
58
59    if ($setup eq '-setup') {
60       my %options = %$options;
61
62       OPTIONS:
63       for my $opt (keys %options) {
64          if ($opt eq 'exports') {
65
66             $TOO_COMPLICATED = 1, last OPTIONS
67                if ref $options{exports} ne 'ARRAY';
68
69             @exports = @{$options{exports}};
70
71             $TOO_COMPLICATED = 1, last OPTIONS
72                if first { ref } @exports;
73
74          } elsif ($opt eq 'groups') {
75
76             $TOO_COMPLICATED = 1, last OPTIONS
77                if first { $_ ne 'default' } keys %{$options{groups}};
78
79             @defaults = @{$options{groups}{default} || [] };
80          } else {
81             $TOO_COMPLICATED = 1;
82             last OPTIONS
83          }
84       }
85       @defaults = @exports if $defaults[0] eq '-all';
86    }
87
88    return $TOO_COMPLICATED, {
89       exports => \@exports,
90       defaults => \@defaults,
91       original => $options,
92    }
93 }
94
95 1;
96
97 =head1 SYNOPSIS
98
99  package Syntax::Keyword::Gather;
100
101  use Sub::Exporter::Progressive -setup => {
102    exports => [qw( break gather gathered take )],
103    groups => {
104      defaults => [qw( break gather gathered take )],
105    },
106  };
107
108  # elsewhere
109
110  # uses Exporter for speed
111  use Syntax::Keyword::Gather;
112
113  # somewhere else
114
115  # uses Sub::Exporter for features
116  use Syntax::Keyword::Gather 'gather', take => { -as => 'grab' };
117
118 =head1 DESCRIPTION
119
120 L<Sub::Exporter> is an incredibly powerful module, but with that power comes
121 great responsibility, er- as well as some runtime penalties.  This module
122 is a C<Sub::Exporter> wrapper that will let your users just use L<Exporter>
123 if all they are doing is picking exports, but use C<Sub::Exporter> if your
124 users try to use C<Sub::Exporter>'s more advanced features features, like
125 renaming exports, if they try to use them.
126
127 Note that this module will export C<@EXPORT> and C<@EXPORT_OK> package
128 variables for C<Exporter> to work.  Additionally, if your package uses advanced
129 C<Sub::Exporter> features like currying, this module will only ever use
130 C<Sub::Exporter>, so you might as well use it directly.