1 package MooseX::MultiMethods;
3 # ABSTRACT: Multi Method Dispatch based on Moose type constraints
7 use MooseX::Method::Signatures;
8 use Sub::Install qw/install_sub/;
9 use MooseX::Types::Moose qw/HashRef ClassName/;
10 use aliased 'Devel::Declare::Context::Simple' => 'DDContext';
11 use aliased 'MooseX::MultiMethods::Meta::Method' => 'MetaMethod';
13 use namespace::autoclean;
20 builder => '_build_dd_context',
24 has _dd_init_args => (
27 default => sub { {} },
36 method BUILD ($args) {
37 $self->_dd_init_args($args);
40 method _build_dd_context {
41 return DDContext->new(%{ $self->_dd_init_args });
44 method import (ClassName $class:) {
45 my $setup_class = caller;
46 $class->setup_for($setup_class);
49 method setup_for (ClassName $class: ClassName $setup_class, HashRef $args = {}) {
50 Devel::Declare->setup_for($setup_class, {
53 my $self = $class->new({ class => $setup_class, %{ $args } });
66 MooseX::Method::Signatures->setup_for($setup_class)
67 unless $setup_class->can('method');
71 $self->skip_declarator;
74 my $thing = $self->strip_name;
75 confess "expected 'method', got '${thing}'"
76 unless $thing eq 'method';
80 my $name = $self->strip_name;
81 confess "anonymous multi methods not allowed"
82 unless defined $name && length $name;
84 my $proto = $self->strip_proto || '';
85 my $proto_variant = MooseX::Method::Signatures::Meta::Method->wrap(
86 signature => "(${proto})",
87 package_name => $self->get_curstash_name,
91 $self->inject_if_block($self->scope_injector_call . $proto_variant->injectable_code, 'sub');
93 my $meta = Class::MOP::class_of($self->class);
94 my $meta_method = $meta->get_method($name);
95 unless ($meta_method) {
96 $meta_method = MetaMethod->new(
98 package_name => $self->class,
100 $meta->add_method($name => $meta_method);
103 confess "method '${name}' is already defined"
104 unless $meta_method->isa(MetaMethod);
107 my $variant = $proto_variant->reify(actual_body => $_[0]);
108 $meta_method->add_variant($variant->type_constraint => $variant);
119 MooseX::MultiMethods - Multi Method Dispatch based on Moose type constraints
127 package Paper; use Moose;
128 package Scissors; use Moose;
129 package Rock; use Moose;
130 package Lizard; use Moose;
131 package Spock; use Moose;
135 use MooseX::MultiMethods;
137 multi method play (Paper $x, Rock $y) { 1 }
138 multi method play (Paper $x, Spock $y) { 1 }
139 multi method play (Scissors $x, Paper $y) { 1 }
140 multi method play (Scissors $x, Lizard $y) { 1 }
141 multi method play (Rock $x, Scissors $y) { 1 }
142 multi method play (Rock $x, Lizard $y) { 1 }
143 multi method play (Lizard $x, Paper $y) { 1 }
144 multi method play (Lizard $x, Spock $y) { 1 }
145 multi method play (Spock $x, Rock $y) { 1 }
146 multi method play (Spock $x, Scissors $y) { 1 }
147 multi method play (Any $x, Any $y) { 0 }
149 my $game = Game->new;
150 $game->play(Paper->new, Rock->new); # 1, Paper covers Rock
151 $game->play(Spock->new, Paper->new); # 0, Paper disproves Spock
152 $game->play(Spock->new, Scissors->new); # 1, Spock smashes Scissors
156 This module provides multi method dispatch based on Moose type constraints. It
157 does so by providing a C<multi> keyword that extends the C<method> keyword
158 provided by L<MooseX::Method::Signatures|MooseX::Method::Signatures>.
160 When invoking a method declared as C<multi> a matching variant is being
161 searched in all the declared multi variants based on the passed parameters and
162 the declared type constraints. If a variant has been found, it will be invoked.
163 If no variant could be found, an exception will be thrown.
167 Florian Ragwitz <rafl@debian.org>
169 =head1 COPYRIGHT AND LICENSE
171 This software is copyright (c) 2010 by Florian Ragwitz.
173 This is free software; you can redistribute it and/or modify it under
174 the same terms as the Perl 5 programming language system itself.