use strict;
use warnings;
package Sub::Exporter::Util;
{
$Sub::Exporter::Util::VERSION = '0.987';
}
# ABSTRACT: utilities to make Sub::Exporter easier
use Data::OptList ();
use Params::Util ();
sub curry_method {
my $override_name = shift;
sub {
my ($class, $name) = @_;
$name = $override_name if defined $override_name;
sub { $class->$name(@_); };
}
}
BEGIN { *curry_class = \&curry_method; }
sub curry_chain {
# In the future, we can make \%arg an optional prepend, like the "special"
# args to the default Sub::Exporter-generated import routine.
my (@opt_list) = @_;
my $pairs = Data::OptList::mkopt(\@opt_list, 'args', 'ARRAY');
sub {
my ($class) = @_;
sub {
my $next = $class;
for my $i (0 .. $#$pairs) {
my $pair = $pairs->[ $i ];
unless (Params::Util::_INVOCANT($next)) { ## no critic Private
my $str = defined $next ? "'$next'" : 'undef';
Carp::croak("can't call $pair->[0] on non-invocant $str")
}
my ($method, $args) = @$pair;
if ($i == $#$pairs) {
return $next->$method($args ? @$args : ());
} else {
$next = $next->$method($args ? @$args : ());
}
}
};
}
}
# =head2 name_map
#
# This utility returns an list to be used in specify export generators. For
# example, the following:
#
# exports => {
# name_map(
# '_?_gen' => [ qw(fee fie) ],
# '_make_?' => [ qw(foo bar) ],
# ),
# }
#
# is equivalent to:
#
# exports => {
# name_map(
# fee => \'_fee_gen',
# fie => \'_fie_gen',
# foo => \'_make_foo',
# bar => \'_make_bar',
# ),
# }
#
# This can save a lot of typing, when providing many exports with similarly-named
# generators.
#
# =cut
#
# sub name_map {
# my (%groups) = @_;
#
# my %map;
#
# while (my ($template, $names) = each %groups) {
# for my $name (@$names) {
# (my $export = $template) =~ s/\?/$name/
# or Carp::croak 'no ? found in name_map template';
#
# $map{ $name } = \$export;
# }
# }
#
# return %map;
# }
sub merge_col {
my (%groups) = @_;
my %merged;
while (my ($default_name, $group) = each %groups) {
while (my ($export_name, $gen) = each %$group) {
$merged{$export_name} = sub {
my ($class, $name, $arg, $col) = @_;
my $merged_arg = exists $col->{$default_name}
? { %{ $col->{$default_name} }, %$arg }
: $arg;
if (Params::Util::_CODELIKE($gen)) { ## no critic Private
$gen->($class, $name, $merged_arg, $col);
} else {
$class->$$gen($name, $merged_arg, $col);
}
}
}
}
return %merged;
}
sub __mixin_class_for {
my ($class, $mix_into) = @_;
require Package::Generator;
my $mixin_class = Package::Generator->new_package({
base => "$class\:\:__mixin__",
});
## no critic (ProhibitNoStrict)
no strict 'refs';
if (ref $mix_into) {
unshift @{"$mixin_class" . "::ISA"}, ref $mix_into;
} else {
unshift @{"$mix_into" . "::ISA"}, $mixin_class;
}
return $mixin_class;
}
sub mixin_installer {
sub {
my ($arg, $to_export) = @_;
my $mixin_class = __mixin_class_for($arg->{class}, $arg->{into});
bless $arg->{into} => $mixin_class if ref $arg->{into};
Sub::Exporter::default_installer(
{ %$arg, into => $mixin_class },
$to_export,
);
};
}
sub mixin_exporter {
Carp::cluck "mixin_exporter is deprecated; use mixin_installer instead; it behaves identically";
return mixin_installer;
}
sub like {
sub {
my ($value, $arg) = @_;
Carp::croak "no regex supplied to regex group generator" unless $value;
# Oh, qr//, how you bother me! See the p5p thread from around now about
# fixing this problem... too bad it won't help me. -- rjbs, 2006-04-25
my @values = eval { $value->isa('Regexp') } ? ($value, undef)
: @$value;
while (my ($re, $opt) = splice @values, 0, 2) {
Carp::croak "given pattern for regex group generater is not a Regexp"
unless eval { $re->isa('Regexp') };
my @exports = keys %{ $arg->{config}->{exports} };
my @matching = grep { $_ =~ $re } @exports;
my %merge = $opt ? %$opt : ();
my $prefix = (delete $merge{-prefix}) || '';
my $suffix = (delete $merge{-suffix}) || '';
for my $name (@matching) {
my $as = $prefix . $name . $suffix;
push @{ $arg->{import_args} }, [ $name => { %merge, -as => $as } ];
}
}
1;
}
}
use Sub::Exporter -setup => {
exports => [ qw(
like
name_map
merge_col
curry_method curry_class
curry_chain
mixin_installer mixin_exporter
) ]
};
1;
__END__
=pod
=head1 NAME
Sub::Exporter::Util - utilities to make Sub::Exporter easier
=head1 VERSION
version 0.987
=head1 DESCRIPTION
This module provides a number of utility functions for performing common or
useful operations when setting up a Sub::Exporter configuration. All of the
utilities may be exported, but none are by default.
=head1 THE UTILITIES
=head2 curry_method
exports => {
some_method => curry_method,
}
This utility returns a generator which will produce an invocant-curried version
of a method. In other words, it will export a method call with the exporting
class built in as the invocant.
A module importing the code some the above example might do this:
use Some::Module qw(some_method);
my $x = some_method;
This would be equivalent to:
use Some::Module;
my $x = Some::Module->some_method;
If Some::Module is subclassed and the subclass's import method is called to
import C