371
Sub::Exporter Crafting Custom Interfaces

Crafting Custom Interfaces with Sub::Exporter

Embed Size (px)

DESCRIPTION

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.

Citation preview

Page 1: Crafting Custom Interfaces with Sub::Exporter

Sub::ExporterCrafting Custom Interfaces

Page 2: Crafting Custom Interfaces with Sub::Exporter

[email protected] SIGNES

Page 3: Crafting Custom Interfaces with Sub::Exporter

What’s an Exporter?

•Something that takes care of the annoying details of importing.

Page 4: Crafting Custom Interfaces with Sub::Exporter

What is Importing?

Page 5: Crafting Custom Interfaces with Sub::Exporter

What is Importing?

•Build it over there, then bring it here.

Page 6: Crafting Custom Interfaces with Sub::Exporter

What is Importing?

•Build it over there, then bring it here.

•For our purposes, “it” is code.

Page 7: Crafting Custom Interfaces with Sub::Exporter

Why Do We Import?

Page 8: Crafting Custom Interfaces with Sub::Exporter

Why Do We Import?

•We want someone else to do the hard, boring work.

Page 9: Crafting Custom Interfaces with Sub::Exporter

Why Do We Import?

•We want someone else to do the hard, boring work.

•And we want it done cheap.

Page 10: Crafting Custom Interfaces with Sub::Exporter

sub strftime { my($pkg,$fmt,$time); ($pkg,$fmt,$time,$tzname) = @_;

my $me = ref($pkg) ? $pkg : bless [];

if(defined $tzname) { $tzname = uc $tzname;

$tzname = sprintf(“%+05d”,$tzname) unless($tzname =~ /\D/);

$epoch = timegm(@{$time}[0..5]);

@$me = gmtime($epoch + tz_offset($tzname) - tz_offset()); } else { @$me = @$time; undef $epoch; }

_subs($me,$fmt); }

Page 11: Crafting Custom Interfaces with Sub::Exporter

Date::Format::strftime

Page 12: Crafting Custom Interfaces with Sub::Exporter

strftime

Page 13: Crafting Custom Interfaces with Sub::Exporter

How Importing Works

Page 14: Crafting Custom Interfaces with Sub::Exporter

How Importing Works

•the client use-s a module

Page 15: Crafting Custom Interfaces with Sub::Exporter

How Importing Works

•the client use-s a module

• the module’s import method is called

Page 16: Crafting Custom Interfaces with Sub::Exporter

How Importing Works

•the client use-s a module

• the module’s import method is called

• something ugly happens

Page 17: Crafting Custom Interfaces with Sub::Exporter

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

Page 18: Crafting Custom Interfaces with Sub::Exporter

How Importing Works

•usually that ugliness is Exporter.pm

Page 19: Crafting Custom Interfaces with Sub::Exporter

How Importing Works

•usually that ugliness is Exporter.pm

# the dark and twisted heart of Exporter.pm *{“${callpkg}::$sym”} = \&{“${pkg}::$sym”};

Page 20: Crafting Custom Interfaces with Sub::Exporter

*{"$::$"} = \&{"$::$"};

•the caller gets the same code

•with the same name

Page 21: Crafting Custom Interfaces with Sub::Exporter

*{"$::$"} = \&{"$::$"};

•Exporter.pm churns out identically named and constructed products.

Page 22: Crafting Custom Interfaces with Sub::Exporter

The Factory Model

Page 23: Crafting Custom Interfaces with Sub::Exporter

The Factory Model

•One size fits all

Page 24: Crafting Custom Interfaces with Sub::Exporter

The Factory Model

•One size fits all

• If it doesn’t fit your code, adjust your code.

Page 25: Crafting Custom Interfaces with Sub::Exporter

The Factory Model

•One size fits all

• If it doesn’t fit your code, adjust your code.

•Or abuse the Exporter

Page 26: Crafting Custom Interfaces with Sub::Exporter

The Factory Model

•There’s Only One Way To Do It

Page 27: Crafting Custom Interfaces with Sub::Exporter

The Tool Metaphor

Page 28: Crafting Custom Interfaces with Sub::Exporter

The Tool Metaphor

•“You can’t write good code without good tools.”

Page 29: Crafting Custom Interfaces with Sub::Exporter

The Tool Metaphor

•“You can’t write good code without good tools.”

•Exporters are tools for making tools.

Page 30: Crafting Custom Interfaces with Sub::Exporter

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.

Page 31: Crafting Custom Interfaces with Sub::Exporter

Craftsman Tools

Page 32: Crafting Custom Interfaces with Sub::Exporter

Craftsman Tools

•We want adaptable tools, customized for our current needs.

Page 33: Crafting Custom Interfaces with Sub::Exporter

Craftsman Tools

•We want adaptable tools, customized for our current needs.

•We want tools hand-crafted to our specifications.

Page 34: Crafting Custom Interfaces with Sub::Exporter

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.

Page 35: Crafting Custom Interfaces with Sub::Exporter

Sub::Exporter!

Page 36: Crafting Custom Interfaces with Sub::Exporter

Basic Exporting

Page 37: Crafting Custom Interfaces with Sub::Exporter

The Basics

•String::Truncate

• trunc: truncate a string to length

•elide: truncate, ending in “...”

Page 38: Crafting Custom Interfaces with Sub::Exporter

String::Truncate

Page 39: Crafting Custom Interfaces with Sub::Exporter

String::Truncate

$string = “This string is 34 characters long.”;

Page 40: Crafting Custom Interfaces with Sub::Exporter

String::Truncate

$string = “This string is 34 characters long.”;

trunc($string, 10); # This strin

Page 41: Crafting Custom Interfaces with Sub::Exporter

String::Truncate

$string = “This string is 34 characters long.”;

trunc($string, 10); # This strin

elide($string, 10); # This st...

Page 42: Crafting Custom Interfaces with Sub::Exporter

Basic Exports

use String::Truncate qw(elide trunc);

To let your client write:

Page 43: Crafting Custom Interfaces with Sub::Exporter

Basic Exports

package String::Truncate;

use Sub::Exporter -setup => { exports => [ qw(elide trunc) ], };

Page 44: Crafting Custom Interfaces with Sub::Exporter

Basic Groups

use String::Truncate qw(:all)

To let your client write:

Page 45: Crafting Custom Interfaces with Sub::Exporter

Basic Groups

package String::Truncate;

use Sub::Exporter -setup => { exports => [ qw(elide trunc) ], };

Page 46: Crafting Custom Interfaces with Sub::Exporter

Basic Groups

package String::Truncate; use Sub::Exporter -setup => { exports => [ qw(elide trunc) ], groups => { all => [qw(elide trunc)] }, };

Page 47: Crafting Custom Interfaces with Sub::Exporter

Basic Groups

use String::Truncate qw(:basic)

To let your client write:

Page 48: Crafting Custom Interfaces with Sub::Exporter

Basic Groups

package String::Truncate; use Sub::Exporter -setup => { exports => [ qw(elide trunc) ], groups => { basic => [qw(elide trunc)] } };

Page 49: Crafting Custom Interfaces with Sub::Exporter

Basic Defaults

use String::Truncate; # imports “trunc”

To let your client write:

Page 50: Crafting Custom Interfaces with Sub::Exporter

Basic Defaults

package String::Truncate; use Sub::Exporter -setup => { exports => [ qw(elide trunc) ], groups => { basic => [ qw(elide trunc) ], default => [ qw(trunc) ] }, };

Page 51: Crafting Custom Interfaces with Sub::Exporter

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) ], );

Using Exporter.pm

Page 52: Crafting Custom Interfaces with Sub::Exporter

Renaming Exports

Page 53: Crafting Custom Interfaces with Sub::Exporter

Renaming Exports

•avoid namespace collisions

Page 54: Crafting Custom Interfaces with Sub::Exporter

Renaming Exports

use CGI qw(:standard); use LWP::Simple;

my $head = head(...); # what happens?

Page 55: Crafting Custom Interfaces with Sub::Exporter

Renaming Exports

•avoid unclear or ambiguous names

Page 56: Crafting Custom Interfaces with Sub::Exporter

Renaming Exports

use File::Basename; use XML::Parser;

my $file = fileparse($ARGV[0]);

$parser->parsefile($file);

Page 57: Crafting Custom Interfaces with Sub::Exporter

Renaming Exports

•“privatize” subs imported to classes

Page 58: Crafting Custom Interfaces with Sub::Exporter

Renaming Exports

package XML::Parser::Hypothetical; use File::Basename;

Page 59: Crafting Custom Interfaces with Sub::Exporter

Renaming Exports

use Exporter::Renaming; use String::Truncate qw(elide), Renaming => [ trunc => ‘trunc_str’ ]; no Exporter::Renaming;

Using Exporter::Renaming

Page 60: Crafting Custom Interfaces with Sub::Exporter

Renaming Exports

use String::Truncate qw(trunc), trunc => { -as => ‘trunc_str’ };

To let your client write:

Page 61: Crafting Custom Interfaces with Sub::Exporter

Renaming Exports

package String::Truncate; use Sub::Exporter -setup => { exports => [ qw(elide trunc) ], groups => { basic => [ qw(elide trunc) ], default => [ qw(trunc) ] }, };

Page 62: Crafting Custom Interfaces with Sub::Exporter

Wait a second...

use String::Truncate qw(trunc), trunc => { -as => ‘trunc_str’ };

Page 63: Crafting Custom Interfaces with Sub::Exporter

Data::OptListQuick and Dirty Data Structures

Page 64: Crafting Custom Interfaces with Sub::Exporter

Data::OptList

@optlist = ( qw(alfa bravo), charlie => [ 0, 1, 2 ], delta => { a => 1 }, ‘echo’, foxtrox => undef, ‘gulf’,

);

Page 65: Crafting Custom Interfaces with Sub::Exporter

Data::OptList

@optlist = ( qw(alfa bravo), charlie => [ 0, 1, 2 ], delta => { a => 1 }, ‘echo’, foxtrox => undef, ‘gulf’,

);

$as_href = { alfa => undef, bravo => undef, charlie => [ 0, 1, 2], delta => { a => 1 }, echo => undef, foxtrot => undef, gulf => undef, ];

Page 66: Crafting Custom Interfaces with Sub::Exporter

Data::OptList

@optlist = ( qw(alfa bravo), charlie => [ 0, 1, 2 ], delta => { a => 1 }, ‘echo’, foxtrox => undef, ‘gulf’,

);

$as_aref = [ [ alfa => undef ], [ bravo => undef ], [ charlie => [0,1,2] ], [ delta => {a => 1}], [ echo => undef ], [ foxtrot => undef ], [ gulf => undef ], ];

Page 67: Crafting Custom Interfaces with Sub::Exporter

Data::OptList

@optlist = ( qw(aye aye) love => [ qw(chex) ], love => [ qw(milk) ], aye => { sir => ‘!’ }, );

Page 68: Crafting Custom Interfaces with Sub::Exporter

Data::OptList

@optlist = ( qw(aye aye) love => [ qw(chex) ], love => [ qw(milk) ], aye => { sir => ‘!’ }, );

$as_aref = [ [ aye => undef ], [ aye => undef ], [ love => [qw(chex)] ], [ love => [qw(milk)] ], [ aye => {sir => ‘!’}] ];

Page 69: Crafting Custom Interfaces with Sub::Exporter

Data::OptList

$as_href = die “...”;

@optlist = ( qw(aye aye) love => [ qw(chex) ], love => [ qw(milk) ], aye => { sir => ‘!’ }, );

Page 70: Crafting Custom Interfaces with Sub::Exporter

Customizing Exports

Page 71: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

Page 72: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

• import is a method

Page 73: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

• import is a method

• that implies that exporters are classes

Page 74: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

• import is a method

• that implies that exporters are classes

•and that we can subclass them

Page 75: Crafting Custom Interfaces with Sub::Exporter

package String::Truncate::Split; use base qw(String::Truncate);

sub trunc { my ($string, $length) = @_;

# ...

return ($head, $tail); }

Page 76: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

Page 77: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

• *{“$::$”} = \&{“$::$”};

Page 78: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

• *{“$::$”} = \&{“$::$”};

• @EXPORT has to be defined in the derived class

Page 79: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

• *{“$::$”} = \&{“$::$”};

• @EXPORT has to be defined in the derived class

• the export has to be defined in the exporting package

Page 80: Crafting Custom Interfaces with Sub::Exporter

package String::Truncate::Split; use base qw(String::Truncate);

sub trunc { my ($string, $length) = @_;

# ...

return ($head, $tail); }

1;

Page 81: Crafting Custom Interfaces with Sub::Exporter

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); }

Page 82: Crafting Custom Interfaces with Sub::Exporter

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;

Page 83: Crafting Custom Interfaces with Sub::Exporter

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; }

Page 84: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

Page 85: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

•Sub::Exporter finds exports with “can”

Page 86: Crafting Custom Interfaces with Sub::Exporter

Subclassed Exporters

•Sub::Exporter finds exports with “can”

• this means you can subclass exporting toolkits, replacing just pieces

Page 87: Crafting Custom Interfaces with Sub::Exporter

package String::Truncate::Split; use base qw(String::Truncate);

sub trunc { my ($string, $length) = @_;

# ...

return ($head, $tail); }

Page 88: Crafting Custom Interfaces with Sub::Exporter

Customizing Exports

Page 89: Crafting Custom Interfaces with Sub::Exporter

Customizing Exports

•What if you want trunc to work differently when you use it?

Page 90: Crafting Custom Interfaces with Sub::Exporter

Customizing Exports

•Some modules do this with package variables.

Page 91: Crafting Custom Interfaces with Sub::Exporter

Package-Level Config

use String::Truncate qw(:all); $String::Truncate::DEFAULT_LENGTH = 20; $String::Truncate::DEFAULT_MARKER = “--”;

Page 92: Crafting Custom Interfaces with Sub::Exporter

Package-Level Config

use String::Truncate qw(:all); $String::Truncate::DEFAULT_LENGTH = 20; $String::Truncate::DEFAULT_MARKER = “--”;

use Tools::Useful;

Page 93: Crafting Custom Interfaces with Sub::Exporter

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) }

Page 94: Crafting Custom Interfaces with Sub::Exporter

Package-Level Config

use String::Truncate (); use Tools::Useful;

sub trunc { local $String::Truncate::DEFAULT_LENGTH = 20; String::Truncate::trunc(@_); }

Page 95: Crafting Custom Interfaces with Sub::Exporter

Custom Imports

use String::Truncate qw(trunc), elide => { -as => ‘trail_off’, marker => ‘etc’, };

Page 96: Crafting Custom Interfaces with Sub::Exporter

Custom Imports

use String::Truncate qw(trunc elide), elide => { -as => ‘trail_off’, marker => ‘etc’, };

Page 97: Crafting Custom Interfaces with Sub::Exporter

Custom Imports

use String::Truncate trunc => { -as => ‘trunc_str’, length => 10 }, elide => { -as => ‘elide_str’, length => 10 };

Page 98: Crafting Custom Interfaces with Sub::Exporter

Custom Imports

use String::Truncate -all => { -suffix => ‘_str’, length => 10 };

Page 99: Crafting Custom Interfaces with Sub::Exporter

Exports to Order

package String::Truncate; use Sub::Exporter -setup => { exports => [ qw(elide trunc) ], groups => { basic => [ qw(elide trunc) ], default => [ qw(trunc) ] }, };

Page 100: Crafting Custom Interfaces with Sub::Exporter

Exports to Order

package String::Truncate; use Sub::Exporter -setup => { exports => [ qw(elide trunc) ], groups => { basic => [ qw(elide trunc) ], default => [ qw(trunc) ] }, };

Page 101: Crafting Custom Interfaces with Sub::Exporter

Exports to Order package String::Truncate; use Sub::Exporter -setup => { exports => [ elide => undef, trunc => undef, ], groups => { basic => [ qw(elide trunc) ], default => [ qw(trunc) ] }, };

Page 102: Crafting Custom Interfaces with Sub::Exporter

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) ] }, };

Page 103: Crafting Custom Interfaces with Sub::Exporter

Generating Routines

Page 104: Crafting Custom Interfaces with Sub::Exporter

Generating Routines

sub _build_trunc {

Page 105: Crafting Custom Interfaces with Sub::Exporter

Generating Routines

sub _build_trunc { my ($class, $name, $arg) = @_;

Page 106: Crafting Custom Interfaces with Sub::Exporter

Generating Routines

sub _build_trunc { my ($class, $name, $arg) = @_; my $_length = $arg->{length};

Page 107: Crafting Custom Interfaces with Sub::Exporter

Generating Routines

sub _build_trunc { my ($class, $name, $arg) = @_; my $_length = $arg->{length};

return sub {

Page 108: Crafting Custom Interfaces with Sub::Exporter

Generating Routines

sub _build_trunc { my ($class, $name, $arg) = @_; my $_length = $arg->{length};

return sub { my ($string, $length, @rest) = @_;

Page 109: Crafting Custom Interfaces with Sub::Exporter

Generating Routines

sub _build_trunc { my ($class, $name, $arg) = @_; my $_length = $arg->{length};

return sub { my ($string, $length, @rest) = @_; $length = $_length if !defined $length;

Page 110: Crafting Custom Interfaces with Sub::Exporter

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);

Page 111: Crafting Custom Interfaces with Sub::Exporter

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); }

Page 112: Crafting Custom Interfaces with Sub::Exporter

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); } }

Page 113: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

Page 114: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

use Cypher::Trivial qw(cyphers);

Page 115: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

use Cypher::Trivial qw(cyphers);

my ($encyph, $decyph) = cyphers(“secret”);

Page 116: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

use Cypher::Trivial qw(cyphers);

my ($encyph, $decyph) = cyphers(“secret”);

$cyphertext

Page 117: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

use Cypher::Trivial qw(cyphers);

my ($encyph, $decyph) = cyphers(“secret”);

$cyphertext = $encyph->(“Top secret message.”);

Page 118: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

use Cypher::Trivial qw(cyphers);

my ($encyph, $decyph) = cyphers(“secret”);

$cyphertext = $encyph->(“Top secret message.”);

sub encypher {

Page 119: Crafting Custom Interfaces with Sub::Exporter

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);

Page 120: Crafting Custom Interfaces with Sub::Exporter

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); }

Page 121: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

Page 122: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

use Cypher::Trivial

Page 123: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

use Cypher::Trivial encypher => { secret => “secret” };

Page 124: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

use Cypher::Trivial encypher => { secret => “secret” };

encypher(“Top secret message”);

Page 125: Crafting Custom Interfaces with Sub::Exporter

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; }

Page 126: Crafting Custom Interfaces with Sub::Exporter

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; }

Page 127: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo package Cypher::Trivial; use Sub::Exporter -setup => { exports => [ encypher => \’_build_encypher’, decypher => \’_build_decypher’, cyphers => undef, ], groups => { cyphers => [ qw(encypher decypher) ], } };

Page 128: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

use Cypher::Trivial encypher => { secret => “secret” };

encypher(“Top secret message”);

Page 129: Crafting Custom Interfaces with Sub::Exporter

Routines ex nihilo

use Cypher::Trivial -cyphers => { secret => “secret” };

encypher(“Top secret message”); decypher(“Gbc frperg zrffntr”);

Page 130: Crafting Custom Interfaces with Sub::Exporter

Generating Groups package Cypher::Trivial; use Sub::Exporter -setup => { exports => [ encypher => \’_build_encypher’, decypher => \’_build_decypher’, cyphers => undef, ], groups => { cyphers => [ qw(encypher decypher) ], } };

Page 131: Crafting Custom Interfaces with Sub::Exporter

Generating Groups 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; }

Page 132: Crafting Custom Interfaces with Sub::Exporter

Generating Groups package Cypher::Trivial; use Sub::Exporter -setup => { exports => [ encypher => \’_build_encypher’, decypher => \’_build_decypher’, cyphers => undef, ], groups => { cyphers => \’_build_cyphers’, } };

Page 133: Crafting Custom Interfaces with Sub::Exporter

Generating Groups

Page 134: Crafting Custom Interfaces with Sub::Exporter

Generating Groups

sub _build_cyphers {

Page 135: Crafting Custom Interfaces with Sub::Exporter

Generating Groups

sub _build_cyphers { my ($class, $name, $arg) = @_;

Page 136: Crafting Custom Interfaces with Sub::Exporter

Generating Groups

sub _build_cyphers { my ($class, $name, $arg) = @_;

my %sub;

Page 137: Crafting Custom Interfaces with Sub::Exporter

Generating Groups

sub _build_cyphers { my ($class, $name, $arg) = @_;

my %sub; @sub{qw(encypher decypher)}

Page 138: Crafting Custom Interfaces with Sub::Exporter

Generating Groups

sub _build_cyphers { my ($class, $name, $arg) = @_;

my %sub; @sub{qw(encypher decypher)} = cyphers($arg->{secret});

Page 139: Crafting Custom Interfaces with Sub::Exporter

Generating Groups

sub _build_cyphers { my ($class, $name, $arg) = @_;

my %sub; @sub{qw(encypher decypher)} = cyphers($arg->{secret});

return \%sub;

Page 140: Crafting Custom Interfaces with Sub::Exporter

Generating Groups

sub _build_cyphers { my ($class, $name, $arg) = @_;

my %sub; @sub{qw(encypher decypher)} = cyphers($arg->{secret});

return \%sub; }

Page 141: Crafting Custom Interfaces with Sub::Exporter

Generating Groups

use Cypher::Trivial -cyphers => { secret => “secret” };

Page 142: Crafting Custom Interfaces with Sub::Exporter

Generating Groups

use Cypher::Trivial -cyphers => { secret => “secret” },

-cyphers => { secret => ‘Secret1234’, -suffix => ‘_strong’ } ;

Page 143: Crafting Custom Interfaces with Sub::Exporter

Exporting Methods

Page 144: Crafting Custom Interfaces with Sub::Exporter

ZOMG O NO!

Page 145: Crafting Custom Interfaces with Sub::Exporter

Methods & Exporter.pm

Page 146: Crafting Custom Interfaces with Sub::Exporter

Methods & Exporter.pm

•Exporter.pm: “Do not export method names!”

Page 147: Crafting Custom Interfaces with Sub::Exporter

Methods & Exporter.pm

•Exporter.pm: “Do not export method names!”

• *{“$::$”} = \&{“$::$”};

Page 148: Crafting Custom Interfaces with Sub::Exporter

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

Page 149: Crafting Custom Interfaces with Sub::Exporter

use Object::Hybrid qw(retrieve);

my $object = retrieve(42); my $object = retrieve(49);

Methods & Exporter.pm

Page 150: Crafting Custom Interfaces with Sub::Exporter

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

Page 151: Crafting Custom Interfaces with Sub::Exporter

use Object::Hybrid qw(object);

my $object = object(42); my $object = object(49);

Methods & Exporter.pm

Page 152: Crafting Custom Interfaces with Sub::Exporter

use Object::Hybrid;

my $object = Object::Hybrid->object(42);

Methods & Exporter.pm

Page 153: Crafting Custom Interfaces with Sub::Exporter

Methods & Exporter.pm

Page 154: Crafting Custom Interfaces with Sub::Exporter

use Object::Hybrid;

Methods & Exporter.pm

Page 155: Crafting Custom Interfaces with Sub::Exporter

use Object::Hybrid; use Object::Hybrid::With::Much::Derivation;

Methods & Exporter.pm

Page 156: Crafting Custom Interfaces with Sub::Exporter

use Object::Hybrid; use Object::Hybrid::With::Much::Derivation;

my $object = Object::Hybrid->retrieve(42);

Methods & Exporter.pm

Page 157: Crafting Custom Interfaces with Sub::Exporter

use Object::Hybrid; use Object::Hybrid::With::Much::Derivation;

my $object = Object::Hybrid->retrieve(42);

my $thing =

Methods & Exporter.pm

Page 158: Crafting Custom Interfaces with Sub::Exporter

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

Page 159: Crafting Custom Interfaces with Sub::Exporter

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

Page 160: Crafting Custom Interfaces with Sub::Exporter

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

Page 161: Crafting Custom Interfaces with Sub::Exporter

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);

Page 162: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

use Object::Hybrid qw(object);

my $object = Object::Hybrid->object(49);

Page 163: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

Page 164: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

Page 165: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

use Sub::Exporter -setup => {

Page 166: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

use Sub::Exporter -setup => { exports => [ object => \&_build_object ],

Page 167: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

use Sub::Exporter -setup => { exports => [ object => \&_build_object ], };

Page 168: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

use Sub::Exporter -setup => { exports => [ object => \&_build_object ], };

sub _build_object {

Page 169: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

use Sub::Exporter -setup => { exports => [ object => \&_build_object ], };

sub _build_object { my ($class, $name, $arg) = @_;

Page 170: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

use Sub::Exporter -setup => { exports => [ object => \&_build_object ], };

sub _build_object { my ($class, $name, $arg) = @_;

return sub { $class->new(@_); }

Page 171: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

use Sub::Exporter -setup => { exports => [ object => \&_build_object ], };

sub _build_object { my ($class, $name, $arg) = @_;

return sub { $class->new(@_); } }

Page 172: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

use Sub::Exporter -setup => { exports => [ object => curry_class(‘new’) ], }

Page 173: Crafting Custom Interfaces with Sub::Exporter

Currying Methods

use Sub::Exporter::Util qw(curry_class); use Sub::Exporter -setup => { exports => [ object => curry_class(‘new’) ], }

Page 174: Crafting Custom Interfaces with Sub::Exporter

Exporting Methods

Page 175: Crafting Custom Interfaces with Sub::Exporter

Exporting Methods

•Sometimes you want to export methods without currying the class.

Page 176: Crafting Custom Interfaces with Sub::Exporter

Exporting Methods

•Sometimes you want to export methods without currying the class.

•Exporters can serve as method crafters.

Page 177: Crafting Custom Interfaces with Sub::Exporter

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); }

Page 178: Crafting Custom Interfaces with Sub::Exporter

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; }

Page 179: Crafting Custom Interfaces with Sub::Exporter

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; }

Page 180: Crafting Custom Interfaces with Sub::Exporter

Exporting Methods

use Email::Simple; use Email::Simple::mixin::ReplyText;

Page 181: Crafting Custom Interfaces with Sub::Exporter

Exporting Methods

use Email::Simple; use Email::Simple::mixin::ReplyText;

use Email::Simple::Mock; use Email::Simple::mixin::ReplyText { into => ‘Email::Simple::Mock’ };

Page 182: Crafting Custom Interfaces with Sub::Exporter

Emulating mixin.pm

Page 183: Crafting Custom Interfaces with Sub::Exporter

Emulating mixin.pm

•Don’t import into my namespace...

Page 184: Crafting Custom Interfaces with Sub::Exporter

Emulating mixin.pm

•Don’t import into my namespace...

• ...import to a new namespace...

Page 185: Crafting Custom Interfaces with Sub::Exporter

Emulating mixin.pm

•Don’t import into my namespace...

• ...import to a new namespace...

• ...and add it to my @ISA.

Page 186: Crafting Custom Interfaces with Sub::Exporter

Emulating mixin.pm

Page 187: Crafting Custom Interfaces with Sub::Exporter

Emulating mixin.pm

•This makes it easy to import a chunk of methods and override just a few...

Page 188: Crafting Custom Interfaces with Sub::Exporter

Emulating mixin.pm

•This makes it easy to import a chunk of methods and override just a few...

• ...and those few can call SUPER.

Page 189: Crafting Custom Interfaces with Sub::Exporter

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; }

Page 190: Crafting Custom Interfaces with Sub::Exporter

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; }

Page 191: Crafting Custom Interfaces with Sub::Exporter

Collectors

Page 192: Crafting Custom Interfaces with Sub::Exporter

Collectors

Page 193: Crafting Custom Interfaces with Sub::Exporter

Collectors

•Arguments that don’t export anything.

Page 194: Crafting Custom Interfaces with Sub::Exporter

Collectors

•Arguments that don’t export anything.

•They collect data for generators to use.

Page 195: Crafting Custom Interfaces with Sub::Exporter

Collectors

package String::Truncate; use Sub::Exporter -setup => { exports => [ elide => \’_build_elide’, trunc => \’_build_trunc’, ], collectors => [ qw(defaults) ], };

Page 196: Crafting Custom Interfaces with Sub::Exporter

Collectors

Page 197: Crafting Custom Interfaces with Sub::Exporter

Collectors

use String::Truncate

Page 198: Crafting Custom Interfaces with Sub::Exporter

Collectors

use String::Truncate defaults => { length => 10 },

Page 199: Crafting Custom Interfaces with Sub::Exporter

Collectors

use String::Truncate defaults => { length => 10 },

qw(-all),

Page 200: Crafting Custom Interfaces with Sub::Exporter

Collectors

use String::Truncate defaults => { length => 10 },

qw(-all), trunc => { length => 1, -as => ‘onechar’ },

Page 201: Crafting Custom Interfaces with Sub::Exporter

Collectors

use String::Truncate defaults => { length => 10 },

qw(-all), trunc => { length => 1, -as => ‘onechar’ }, elide => { marker => ‘&c’, -as => ‘yul’ },

Page 202: Crafting Custom Interfaces with Sub::Exporter

Collectors

use String::Truncate defaults => { length => 10 },

qw(-all), trunc => { length => 1, -as => ‘onechar’ }, elide => { marker => ‘&c’, -as => ‘yul’ }, ;

Page 203: Crafting Custom Interfaces with Sub::Exporter

Collectors

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); } }

Page 204: Crafting Custom Interfaces with Sub::Exporter

Collectors

sub _build_trunc { my ($class, $name, $arg, $col) = @_; my $_length = $arg->{length};

return sub { my ($string, $length, @rest) = @_; $length = $_length if !defined $length; trunc($string, $length, @rest); } }

Page 205: Crafting Custom Interfaces with Sub::Exporter

Collectors sub _build_trunc { my ($class, $name, $arg, $col) = @_; my $_length = $arg->{length};

$_length = $col->{defaults}{length} if !defined $_length;

return sub { my ($string, $length, @rest) = @_; $length = $_length if !defined $length; trunc($string, $length, @rest); } }

Page 206: Crafting Custom Interfaces with Sub::Exporter

Collectors

Page 207: Crafting Custom Interfaces with Sub::Exporter

Collectors

•Arguments that don’t export.

•They collect data for generators to use.

Page 208: Crafting Custom Interfaces with Sub::Exporter

Collectors

•Arguments that don’t export.

•They collect data for generators to use.

•They can validate the collected data.

Page 209: Crafting Custom Interfaces with Sub::Exporter

Collectors

package String::Truncate; use Sub::Exporter -setup => { exports => [ elide => \’_build_elide’, trunc => \’_build_trunc’, ], collectors => { defaults => \’_validate_defaults’, }, };

Page 210: Crafting Custom Interfaces with Sub::Exporter

Collectors

sub _validate_defaults { my ($class, $value, $data) = @_; return (ref $value eq ‘HASH’); }

Page 211: Crafting Custom Interfaces with Sub::Exporter

Collectors

Page 212: Crafting Custom Interfaces with Sub::Exporter

Collectors

•Arguments that don’t export.

•They collect data for generators to use.

•They can validate the collected data.

Page 213: Crafting Custom Interfaces with Sub::Exporter

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.

Page 214: Crafting Custom Interfaces with Sub::Exporter

Collectors

sub _validate_defaults { my ($class, $value, $data) = @_; return (ref $value eq ‘HASH’); }

Page 215: Crafting Custom Interfaces with Sub::Exporter

Collectors

Page 216: Crafting Custom Interfaces with Sub::Exporter

Collectors

•name - name of the collection

Page 217: Crafting Custom Interfaces with Sub::Exporter

Collectors

•name - name of the collection

•class - invocant of import method

Page 218: Crafting Custom Interfaces with Sub::Exporter

Collectors

•name - name of the collection

•class - invocant of import method

•config - exporter configuration

Page 219: Crafting Custom Interfaces with Sub::Exporter

Collectors

•name - name of the collection

•class - invocant of import method

•config - exporter configuration

• into - the package that’s importing

Page 220: Crafting Custom Interfaces with Sub::Exporter

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

Page 221: Crafting Custom Interfaces with Sub::Exporter

Collectors

Page 222: Crafting Custom Interfaces with Sub::Exporter

Collectors

•name - the name of the collection

Page 223: Crafting Custom Interfaces with Sub::Exporter

Collectors

•name - the name of the collection

•class - import’s invocant

Page 224: Crafting Custom Interfaces with Sub::Exporter

Collectors

Page 225: Crafting Custom Interfaces with Sub::Exporter

Collectors

•config - the Sub::Exporter config

Page 226: Crafting Custom Interfaces with Sub::Exporter

Collectors

•config - the Sub::Exporter config

• find out what exports exist

Page 227: Crafting Custom Interfaces with Sub::Exporter

Collectors

•config - the Sub::Exporter config

• find out what exports exist

• validate collection value based on config

Page 228: Crafting Custom Interfaces with Sub::Exporter

use LWP::Simple “/^is_/”;

is_success($res); is_failure($res);

Page 229: Crafting Custom Interfaces with Sub::Exporter

use LWP::Simpleton;

use Sub::Exporter -setup => { collectors => { like => Sub::Exporter::Util::like }, };

Page 230: Crafting Custom Interfaces with Sub::Exporter

use LWP::Simple like => qr/^is_/;

is_success($res); is_failure($res);

Page 231: Crafting Custom Interfaces with Sub::Exporter

use LWP::Simple like => [ qr/^is_/, undef, qr/^get/, { -prefix => ‘https_’, ssl => 1 } ];

is_success($res); is_failure($res);

https_get(“https://codesimply.com”)

Page 232: Crafting Custom Interfaces with Sub::Exporter

Collectors

Page 233: Crafting Custom Interfaces with Sub::Exporter

Collectors

• into - the target to which exports go

Page 234: Crafting Custom Interfaces with Sub::Exporter

Collectors

• into - the target to which exports go

•alter the class directly

Page 235: Crafting Custom Interfaces with Sub::Exporter

Collectors

• into - the target to which exports go

•alter the class directly

•particularly useful: @ISA

Page 236: Crafting Custom Interfaces with Sub::Exporter
Page 237: Crafting Custom Interfaces with Sub::Exporter

sub _make_base { my ($class, $value, $data) = @_;

my $target = $data->{into}; push @{“$target\::ISA”}, $class; }

Page 238: Crafting Custom Interfaces with Sub::Exporter

sub _make_base { my ($class, $value, $data) = @_;

my $target = $data->{into}; push @{“$target\::ISA”}, $class; }

use Sub::Exporter -setup => { collectors => { base => \’_make_base’ }, };

Page 239: Crafting Custom Interfaces with Sub::Exporter

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;

Page 240: Crafting Custom Interfaces with Sub::Exporter
Page 241: Crafting Custom Interfaces with Sub::Exporter

package Email::Constants;

sub _set_constants { my ($class, $value, $data) = @_;

Package::Generator->assign_symbols( $data->{into}, [ EX_TEMPFAIL => 75, FORMATS => [ qw(Maildir mbox mh) ], ], ); }

Page 242: Crafting Custom Interfaces with Sub::Exporter

package Email::Constants;

sub _set_constants { my ($class, $value, $data) = @_;

Package::Generator->assign_symbols( $data->{into}, [ EX_TEMPFAIL => 75, FORMATS => [ qw(Maildir mbox mh) ], ], ); }

use Sub::Exporter -setup => { collectors => { constants => \’_set_constants’ }, };

Page 243: Crafting Custom Interfaces with Sub::Exporter

use Email::Constants qw(constants);

Page 244: Crafting Custom Interfaces with Sub::Exporter

Collectors

Page 245: Crafting Custom Interfaces with Sub::Exporter

Collectors

• import_args - the arguments to import

Page 246: Crafting Custom Interfaces with Sub::Exporter

Collectors

• import_args - the arguments to import

• rewrite the arguments list

Page 247: Crafting Custom Interfaces with Sub::Exporter

Collectors

• import_args - the arguments to import

• rewrite the arguments list

• add new imports

Page 248: Crafting Custom Interfaces with Sub::Exporter
Page 249: Crafting Custom Interfaces with Sub::Exporter

sub _setup {

Page 250: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

Page 251: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) {

Page 252: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} },

Page 253: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, %$value } ];

Page 254: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, %$value } ]; return 1;

Page 255: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, %$value } ]; return 1;

} elsif (ref $value eq ‘ARRAY’) {

Page 256: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, %$value } ]; return 1;

} elsif (ref $value eq ‘ARRAY’) { push @{ $data->{import_args} },

Page 257: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, %$value } ]; return 1;

} elsif (ref $value eq ‘ARRAY’) { push @{ $data->{import_args} }, [ _import => {

Page 258: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, %$value } ]; return 1;

} elsif (ref $value eq ‘ARRAY’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, exports => $value } ];

Page 259: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, %$value } ]; return 1;

} elsif (ref $value eq ‘ARRAY’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, exports => $value } ]; return 1;

Page 260: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, %$value } ]; return 1;

} elsif (ref $value eq ‘ARRAY’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, exports => $value } ]; return 1; }

Page 261: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, %$value } ]; return 1;

} elsif (ref $value eq ‘ARRAY’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, exports => $value } ]; return 1; } return;

Page 262: Crafting Custom Interfaces with Sub::Exporter

sub _setup { my ($class, $value, $data) = @_;

if (ref $value eq ‘HASH’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, %$value } ]; return 1;

} elsif (ref $value eq ‘ARRAY’) { push @{ $data->{import_args} }, [ _import => { -as => ‘import’, exports => $value } ]; return 1; } return; }

Page 263: Crafting Custom Interfaces with Sub::Exporter
Page 264: Crafting Custom Interfaces with Sub::Exporter

use Sub::Exporter -setup => {

Page 265: Crafting Custom Interfaces with Sub::Exporter

use Sub::Exporter -setup => { collectors => { -setup => \’_setup’ },

Page 266: Crafting Custom Interfaces with Sub::Exporter

use Sub::Exporter -setup => { collectors => { -setup => \’_setup’ }, exports => [ _import => \’_build_import’ ],

Page 267: Crafting Custom Interfaces with Sub::Exporter

use Sub::Exporter -setup => { collectors => { -setup => \’_setup’ }, exports => [ _import => \’_build_import’ ], });

Page 268: Crafting Custom Interfaces with Sub::Exporter

-setup => { into_level => 2, exports => [qw(foo)] }

Page 269: Crafting Custom Interfaces with Sub::Exporter

-setup => { into_level => 2, exports => [qw(foo)] }

_import => { -as => ‘import’, into_level => 2, exports => [qw(foo)] }

Page 270: Crafting Custom Interfaces with Sub::Exporter

-setup => [ qw(foo bar baz) ]

Page 271: Crafting Custom Interfaces with Sub::Exporter

-setup => [ qw(foo bar baz) ]

_import => { -as => ‘import’, exports => [qw(foo bar baz)] }

Page 272: Crafting Custom Interfaces with Sub::Exporter

use Sub::Exporter -setup => { collectors => { -setup => \’_setup’ }, exports => [ _import => \’_build_import’ ], });

Page 273: Crafting Custom Interfaces with Sub::Exporter

use Sub::Exporter -setup => { collectors => { -setup => \’_setup’ }, exports => [ _import => sub { my ($class, $name, $arg) = @_; build_exporter($arg); }, ], });

Page 274: Crafting Custom Interfaces with Sub::Exporter

package Sub::Exporter;

use Sub::Exporter -setup => { collectors => { -setup => \&_setup }, exports => [ _import => sub { my ($class, $name, $arg) = @_; build_exporter($arg); }, ], });

Page 275: Crafting Custom Interfaces with Sub::Exporter

RJBS’s Advice

Page 276: Crafting Custom Interfaces with Sub::Exporter

RJBS’s Advice

•Write the client code first.

Page 277: Crafting Custom Interfaces with Sub::Exporter

RJBS’s Advice

•Write the client code first.

•Make as many assumptions as possible.

Page 278: Crafting Custom Interfaces with Sub::Exporter

RJBS’s Advice

•Write the client code first.

•Make as many assumptions as possible.

• Let most of them be refuted.

Page 279: Crafting Custom Interfaces with Sub::Exporter

Any Questions?

Page 280: Crafting Custom Interfaces with Sub::Exporter

Random Tricks

Page 281: Crafting Custom Interfaces with Sub::Exporter

Mixed-in Helpers

$object->complex_method($arg);

Page 282: Crafting Custom Interfaces with Sub::Exporter

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 {...}

Page 283: Crafting Custom Interfaces with Sub::Exporter

Mixed-in Helpers

package Mixin::Helper;

use Sub::Exporter -setup => { exports => [ complex_method => \’_build_cplx_method’, ],};

sub _build_cplx_method { ...

Page 284: Crafting Custom Interfaces with Sub::Exporter

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 {...}

Page 285: Crafting Custom Interfaces with Sub::Exporter

Mixed-in Helpers

package Mixin::Helper::Faster;use base qw(Mixin::Helper);

sub analyze { my ($mixin, $object) = @_; return 1;}

1;

Page 286: Crafting Custom Interfaces with Sub::Exporter

A Coderef Generator

Page 287: Crafting Custom Interfaces with Sub::Exporter

A Coderef Generator

use String::Truncate ();

Page 288: Crafting Custom Interfaces with Sub::Exporter

A Coderef Generator

use String::Truncate ();

my $trunc;

Page 289: Crafting Custom Interfaces with Sub::Exporter

A Coderef Generator

use String::Truncate ();

my $trunc; String::Truncate->import(

Page 290: Crafting Custom Interfaces with Sub::Exporter

A Coderef Generator

use String::Truncate ();

my $trunc; String::Truncate->import(trunc =>

Page 291: Crafting Custom Interfaces with Sub::Exporter

A Coderef Generator

use String::Truncate ();

my $trunc; String::Truncate->import(trunc => { -as => \$trunc });

Page 292: Crafting Custom Interfaces with Sub::Exporter

package YAPC::Slideshow; use Accessors::Simple -setup => { fields => [ qw(topic presenter timeslot room) ], };

Accessors sans ISA

Page 293: Crafting Custom Interfaces with Sub::Exporter

Accessors sans ISA

Page 294: Crafting Custom Interfaces with Sub::Exporter

sub _make_accessor {

Accessors sans ISA

Page 295: Crafting Custom Interfaces with Sub::Exporter

sub _make_accessor { my ($field) = @_;

Accessors sans ISA

Page 296: Crafting Custom Interfaces with Sub::Exporter

sub _make_accessor { my ($field) = @_; sub {

Accessors sans ISA

Page 297: Crafting Custom Interfaces with Sub::Exporter

sub _make_accessor { my ($field) = @_; sub { my ($self) = shift;

Accessors sans ISA

Page 298: Crafting Custom Interfaces with Sub::Exporter

sub _make_accessor { my ($field) = @_; sub { my ($self) = shift; $self->{field} = shift if @_;

Accessors sans ISA

Page 299: Crafting Custom Interfaces with Sub::Exporter

sub _make_accessor { my ($field) = @_; sub { my ($self) = shift; $self->{field} = shift if @_; return $self->{$field};

Accessors sans ISA

Page 300: Crafting Custom Interfaces with Sub::Exporter

sub _make_accessor { my ($field) = @_; sub { my ($self) = shift; $self->{field} = shift if @_; return $self->{$field}; }

Accessors sans ISA

Page 301: Crafting Custom Interfaces with Sub::Exporter

sub _make_accessor { my ($field) = @_; sub { my ($self) = shift; $self->{field} = shift if @_; return $self->{$field}; } }

Accessors sans ISA

Page 302: Crafting Custom Interfaces with Sub::Exporter

sub _make_accessor { my ($field) = @_; sub { my ($self) = shift; $self->{field} = shift if @_; return $self->{$field}; } }

sub _make_many_accessors {

Accessors sans ISA

Page 303: Crafting Custom Interfaces with Sub::Exporter

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

Page 304: Crafting Custom Interfaces with Sub::Exporter

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

Page 305: Crafting Custom Interfaces with Sub::Exporter

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

Page 306: Crafting Custom Interfaces with Sub::Exporter

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

Page 307: Crafting Custom Interfaces with Sub::Exporter

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

Page 308: Crafting Custom Interfaces with Sub::Exporter

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 } };

Accessors sans ISA

Page 309: Crafting Custom Interfaces with Sub::Exporter

Eat Exporter’s Brain

Page 310: Crafting Custom Interfaces with Sub::Exporter

sub exporter_upgrade {

Eat Exporter’s Brain

Page 311: Crafting Custom Interfaces with Sub::Exporter

sub exporter_upgrade { my ($pkg) = @_;

Eat Exporter’s Brain

Page 312: Crafting Custom Interfaces with Sub::Exporter

sub exporter_upgrade { my ($pkg) = @_; my $new_pkg = “$pkg\::SE”;

Eat Exporter’s Brain

Page 313: Crafting Custom Interfaces with Sub::Exporter

sub exporter_upgrade { my ($pkg) = @_; my $new_pkg = “$pkg\::SE”;

Sub::Exporter::setup_exporter({

Eat Exporter’s Brain

Page 314: Crafting Custom Interfaces with Sub::Exporter

sub exporter_upgrade { my ($pkg) = @_; my $new_pkg = “$pkg\::SE”;

Sub::Exporter::setup_exporter({ as => ‘import’,

Eat Exporter’s Brain

Page 315: Crafting Custom Interfaces with Sub::Exporter

sub exporter_upgrade { my ($pkg) = @_; my $new_pkg = “$pkg\::SE”;

Sub::Exporter::setup_exporter({ as => ‘import’, into => $new_pkg,

Eat Exporter’s Brain

Page 316: Crafting Custom Interfaces with Sub::Exporter

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

Page 317: Crafting Custom Interfaces with Sub::Exporter

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

Page 318: Crafting Custom Interfaces with Sub::Exporter

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

Page 319: Crafting Custom Interfaces with Sub::Exporter

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

Page 320: Crafting Custom Interfaces with Sub::Exporter

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

Page 321: Crafting Custom Interfaces with Sub::Exporter

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

Page 322: Crafting Custom Interfaces with Sub::Exporter

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

Page 323: Crafting Custom Interfaces with Sub::Exporter

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

Page 324: Crafting Custom Interfaces with Sub::Exporter

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

Page 325: Crafting Custom Interfaces with Sub::Exporter
Page 326: Crafting Custom Interfaces with Sub::Exporter

package UNIVERSAL;

Page 327: Crafting Custom Interfaces with Sub::Exporter

package UNIVERSAL;

sub exporter_upgrade {

Page 328: Crafting Custom Interfaces with Sub::Exporter

package UNIVERSAL;

sub exporter_upgrade { my ($pkg) = @_;

Page 329: Crafting Custom Interfaces with Sub::Exporter

package UNIVERSAL;

sub exporter_upgrade { my ($pkg) = @_; my $new_pkg = “$pkg\::SE”;

Page 330: Crafting Custom Interfaces with Sub::Exporter

package UNIVERSAL;

sub exporter_upgrade { my ($pkg) = @_; my $new_pkg = “$pkg\::SE”;

return $new_pkg if $new_pkg->isa($pkg);

Page 331: Crafting Custom Interfaces with Sub::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({

Page 332: Crafting Custom Interfaces with Sub::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’,

Page 333: Crafting Custom Interfaces with Sub::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’, into => $new_pkg,

Page 334: Crafting Custom Interfaces with Sub::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’, into => $new_pkg, exports => [ @{“$pkg\::EXPORT_OK”} ],

Page 335: Crafting Custom Interfaces with Sub::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’, into => $new_pkg, exports => [ @{“$pkg\::EXPORT_OK”} ], groups => {

Page 336: Crafting Custom Interfaces with Sub::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’, into => $new_pkg, exports => [ @{“$pkg\::EXPORT_OK”} ], groups => { %{“$pkg\::EXPORT_TAGS”},

Page 337: Crafting Custom Interfaces with Sub::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’, into => $new_pkg, exports => [ @{“$pkg\::EXPORT_OK”} ], groups => { %{“$pkg\::EXPORT_TAGS”}, default => [ @{“$pkg\::EXPORTS”} ],

Page 338: Crafting Custom Interfaces with Sub::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’, into => $new_pkg, exports => [ @{“$pkg\::EXPORT_OK”} ], groups => { %{“$pkg\::EXPORT_TAGS”}, default => [ @{“$pkg\::EXPORTS”} ], },

Page 339: Crafting Custom Interfaces with Sub::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’, into => $new_pkg, exports => [ @{“$pkg\::EXPORT_OK”} ], groups => { %{“$pkg\::EXPORT_TAGS”}, default => [ @{“$pkg\::EXPORTS”} ], }, });

Page 340: Crafting Custom Interfaces with Sub::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’, into => $new_pkg, exports => [ @{“$pkg\::EXPORT_OK”} ], groups => { %{“$pkg\::EXPORT_TAGS”}, default => [ @{“$pkg\::EXPORTS”} ], }, });

push @{“$new_pkg\::ISA”}, $class;

Page 341: Crafting Custom Interfaces with Sub::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’, into => $new_pkg, exports => [ @{“$pkg\::EXPORT_OK”} ], groups => { %{“$pkg\::EXPORT_TAGS”}, default => [ @{“$pkg\::EXPORTS”} ], }, });

push @{“$new_pkg\::ISA”}, $class; return $new_pkg;

Page 342: Crafting Custom Interfaces with Sub::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’, into => $new_pkg, exports => [ @{“$pkg\::EXPORT_OK”} ], groups => { %{“$pkg\::EXPORT_TAGS”}, default => [ @{“$pkg\::EXPORTS”} ], }, });

push @{“$new_pkg\::ISA”}, $class; return $new_pkg; }

Page 343: Crafting Custom Interfaces with Sub::Exporter

Fixing caller

Page 344: Crafting Custom Interfaces with Sub::Exporter

Fixing caller

sub default_exporter {

Page 345: Crafting Custom Interfaces with Sub::Exporter

Fixing caller

sub default_exporter { my ($class, $gen, $name, $arg, $col, $as, $into)

Page 346: Crafting Custom Interfaces with Sub::Exporter

Fixing caller

sub default_exporter { my ($class, $gen, $name, $arg, $col, $as, $into) = @_;

Page 347: Crafting Custom Interfaces with Sub::Exporter

Fixing caller

sub default_exporter { my ($class, $gen, $name, $arg, $col, $as, $into) = @_;

_install(

Page 348: Crafting Custom Interfaces with Sub::Exporter

Fixing caller

sub default_exporter { my ($class, $gen, $name, $arg, $col, $as, $into) = @_;

_install( _generate($class, $generator, $name, $arg, $col),

Page 349: Crafting Custom Interfaces with Sub::Exporter

Fixing caller

sub default_exporter { my ($class, $gen, $name, $arg, $col, $as, $into) = @_;

_install( _generate($class, $generator, $name, $arg, $col), $into,

Page 350: Crafting Custom Interfaces with Sub::Exporter

Fixing caller

sub default_exporter { my ($class, $gen, $name, $arg, $col, $as, $into) = @_;

_install( _generate($class, $generator, $name, $arg, $col), $into, $as,

Page 351: Crafting Custom Interfaces with Sub::Exporter

Fixing caller

sub default_exporter { my ($class, $gen, $name, $arg, $col, $as, $into) = @_;

_install( _generate($class, $generator, $name, $arg, $col), $into, $as, );

Page 352: Crafting Custom Interfaces with Sub::Exporter

Fixing caller

sub default_exporter { my ($class, $gen, $name, $arg, $col, $as, $into) = @_;

_install( _generate($class, $generator, $name, $arg, $col), $into, $as, ); }

Page 353: Crafting Custom Interfaces with Sub::Exporter
Page 354: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED!

Page 355: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into)

Page 356: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_;

Page 357: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_;

Page 358: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do {

Page 359: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out;

Page 360: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/;

Page 361: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/; $g = “package $into;\n$g”;

Page 362: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/; $g = “package $into;\n$g”; eval $g;

Page 363: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/; $g = “package $into;\n$g”; eval $g; \&{“$into\::_generate”};

Page 364: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/; $g = “package $into;\n$g”; eval $g; \&{“$into\::_generate”}; };

Page 365: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/; $g = “package $into;\n$g”; eval $g; \&{“$into\::_generate”}; };

_install(

Page 366: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/; $g = “package $into;\n$g”; eval $g; \&{“$into\::_generate”}; };

_install( $col->{_g}($class, $generator, $name, $arg, $col),

Page 367: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/; $g = “package $into;\n$g”; eval $g; \&{“$into\::_generate”}; };

_install( $col->{_g}($class, $generator, $name, $arg, $col), $into,

Page 368: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/; $g = “package $into;\n$g”; eval $g; \&{“$into\::_generate”}; };

_install( $col->{_g}($class, $generator, $name, $arg, $col), $into, $as,

Page 369: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/; $g = “package $into;\n$g”; eval $g; \&{“$into\::_generate”}; };

_install( $col->{_g}($class, $generator, $name, $arg, $col), $into, $as, );

Page 370: Crafting Custom Interfaces with Sub::Exporter

sub evil_eval_exporter { # TOTALLY UNTESTED! my ($class, $gen, $name, $arg, $col, $as, $into) = @_; $col->{_g} ||= do { my $g = Dump(\&_generate)->Names(‘GEN’)->Out; $g =~ s/\A\$GEN = sub/sub _generate/; $g = “package $into;\n$g”; eval $g; \&{“$into\::_generate”}; };

_install( $col->{_g}($class, $generator, $name, $arg, $col), $into, $as, ); }

Page 371: Crafting Custom Interfaces with Sub::Exporter

Thank You!