How Importing Works
• the client use-s a module
• the module’s import method is called
How Importing Works
• the client use-s a module
• the module’s import method is called
• something ugly happens
How Importing Works
• the client use-s a module
• the module’s import method is called
• something ugly happens
• the client has more named subs
How Importing Works
• usually that ugliness is Exporter.pm
How Importing Works
• usually that ugliness is Exporter.pm
# the dark and twisted heart of Exporter.pm
*{“${callpkg}::$sym”} = \\&{“${pkg}::$sym”};
*{\"$::$\"} = \\&{\"$::$\"};
• the caller gets the same code
• with the same name
*{\"$::$\"} = \\&{\"$::$\"};
• Exporter.pm churns out identically
named and constructed products.
The Factory Model
The Factory Model
• One size fits all
The Factory Model
• One size fits all
• If it doesn’t fit your code, adjust your
code.
The Factory Model
• One size fits all
• If it doesn’t fit your code, adjust your
code.
• Or abuse the Exporter
The Factory Model
• There’s Only One Way To Do It
The Tool Metaphor
The Tool Metaphor
• “You can’t write good code without
good tools.”
The Tool Metaphor
• “You can’t write good code without
good tools.”
• Exporters are tools for making tools.
The Tool Metaphor
• “You can’t write good code without
good tools.”
• Exporters are tools for making tools.
• Their quality has an impact all the way
down the line.
Craftsman Tools
Craftsman Tools
• We want adaptable tools, customized
for our current needs.
Craftsman Tools
• We want adaptable tools, customized
for our current needs.
• We want tools hand-crafted to our
specifications.
Craftsman Tools
• We want adaptable tools, customized
for our current needs.
• We want tools hand-crafted to our
specifications.
• We want to reduce our labor by having
someone else do the boring work.
Sub::Exporter!
Basic Exporting
The Basics
• String::Truncate
• trunc: truncate a string to length
• elide: truncate, ending in “...”
String::Truncate
String::Truncate
$string = “This string is 34 characters long.”;
String::Truncate
$string = “This string is 34 characters long.”;
trunc($string, 10); # This strin
String::Truncate
$string = “This string is 34 characters long.”;
trunc($string, 10); # This strin
elide($string, 10); # This st...
Basic Exports
To let your client write:
use String::Truncate qw(elide trunc);
Using Exporter.pm
package String::Truncate;
use Exporter;
use vars
qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
@ISA = qw(Exporter);
@EXPORT = qw(trunc);
@EXPORT_OK = qw(elide trunc);
%EXPORT_TAGS = (
all => \\@EXPORT_OK,
basic => [ qw(elide trunc) ],
);
Renaming Exports
Renaming Exports
• avoid namespace collisions
Renaming Exports
use CGI qw(:standard);
use LWP::Simple;
my $head = head(...); # what happens?
Renaming Exports
• avoid unclear or ambiguous names
Renaming Exports
use File::Basename;
use XML::Parser;
my $file = fileparse($ARGV[0]);
$parser->parsefile($file);
Renaming Exports
• “privatize” subs imported to classes
Renaming Exports
package XML::Parser::Hypothetical;
use File::Basename;
Renaming Exports
Using Exporter::Renaming
use Exporter::Renaming;
use String::Truncate
qw(elide),
Renaming => [ trunc => ‘trunc_str’ ];
no Exporter::Renaming;
Renaming Exports
To let your client write:
use String::Truncate
qw(trunc), trunc => { -as => ‘trunc_str’ };
Data::OptList
@optlist = (
qw(aye aye)
love => [ qw(chex) ],
$as_href = die “...”;
love => [ qw(milk) ],
aye => { sir => ‘!’ },
);
Customizing Exports
Subclassed Exporters
Subclassed Exporters
• import is a method
Subclassed Exporters
• import is a method
• that implies that exporters are classes
Subclassed Exporters
• import is a method
• that implies that exporters are classes
• and that we can subclass them
package String::Truncate::Split;
use base qw(String::Truncate);
sub trunc {
my ($string, $length) = @_;
# ...
return ($head, $tail);
}
Subclassed Exporters
Subclassed Exporters
• *{“$::$”} = \\&{“$::$”};
Subclassed Exporters
• *{“$::$”} = \\&{“$::$”};
• @EXPORT has to be defined in the
derived class
Subclassed Exporters
• *{“$::$”} = \\&{“$::$”};
• @EXPORT has to be defined in the
derived class
• the export has to be defined in the
exporting package
package String::Truncate::Split;
use base qw(String::Truncate);
sub trunc {
my ($string, $length) = @_;
# ...
return ($head, $tail);
}
1;
package String::Truncate::Split;
use base qw(String::Truncate);
our @EXPORT_OK = @String::Truncate::EXPORT_OK;
our @EXPORT = @String::Truncate::EXPORT;
our %EXPORT_TAGS
= %String::Truncate::EXPORT_TAGS;
sub trunc {
my ($string, $length) = @_;
# ...
return ($head, $tail);
}
package String::Truncate::Split;
use base qw(String::Truncate);
our @EXPORT_OK = @String::Truncate::EXPORT_OK;
our @EXPORT = @String::Truncate::EXPORT;
our %EXPORT_TAGS
= %String::Truncate::EXPORT_TAGS;
sub trunc {
my ($string, $length) = @_;
# ...
return ($head, $tail);
}
*$_ = \\&{“String::Truncate::$_”}
for grep { not defined &{__PACKAGE__.“::$_”} }
@EXPORT;
package String::Truncate::Split;
use base qw(String::Truncate);
our @EXPORT_OK = @String::Truncate::EXPORT_OK;
our @EXPORT = @String::Truncate::EXPORT;
our %EXPORT_TAGS
= %String::Truncate::EXPORT_TAGS;
sub trunc {
my ($string, $length) = @_;
# ...
return ($head, $tail);
}
do {
no strict ‘refs’;
*$_ = \\&{“String::Truncate::$_”}
for grep { not defined &{__PACKAGE__.“::$_”} }
@EXPORT;
}
Subclassed Exporters
Subclassed Exporters
• Sub::Exporter finds exports with “can”
Subclassed Exporters
• Sub::Exporter finds exports with “can”
• this means you can subclass exporting
toolkits, replacing just pieces
package String::Truncate::Split;
use base qw(String::Truncate);
sub trunc {
my ($string, $length) = @_;
# ...
return ($head, $tail);
}
Customizing Exports
Customizing Exports
• What if you want trunc to work
differently when you use it?
Customizing Exports
• Some modules do this with package
variables.
Package-Level Config
use String::Truncate qw(:all);
$String::Truncate::DEFAULT_LENGTH = 20;
$String::Truncate::DEFAULT_MARKER = “--”;
use Tools::Useful;
Package-Level Config
use String::Truncate ();
use Tools::Useful;
sub trunc {
my ($string, $length) = @_;
$length = 20 if not defined $length;
String::Truncate::trunc($string, $length)
}
Package-Level Config
use String::Truncate ();
use Tools::Useful;
sub trunc {
local $String::Truncate::DEFAULT_LENGTH
= 20;
String::Truncate::trunc(@_);
}
Exports to Order
package String::Truncate;
use Sub::Exporter -setup => {
exports => [ qw(elide trunc) ],
groups => {
basic => [ qw(elide trunc) ],
default => [ qw(trunc) ]
},
};
Exports to Order
package String::Truncate;
use Sub::Exporter -setup => {
exports => [ qw(elide trunc) ],
groups => {
basic => [ qw(elide trunc) ],
default => [ qw(trunc) ]
},
};
Exports to Order
package String::Truncate;
use Sub::Exporter -setup => {
exports => [
elide => undef,
trunc => undef,
],
groups => {
basic => [ qw(elide trunc) ],
default => [ qw(trunc) ]
},
};
Exports to Order
package String::Truncate;
use Sub::Exporter -setup => {
exports => [
elide => \\’_build_elide’,
trunc => \\’_build_trunc’,
],
groups => {
basic => [ qw(elide trunc) ],
default => [ qw(trunc) ]
},
};
Generating Routines
Generating Routines
sub _build_trunc {
Generating Routines
sub _build_trunc {
my ($class, $name, $arg) = @_;
Generating Routines
sub _build_trunc {
my ($class, $name, $arg) = @_;
my $_length = $arg->{length};
Generating Routines
sub _build_trunc {
my ($class, $name, $arg) = @_;
my $_length = $arg->{length};
return sub {
Generating Routines
sub _build_trunc {
my ($class, $name, $arg) = @_;
my $_length = $arg->{length};
return sub {
my ($string, $length, @rest) = @_;
Generating Routines
sub _build_trunc {
my ($class, $name, $arg) = @_;
my $_length = $arg->{length};
return sub {
my ($string, $length, @rest) = @_;
$length = $_length if !defined $length;
Generating Routines
sub _build_trunc {
my ($class, $name, $arg) = @_;
my $_length = $arg->{length};
return sub {
my ($string, $length, @rest) = @_;
$length = $_length if !defined $length;
trunc($string, $length, @rest);
Generating Routines
sub _build_trunc {
my ($class, $name, $arg) = @_;
my $_length = $arg->{length};
return sub {
my ($string, $length, @rest) = @_;
$length = $_length if !defined $length;
trunc($string, $length, @rest);
}
Generating Routines
sub _build_trunc {
my ($class, $name, $arg) = @_;
my $_length = $arg->{length};
return sub {
my ($string, $length, @rest) = @_;
$length = $_length if !defined $length;
trunc($string, $length, @rest);
}
}
Routines ex nihilo
Routines ex nihilo
use Cypher::Trivial qw(cyphers);
Routines ex nihilo
use Cypher::Trivial qw(cyphers);
my ($encyph, $decyph) = cyphers(“secret”);
Routines ex nihilo
use Cypher::Trivial qw(cyphers);
my ($encyph, $decyph) = cyphers(“secret”);
$cyphertext
Routines ex nihilo
use Cypher::Trivial qw(cyphers);
my ($encyph, $decyph) = cyphers(“secret”);
$cyphertext
= $encyph->(“Top secret message.”);
Routines ex nihilo
use Cypher::Trivial qw(cyphers);
my ($encyph, $decyph) = cyphers(“secret”);
$cyphertext
= $encyph->(“Top secret message.”);
sub encypher {
Routines ex nihilo
use Cypher::Trivial qw(cyphers);
my ($encyph, $decyph) = cyphers(“secret”);
$cyphertext
= $encyph->(“Top secret message.”);
sub encypher {
my $text = shift; $encyph->($text);
Routines ex nihilo
use Cypher::Trivial qw(cyphers);
my ($encyph, $decyph) = cyphers(“secret”);
$cyphertext
= $encyph->(“Top secret message.”);
sub encypher {
my $text = shift; $encyph->($text);
}
Routines ex nihilo
Routines ex nihilo
use Cypher::Trivial
Routines ex nihilo
use Cypher::Trivial
encypher => { secret => “secret” };
Routines ex nihilo
use Cypher::Trivial
encypher => { secret => “secret” };
encypher(“Top secret message”);
Routines ex nihilo
sub _build_encypher {
my ($class, $name, $arg) = @_;
my ($enc, $dec) = cyphers($arg->{secret});
return $enc;
}
sub _build_decypher {
my ($class, $name, $arg) = @_;
my ($enc, $dec) = cyphers($arg->{secret});
return $dec;
}
Routines ex nihilo
sub _build_encypher {
my ($class, $name, $arg) = @_;
my ($enc, $dec) = cyphers($arg->{secret});
return $enc;
}
sub _build_decypher {
my ($class, $name, $arg) = @_;
my ($enc, $dec) = cyphers($arg->{secret});
return $dec;
}
Methods & Exporter.pm
package Object::Hybrid;
use Exporter;
@Object::Exporter::ISA = qw(Exporter);
@Object::Exporter::EXPORT_OK = qw(retrieve);
sub retrieve {
my ($class, $id) = @_;
my $row = $class->get_row(id => $id);
bless $row => $class;
}
Methods & Exporter.pm
use Object::Hybrid qw(retrieve);
my $object = retrieve(42);
my $object = retrieve(49);
Methods & Exporter.pm
package Object::Hybrid;
use Exporter;
@Object::Exporter::ISA = qw(Exporter);
@Object::Exporter::EXPORT_OK = qw(object);
sub retrieve {
my ($class, $id) = @_;
my $row = $class->get_row(id => $id);
bless $row => $class;
}
sub object { __PACKAGE__->retrieve(@_) }
Methods & Exporter.pm
use Object::Hybrid qw(object);
my $object = object(42);
my $object = object(49);
Methods & Exporter.pm
use Object::Hybrid;
my $object = Object::Hybrid->object(42);
Methods & Exporter.pm
Methods & Exporter.pm
use Object::Hybrid;
Methods & Exporter.pm
use Object::Hybrid;
use Object::Hybrid::With::Much::Derivation;
Methods & Exporter.pm
use Object::Hybrid;
use Object::Hybrid::With::Much::Derivation;
my $object = Object::Hybrid->retrieve(42);
Methods & Exporter.pm
use Object::Hybrid;
use Object::Hybrid::With::Much::Derivation;
my $object = Object::Hybrid->retrieve(42);
my $thing =
Methods & Exporter.pm
use Object::Hybrid;
use Object::Hybrid::With::Much::Derivation;
my $object = Object::Hybrid->retrieve(42);
my $thing =
Object::Hybrid::With::Much::Derivation
Methods & Exporter.pm
use Object::Hybrid;
use Object::Hybrid::With::Much::Derivation;
my $object = Object::Hybrid->retrieve(42);
my $thing =
Object::Hybrid::With::Much::Derivation
->retrieve(49);
Methods & Exporter.pm
package Object::Hybrid;
use Exporter;
@Object::Exporter::ISA = qw(Exporter);
@Object::Exporter::EXPORT_OK = qw(object);
sub retrieve {
my ($class, $id) = @_;
my $row = $class->get_row(id => $id);
bless $row => $class;
}
sub object { __PACKAGE__->retrieve(@_) }
Currying Methods
use Object::Hybrid qw(object);
use Object::Hybrid::With::Much::Derivation
object => { -as => ‘derived_object’ };
my $object = object(42);
my $thing = derived_object(49);
Currying Methods
use Object::Hybrid qw(object);
my $object = Object::Hybrid->object(49);
Currying Methods
use Sub::Exporter::Util qw(curry_class);
use Sub::Exporter -setup => {
exports => [ object => curry_class(‘new’) ],
}
Exporting Methods
Exporting Methods
• Sometimes you want to export
methods without currying the class.
Exporting Methods
• Sometimes you want to export
methods without currying the class.
• Exporters can serve as method
crafters.
Exporting Methods
package Mixin::Dumper;
use Sub::Exporter -setup => {
exports => [ qw(dump) ],
groups => { default => [ qw(dump) ] },
};
sub dump {
my ($self) = @_;
require Data::Dumper;
Data::Dumper::Dumper($self);
}
Exporting Methods
package Email::Simple::mixin:ReplyText;
use Sub::Exporter -setup => {
exports => [ qw(reply_text) ],
groups => { defaults => [ qw(reply_text) ] },
};
sub reply_text {
my ($self) = @_;
join “\\n”, map “>$_”, split /\\n/, $self->body;
}
Exporting Methods
package Email::Simple::mixin:ReplyText;
use Sub::Exporter -setup => {
into => ‘Email::Simple’,
exports => [ qw(reply_text) ],
groups => { defaults => [ qw(reply_text) ] },
};
sub reply_text {
my ($self) = @_;
join “\\n”, map “>$_”, split /\\n/, $self->body;
}
Exporting Methods
use Email::Simple;
use Email::Simple::mixin::ReplyText;
Exporting Methods
use Email::Simple;
use Email::Simple::mixin::ReplyText;
use Email::Simple::Mock;
use Email::Simple::mixin::ReplyText
{ into => ‘Email::Simple::Mock’ };
Emulating mixin.pm
Emulating mixin.pm
• Don’t import into my namespace...
Emulating mixin.pm
• Don’t import into my namespace...
• ...import to a new namespace...
Emulating mixin.pm
• Don’t import into my namespace...
• ...import to a new namespace...
• ...and add it to my @ISA.
Emulating mixin.pm
Emulating mixin.pm
• This makes it easy to import a chunk of
methods and override just a few...
Emulating mixin.pm
• This makes it easy to import a chunk of
methods and override just a few...
• ...and those few can call SUPER.
Emulating mixin.pm
package Email::Simple::mixin:ReplyText;
use Sub::Exporter -setup => {
into => ‘Email::Simple’,
exports => [ qw(reply_text) ],
groups => { defaults => [ qw(reply_text) ] },
};
sub reply_text {
my ($self) = @_;
join “\\n”, map “>$_”, split /\\n/, $self->body;
}
Emulating mixin.pm
package Email::Simple::mixin:ReplyText;
use Sub::Exporter -setup => {
into => ‘Email::Simple’,
exporter=> mixin_exporter,
exports => [ qw(reply_text) ],
groups => { defaults => [ qw(reply_text) ] },
};
sub reply_text {
my ($self) = @_;
join “\\n”, map “>$_”, split /\\n/, $self->body;
}
Collectors
Collectors
Collectors
• Arguments that don’t export anything.
Collectors
• Arguments that don’t export anything.
• They collect data for generators to
use.
Collectors
sub _validate_defaults {
my ($class, $value, $data) = @_;
return (ref $value eq ‘HASH’);
}
Collectors
Collectors
• Arguments that don’t export.
• They collect data for generators to
use.
• They can validate the collected data.
Collectors
• Arguments that don’t export.
• They collect data for generators to
use.
• They can validate the collected data.
• They can do Almost Anything Else.
Collectors
sub _validate_defaults {
my ($class, $value, $data) = @_;
return (ref $value eq ‘HASH’);
}
Collectors
Collectors
• name - name of the collection
Collectors
• name - name of the collection
• class - invocant of import method
Collectors
• name - name of the collection
• class - invocant of import method
• config - exporter configuration
Collectors
• name - name of the collection
• class - invocant of import method
• config - exporter configuration
• into - the package that’s importing
Collectors
• name - name of the collection
• class - invocant of import method
• config - exporter configuration
• into - the package that’s importing
• import_args - args to import method
Collectors
Collectors
• name - the name of the collection
Collectors
• name - the name of the collection
• class - import’s invocant
Collectors
Collectors
• config - the Sub::Exporter config
Collectors
• config - the Sub::Exporter config
• find out what exports exist
Collectors
• config - the Sub::Exporter config
• find out what exports exist
• validate collection value based on
config
use LWP::Simple “/^is_/”;
is_success($res);
is_failure($res);
use LWP::Simpleton;
use Sub::Exporter -setup => {
collectors => {
like => Sub::Exporter::Util::like
},
};
use LWP::Simple like => qr/^is_/;
is_success($res);
is_failure($res);
use LWP::Simple like => [
qr/^is_/, undef,
qr/^get/, { -prefix => ‘https_’, ssl => 1 }
];
is_success($res);
is_failure($res);
https_get(“https://codesimply.com”)
Collectors
Collectors
• into - the target to which exports go
Collectors
• into - the target to which exports go
• alter the class directly
Collectors
• into - the target to which exports go
• alter the class directly
• particularly useful: @ISA
sub _make_base {
my ($class, $value, $data) = @_;
my $target = $data->{into};
push @{“$target\\::ISA”}, $class;
}
sub _make_base {
my ($class, $value, $data) = @_;
my $target = $data->{into};
push @{“$target\\::ISA”}, $class;
}
use Sub::Exporter -setup => {
collectors => { base => \\’_make_base’ },
};
sub _make_base {
my ($class, $value, $data) = @_;
my $target = $data->{into};
push @{“$target\\::ISA”}, $class;
}
use Sub::Exporter -setup => {
collectors => { base => \\’_make_base’ },
};
use Magic::Superclass -base;
Mixed-in Helpers
sub _build_cplx_method {
my ($mixin) = @_;
sub {
my ($self, $arg) = @_;
$mixin->validate_arg($arg);
$mixin->do_stuff($self, $arg);
return $mixin->analyze($self);
}
}
sub validate_arg {...}
Mixed-in Helpers
package Mixin::Helper::Faster;
use base qw(Mixin::Helper);
sub analyze {
my ($mixin, $object) = @_;
return 1;
}
1;
A Coderef Generator
A Coderef Generator
use String::Truncate ();
A Coderef Generator
use String::Truncate ();
my $trunc;
A Coderef Generator
use String::Truncate ();
my $trunc;
String::Truncate->import(
A Coderef Generator
use String::Truncate ();
my $trunc;
String::Truncate->import(trunc =>
A Coderef Generator
use String::Truncate ();
my $trunc;
String::Truncate->import(trunc => { -as => \\$trunc });
Accessors sans ISA
package YAPC::Slideshow;
use Accessors::Simple -setup => {
fields => [ qw(topic presenter timeslot room) ],
};
Accessors sans ISA
Accessors sans ISA
sub _make_accessor {
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
return $self->{$field};
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
return $self->{$field};
}
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
return $self->{$field};
}
}
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
return $self->{$field};
}
}
sub _make_many_accessors {
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
return $self->{$field};
}
}
sub _make_many_accessors {
my @fields = @{ $arg->{fields} };
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
return $self->{$field};
}
}
sub _make_many_accessors {
my @fields = @{ $arg->{fields} };
my %sub = map { $_ => _make_accessor($_) } @fields;
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
return $self->{$field};
}
}
sub _make_many_accessors {
my @fields = @{ $arg->{fields} };
my %sub = map { $_ => _make_accessor($_) } @fields;
return \\%sub;
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
return $self->{$field};
}
}
sub _make_many_accessors {
my @fields = @{ $arg->{fields} };
my %sub = map { $_ => _make_accessor($_) } @fields;
return \\%sub;
}
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
return $self->{$field};
}
}
sub _make_many_accessors {
my @fields = @{ $arg->{fields} };
my %sub = map { $_ => _make_accessor($_) } @fields;
return \\%sub;
}
use Sub::Exporter -setup =>
Accessors sans ISA
sub _make_accessor {
my ($field) = @_;
sub {
my ($self) = shift;
$self->{field} = shift if @_;
return $self->{$field};
}
}
sub _make_many_accessors {
my @fields = @{ $arg->{fields} };
my %sub = map { $_ => _make_accessor($_) } @fields;
return \\%sub;
}
use Sub::Exporter -setup =>
{ groups => { setup => \\&_make_many_accessors } };
Eat Exporter’s Brain
Eat Exporter’s Brain
sub exporter_upgrade {
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
},
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
},
});
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
},
});
push @{“$new_pkg\\::ISA”}, $class;
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
},
});
push @{“$new_pkg\\::ISA”}, $class;
return $new_pkg;
Eat Exporter’s Brain
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
},
});
push @{“$new_pkg\\::ISA”}, $class;
return $new_pkg;
}
package UNIVERSAL;
package UNIVERSAL;
sub exporter_upgrade {
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
},
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
},
});
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
},
});
push @{“$new_pkg\\::ISA”}, $class;
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
},
});
push @{“$new_pkg\\::ISA”}, $class;
return $new_pkg;
package UNIVERSAL;
sub exporter_upgrade {
my ($pkg) = @_;
my $new_pkg = “$pkg\\::SE”;
return $new_pkg if $new_pkg->isa($pkg);
Sub::Exporter::setup_exporter({
as => ‘import’,
into => $new_pkg,
exports => [ @{“$pkg\\::EXPORT_OK”} ],
groups => {
%{“$pkg\\::EXPORT_TAGS”},
default => [ @{“$pkg\\::EXPORTS”} ],
},
});
push @{“$new_pkg\\::ISA”}, $class;
return $new_pkg;
}
Fixing caller
Fixing caller
sub default_exporter {
Fixing caller
sub default_exporter {
my ($class, $gen, $name, $arg, $col, $as, $into)
Fixing caller
sub default_exporter {
my ($class, $gen, $name, $arg, $col, $as, $into)
= @_;
Fixing caller
sub default_exporter {
my ($class, $gen, $name, $arg, $col, $as, $into)
= @_;
_install(
Everybody knows about Exporter.pm: you use it, and more
Everybody knows about Exporter.pm: you use it, and if someone uses your module, they don't have to type quite as much. We'll look at how the Exporter works, and how it fails to take advantage of the powerful concepts on which it's built. We'll see how you can provide flexible import routines that allow your module's user to type even less and get code that behaves much more like part of his own program. You can avoid repeating unnecessary parameters to every overly-generic routine and can avoid collision-prone global configuration. All of this is made possible -- and easy -- by Sub::Exporter.
Generators -- routines that build routines -- can produce customized code, built to each importer's specifications. Sub::Exporter lets you build and provide customized routines easily. You'll learn how to write generators, and how to use them with Sub::Exporter . In its simplest form, it's as easy to use as Exporter.pm. With just a bit more configuration, it can build, group, rename, and julienne routines easily. With this tool, you'll be able to provide interfaces that are both simpler and more powerful than those provided by the stock Exporter. less
0 comments
Post a comment