File Coverage

blib/lib/Sub/Multi/Tiny/Dispatcher/TypeParams.pm
Criterion Covered Total %
statement 58 58 100.0
branch 8 10 80.0
condition 3 3 100.0
subroutine 13 13 100.0
pod 1 1 100.0
total 83 85 97.6


line stmt bran cond sub pod time code
1             package Sub::Multi::Tiny::Dispatcher::TypeParams;
2              
3 5     5   854 use 5.006;
  5         26  
4 5     5   25 use strict;
  5         9  
  5         82  
5 5     5   34 use warnings;
  5         10  
  5         165  
6              
7 5     5   401 use parent 'Exporter';
  5         243  
  5         30  
8 5     5   298 use vars::i '@EXPORT' => qw(MakeDispatcher);
  5         15  
  5         46  
9              
10 5     5   1902 use Guard;
  5         1507  
  5         225  
11 5     5   29 use Import::Into;
  5         9  
  5         130  
12 5         253 use Sub::Multi::Tiny::Util qw(_hlog _line_mark_string _make_positional_copier
13 5     5   23 _complete_dispatcher);
  5         10  
14 5     5   2502 use Type::Params qw(multisig);
  5         468259  
  5         45  
15 5     5   1261 use Type::Tiny ();
  5         11  
  5         1597  
16              
17             our $VERSION = '0.000010'; # TRIAL
18              
19             # Documentation {{{1
20              
21             =head1 NAME
22              
23             Sub::Multi::Tiny::Dispatcher::TypeParams - Dispatcher-maker using Type::Params for Sub::Multi::Tiny
24              
25             =head1 SYNOPSIS
26              
27             # In a multisub
28             require Sub::Multi::Tiny qw($param D:TypeParams);
29              
30             # Internals of Sub::Multi::Tiny
31             use Type::Params;
32             my $dispatcher_coderef =
33             Sub::Multi::Tiny::Dispatcher::TypeParams::MakeDispatcher({impls=>[]...});
34              
35             This module dispatches to any function that can be distinguished by the
36             C<multisig> function in L<Type::Params>. See
37             L<Type::Params/MULTIPLE SIGNATURES>.
38              
39             See L<Sub::Multi::Tiny> for more about the usage of this module.
40             This module does not export any symbols.
41              
42             =head1 USAGE NOTES
43              
44             =head2 Candidate order
45              
46             The candidates must be listed with more
47             specific first, since they are tried top to bottom. For example, constraint
48             L<Types::Standard/Str> matches any scalar (as of Types::Standard v1.004004), so
49             it should be listed after more specific constraints such as
50             L<Types::Standard/Int>.
51              
52             =head2 Named parameters
53              
54             C<Type::Parameters::multisig()> does not directly support named parameters.
55             Instead, use a slurpy hash (C<Dict>) parameter to collect named parameters.
56             An example is given in L<Type::Params/Mixed Positional and Named Parameters>.
57              
58             =head1 FUNCTIONS
59              
60             =cut
61              
62             # }}}1
63              
64             =head2 MakeDispatcher
65              
66             Make the default dispatcher for the given multi. See L</SYNOPSIS>.
67              
68             =cut
69              
70             # uniquify constraint names
71             my $_constraint_idx = 0;
72              
73             # Our own "any" type
74             my $_any_type = Type::Tiny->new(name => 'Any_SMTD_TypeParams');
75             # Default constraint accepts anything
76              
77             sub MakeDispatcher {
78 7     7 1 14 my $hr = shift; # Has possible_params and impls arrayrefs
79 7         13 my $code = '';
80 7     7   37 _hlog { require Data::Dumper;
81 7         54 "Making Type::Params dispatcher for: ",
82 7         46 Data::Dumper->Dump([$hr], ['multisub']) };
83              
84             # Make an array of typechecks for multisig()
85 7         47 my (@sigs, @impls, @copiers);
86 7         16 foreach my $impl (@{$hr->{impls}}) {
  7         24  
87 16         28 my @sig;
88 16         27 foreach my $param (@{$impl->{args}}) {
  16         33  
89              
90             # Sanity checks. TODO FIXME remove the need for these!
91             die "I don't yet know how to handle named arguments"
92 17 50       50 if $param->{named};
93             die "I don't yet know how to handle optional arguments"
94 17 50       41 if !$param->{reqd};
95              
96             # Make the constraint
97 17         25 my $constraint;
98 17 100 100     196 if($param->{type} && $param->{where}) {
    100          
    100          
99 4         38 $constraint = $param->{type} & $param->{where};
100             # Subtype - see http://blogs.perl.org/users/toby_inkster/2014/08/typetiny-tricks-1-quick-intersections.html
101             } elsif($param->{type}) {
102 9         110 $constraint = $param->{type};
103             } elsif($param->{where}) {
104             $constraint = Type::Tiny->new(
105             name => 'Constraint' . $_constraint_idx++ . '_' .
106             substr($param->{name}, 1),
107             constraint => $param->{where},
108 3         28 );
109             } else { # No constraint
110 1         2 $constraint = $_any_type;
111             }
112              
113             # Add it to the signature
114 17         3218 push @sig, $constraint;
115             } #foreach param
116              
117 16         33 push @sigs, [@sig];
118 16         30 push @impls, $impl->{code};
119              
120             # Use a straight positional copier. This is sufficient even for
121             # named parameters because Type::Params::multisig()
122             # fakes named parameters with a slurpy hash.
123 16         54 push @copiers, _make_positional_copier($hr->{defined_in}, $impl);
124             } #foreach impl
125              
126 7         36 my $checker = multisig(@sigs);
127              
128             # Make the dispatcher
129 7         18676 $code .= _line_mark_string <<'EOT';
130             # Find the candidate
131             @_ = $data[0]->(@_); # $checker. Dies on error.
132             # NOTE: this change can't be `local`ized because `goto`
133             # undoes the `local` - see #8
134             $candidate = $data[1]->[${^TYPE_PARAMS_MULTISIG}]; # impls
135             $copier = $data[2]->[${^TYPE_PARAMS_MULTISIG}]; # copiers
136             EOT
137              
138 7         32 return _complete_dispatcher($hr, $code, $checker, \@impls, \@copiers);
139             } #MakeDispatcher
140              
141             =head2 import
142              
143             When used, also imports L<Type::Tiny> into the caller's namespace (since
144             C<Type::Tiny> types are how this dispatcher functions!).
145             The caller may also wish to import L<Types::Standard>, but we don't do so
146             here in the interest of generality.
147              
148             =cut
149              
150             sub import {
151 8     8   1192 my $target = caller;
152 8         614 __PACKAGE__->export_to_level(1, @_);
153 8         42 Type::Tiny->import::into($target);
154             }
155              
156             1;
157             __END__
158              
159             # Rest of documentation {{{1
160              
161             =head1 AUTHOR
162              
163             Chris White E<lt>cxw@cpan.orgE<gt>
164              
165             =head1 LICENSE
166              
167             Copyright (C) 2019 Chris White E<lt>cxw@cpan.orgE<gt>
168              
169             This library is free software; you can redistribute it and/or modify
170             it under the same terms as Perl itself.
171              
172             =cut
173              
174             # }}}1
175             # vi: set fdm=marker: #