Created
August 27, 2012 14:58
-
-
Save tobyink/3489271 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env perl | |
| # Perl 5 needs a does built-in. | |
| # http://perldoc.perl.org/5.14.2/perltodo.html#A-does()-built-in | |
| # | |
| # In an ideal world the syntax would be `$foo does $bar` but Perl doesn't | |
| # seem able to add infix operators via a module, so `$foo ~~does $bar` is | |
| # needed. (Also in an ideal world it would have the same precedence as `eq`. | |
| # | |
| use 5.014; | |
| package does 0.001 | |
| { | |
| BEGIN { $INC{'does.pm'} = __FILE__ }; | |
| use IO::Detect qw( is_filehandle ); | |
| use overload qw(); | |
| use Scalar::Util qw( blessed reftype ); | |
| use Sub::Exporter -setup => { | |
| exports => [qw( does overloads )], | |
| groups => { | |
| default => [qw( does )], | |
| }, | |
| }; | |
| no warnings; | |
| my %ROLES = ( | |
| SCALAR => sub { reftype($_) eq 'SCALAR' or overloads($_, q[${}]) }, | |
| ARRAY => sub { reftype($_) eq 'ARRAY' or overloads($_, q[@{}]) }, | |
| HASH => sub { reftype($_) eq 'HASH' or overloads($_, q[%{}]) }, | |
| CODE => sub { reftype($_) eq 'CODE' or overloads($_, q[&{}]) }, | |
| REF => sub { reftype($_) eq 'REF' }, | |
| GLOB => sub { reftype($_) eq 'GLOB' or overloads($_, q[*{}]) }, | |
| LVALUE => sub { ref($_) eq 'LVALUE' }, | |
| FORMAT => sub { reftype($_) eq 'FORMAT' }, | |
| IO => \&is_filehandle, | |
| VSTRING => sub { reftype($_) eq 'VSTRING' or reftype($_) eq 'VSTRING' }, | |
| Regexp => sub { reftype($_) eq 'Regexp' or overloads($_, q[qr]) }, | |
| q[${}] => 'SCALAR', | |
| q[@{}] => 'ARRAY', | |
| q[%{}] => 'HASH', | |
| q[&{}] => 'CODE', | |
| q[*{}] => 'GLOB', | |
| q[bool] => sub { !blessed($_) or !overload::Overloaded($_) or overloads($_, q[bool]) }, | |
| q[""] => sub { !ref($_) or !overload::Overloaded($_) or overloads($_, q[""]) }, | |
| q[0+] => sub { !ref($_) or !overload::Overloaded($_) or overloads($_, q[0+]) }, | |
| q[qr] => sub { reftype($_) eq 'Regexp' or overloads($_, q[qr]) }, | |
| q[<>] => sub { overloads($_, q[<>]) or is_filehandle($_) }, | |
| q[~~] => sub { overloads($_, q[~~]) or not blessed($_) }, | |
| ); | |
| while (my ($k, $v) = each %ROLES) | |
| { $ROLES{$k} = $ROLES{$v} unless ref $v } | |
| sub overloads ($;$) | |
| { | |
| my ($thing, $role) = @_; | |
| # curry (kinda) | |
| return sub { overloads(shift, $thing) } if @_ < 2; | |
| goto \&overload::Method; | |
| } | |
| sub does ($;$) | |
| { | |
| my ($thing, $role) = @_; | |
| # curry (kinda) | |
| return sub { does(shift, $thing) } if @_ < 2; | |
| if (my $test = $ROLES{$role}) | |
| { | |
| local $_ = $thing; | |
| my $does = $test->($thing); | |
| return 1 if $does; | |
| } | |
| if (blessed $thing) | |
| { | |
| return $thing->DOES($role); | |
| } | |
| return; | |
| } | |
| } | |
| package main | |
| { | |
| use does; | |
| my $var = []; | |
| # Prefix notation | |
| if (does $var, 'ARRAY') | |
| { | |
| say '$var does ARRAY' | |
| } | |
| # Pseudo-infix notation | |
| if ($var ~~does 'ARRAY') | |
| { | |
| say '$var does ARRAY' | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment