Slides for the talk you-did-what at lpw-2013
-
You
did
WHAT?
-
Written
last year
-
... they
kicked us
out early!
-
Oh well
-
Saves me
writing one
this year
-
You
did
WHAT?
-
  $obj->foo;
-
What's
going
on?
-
Get the
class name
for $obj
-
Lookup 'foo'
via the MRO
-
MRO?
-
Method
resolution
order
-
mro.pm
-
mro::get_linear_isa
-
DFS
C3
-
  $obj->SUPER::foo
-
is actually
-
  $obj->Class::Of::Obj::SUPER::foo
-
Class::Of::Obj::SUPER
-
Reference to
SuperClass::Of::Obj
-
(well, it's
almost that)
-
Wait.
-
SuperClass::Of::Obj::foo
-
Fully
qualified
dispatch
-
  $obj->next::method
-
Always
dispatches
C3
-
So that
is ...
-
  package next;
  sub method {}
-
Oooo.
-
(MRO::Compat
actually does
it that way
for 5.8.x)
-
curry.pm
-
How many
times have
you written
-
  sub {
    $obj->foo(@_)
  }
-
  sub {
    $obj->foo(@args, @_)
  }
-
Well ...
-
  package curry;
  sub AUTOLOAD {
    (my $meth = $AUTOLOAD) =~ s/.*:://;
    my ($obj, @args) = @_;
    sub { $obj->$meth(@args, @_) }
  }
-
  my $cb = $obj->curry::foo;
-
  my $cb = $obj->curry::foo(@args);
-
Worse
still
-
  use Scalar::Util qw(weaken);
  ...
  my $weak_obj = $obj;
  weaken($weak_obj);
  sub {
    $weak_obj->foo(@args, @_)
  }
-
BORING
-
Easy to
fuck up
-
  my $cb = $obj->curry::weak::foo;
-
You can
also
do ...
-
  $obj->$foo
-
What?
-
$foo can be
a method name
or a coderef
-
So ...
-
How many
times have
you written
-
  if (
    blessed($obj)
    and $obj->can('foo')) {
-
Can't use
the curry
trick
-
Can't call method 
"foo" on an
undefined value
-
So, instead ...
-
Safe::Isa
-
  our $_can = sub {
    return unless blessed($_[0]);
    $_[0]->can($_[1]);
  }
-
  our @EXPORT = qw($_can);
-
  use Safe::Isa;
  ...
  if ($obj->$_can('foo')) {
    ...
-
(also provides
$_isa $_does
$_call_if_object)
-
Next!
-
  $obj->$foo
-
  $obj->${\foo()}
-
Huh?
-
foo() can
return a name
or a coderef
-
The ${}
derefs
-
  my $meth = "clear_${thing}";
  $obj->$meth;
-
  $obj->${\"clear_${thing}"};
-
  $obj->${\sub {
    my ($self, ...) = @_;
    ...
  }}
-
Inline
method
calls!
-
So, ok, what's
that going
to help with?
-
Importing ...
-
  sub import {
    ...
    require Foo;
    Foo->import;
  }
-
WRONG
-
import() methods
almost always
use caller()
-
  sub import {
    ...
    require Foo;
    goto &Foo::import;
  }
-
What if
you've got
two things
to import?
-
  sub import {
    ...
    require Foo;
    Foo->export_to_level(1);
  }
-
Only works
for Exporter
using things
-
Worse
still
-
pragmas!
-
strict
warnings
etc.
-
Affect
compilation
scope
-
  sub import {
    ...
    strict->import;
-
Damn
-
Anything that
works for
both?
-
  sub import {
    ...
    my $caller = caller;
    eval qq{
      package ${caller};
      Foo->import;
    }
  }
-
caller
correct
for
exporters
-
compilation
scope
right for
pragmas
-
  sub import {
    ...
    my $caller = caller;
    eval qq{
      package ${caller};
      Foo->import;
    }
  }
-
UGLY
-
Sufficiently
encapsulated
ugly is
indistinguishable
from beautiful
-
  my $importer = eval qq{
    package $target;
    sub {
      my \$m = splice \@_, 1, 1;
      shift->\$m(\@_)
    }
  };
-
  $importer->(import => @args);
-
So ...
-
  sub _importer {
    my $target = shift;
    \($importers{$target} ||= eval qq{
      package $target;
      sub {
        my \$m = splice \@_, 1, 1;
        shift->\$m(\@_)
      };
    } or die "Couldn't build importer for $target: $@")
  }
-
  sub import::into {
    my ($class, $target, @args) = @_;
    $class->${_importer($target)}(
      import => @args
    );
  }
-
Import::Into
-
  use Import::Into;
  sub import {
    my $target = caller;
    ...
    Thing1->import::into($target);
    Thing2->import::into($target, @args);
  }
-
Works for
modules
-
Works for
pragmas
-
(also provides
unimport::out_of)
-
I did
what?
-
Import::Into
Safe::Isa
curry
-
Import::Into
Safe::Isa
curry
(all already
on CPAN)
-
Hopefully
they'll be
useful
-
Sufficiently
encapsulated
insanity ...
-
Thank You
IRC:mst
mst@shadowcat.co.uk
@shadowcat_mst