File Coverage

blib/lib/Kavorka/Parameter.pm
Criterion Covered Total %
statement 266 282 94.3
branch 100 150 66.6
condition 41 61 67.2
subroutine 30 35 85.7
pod 13 14 92.8
total 450 542 83.0


line stmt bran cond sub pod time code
1 38     38   479 use 5.014;
  38         81  
2 38     38   115 use strict;
  38         38  
  38         676  
3 38     38   108 use warnings;
  38         38  
  38         2830  
4              
5             package Kavorka::Parameter;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.037';
9             our @CARP_NOT = qw( Kavorka::Signature Kavorka::Sub Kavorka );
10              
11 38     38   167 use Carp qw( croak );
  38         41  
  38         2412  
12 38     38   21362 use Text::Balanced qw( extract_codeblock extract_bracketed );
  38         577354  
  38         2900  
13 38     38   245 use Parse::Keyword {};
  38         40  
  38         311  
14 38     38   14800 use Parse::KeywordX;
  38         80  
  38         459  
15              
16 38     38   13479 use Moo;
  38         10276  
  38         244  
17 38     38   34566 use namespace::sweep;
  38         505090  
  38         214  
18              
19             has package => (is => 'ro');
20             has type => (is => 'ro');
21             has name => (is => 'ro');
22             has constraints => (is => 'ro', default => sub { +[] });
23             has named => (is => 'ro', default => sub { 0 });
24             has named_names => (is => 'ro', default => sub { +[] });
25              
26             has position => (is => 'rwp');
27             has default => (is => 'ro');
28             has default_when => (is => 'ro');
29             has ID => (is => 'rwp');
30             has traits => (is => 'ro', default => sub { +{} });
31              
32 269     269   2494 has sigil => (is => 'lazy', builder => sub { substr(shift->name, 0, 1) });
33             has kind => (is => 'lazy', builder => 1);
34              
35 0     0 1 0 sub readonly { !!shift->traits->{ro} }
36 0     0 1 0 sub ro { !!shift->traits->{ro} }
37 0     0 1 0 sub rw { !shift->traits->{ro} }
38 6     6 1 24 sub alias { !!shift->traits->{alias} }
39 0     0 1 0 sub copy { !shift->traits->{alias} }
40 1993     1993 1 6772 sub slurpy { !!shift->traits->{slurpy} }
41 264     264 1 755 sub optional { !!shift->traits->{optional} }
42 2365     2365 1 10002 sub invocant { !!shift->traits->{invocant} }
43 301     301 1 1116 sub coerce { !!shift->traits->{coerce} }
44 0     0 1 0 sub locked { !!shift->traits->{locked} }
45              
46             our @PARAMS;
47             sub BUILD
48             {
49 269     269 0 7022 my $self = shift;
50 269         286 my $id = scalar(@PARAMS);
51 269         570 $self->_set_ID($id);
52 269         354 $PARAMS[$id] = $self;
53            
54 269         429 my $traits = $self->traits;
55            
56             exists($traits->{rw})
57             and !exists($traits->{ro})
58 269 100 66     632 and ($traits->{ro} = !$traits->{rw});
59            
60             exists($traits->{ro})
61             and !exists($traits->{rw})
62 269 100 100     565 and ($traits->{rw} = !$traits->{ro});
63            
64             exists($traits->{copy})
65             and !exists($traits->{alias})
66 269 50 33     525 and ($traits->{alias} = !$traits->{copy});
67            
68             exists($traits->{alias})
69             and !exists($traits->{copy})
70 269 50 33     556 and ($traits->{copy} = !$traits->{alias});
71            
72 269   66     1473 $traits->{$_} || delete($traits->{$_}) for keys %$traits;
73            
74             # traits handled natively
75 269         559 state $native_traits = {
76             coerce => 1,
77             copy => 1,
78             invocant => 1,
79             rw => 1,
80             slurpy => 1,
81             };
82            
83             my @custom_traits =
84             map "Kavorka::TraitFor::Parameter::$_",
85 269         733 grep !exists($native_traits->{$_}),
86             keys %$traits;
87            
88 269 100       3986 'Moo::Role'->apply_roles_to_object($self, @custom_traits) if @custom_traits;
89             }
90              
91             sub _build_kind
92             {
93 267     267   1495 my $self = shift;
94 267         453 local $_ = $self->name;
95 267 100       1350 /::/ ? 'global' : /\A[\$\@\%](?:\W|_\z)/ ? 'magic' : 'my';
    100          
96             }
97              
98             my $variable_re = qr{ [\$\%\@] (?: \{\^[A-Z]+\} | \w* ) }x;
99              
100             sub parse
101             {
102 193     193 1 196 state $deparse = do { require B::Deparse; 'B::Deparse'->new };
  31         199  
  31         1367  
103            
104 193         238 my $class = shift;
105 193         396 my %args = @_;
106            
107 193         274 lex_read_space;
108            
109 193         451 my %traits = (
110             invocant => 0,
111             _optional => 1,
112             );
113            
114 193 0       388 if (lex_peek(6) eq 'slurpy')
115             {
116 13         40 lex_read(6);
117 13         20 lex_read_space;
118 13         18 $traits{slurpy} = 1;
119             }
120            
121 193         329 my $type;
122 193         349 my $peek = lex_peek(1000);
123 193 100 100     1004 if ($peek =~ /\A[^\W0-9]/ and not $peek =~ /\A(my|our)\b/)
    100          
124             {
125 60         62 my $reg = do {
126 60         6793 require Type::Registry;
127 60         129801 require Type::Utils;
128 60         279223 my $tmp = 'Type::Registry::DWIM'->new;
129 60         453 $tmp->{'~~chained'} = $args{package};
130 60         99 $tmp->{'~~assume'} = 'make_class_type';
131 60         274 $tmp;
132             };
133            
134 60         249 require Type::Parser;
135 60         202 ($type, my($remaining)) = Type::Parser::extract_type($peek, $reg);
136 60         524343 my $len = length($peek) - length($remaining);
137 60         190 lex_read($len);
138 60         267 lex_read_space;
139             }
140             elsif ($peek =~ /\A\(/)
141             {
142 9         11 lex_read(1);
143 9         8 lex_read_space;
144 9 0       249 my $expr = parse_listexpr
145             or croak('Could not parse type constraint expression as listexpr');
146 9         21 lex_read_space;
147 9 0       16 lex_peek eq ')'
148             or croak("Expected ')' after type constraint expression");
149 9         17 lex_read(1);
150 9         10 lex_read_space;
151            
152 9         32 require Types::TypeTiny;
153 9         38 $type = Types::TypeTiny::to_TypeTiny( scalar $expr->() );
154 9 50       2659 $type->isa('Type::Tiny')
155             or croak("Type constraint expression did not return a blessed type constraint object");
156             }
157            
158 193         381 my ($named, $parens, $varname, $varkind, @paramname) = (0, 0);
159            
160             # :foo( ... )
161 193 0       467 if (lex_peek(2) =~ /\A\:\w/)
162             {
163 5         7 $named = 2;
164 5         6 $traits{_optional} = 1;
165 5         12 while (lex_peek(2) =~ /\A\:\w/)
166             {
167 13         22 lex_read(1);
168 13         20 push @paramname, parse_name('named parameter name', 0);
169 13 0       17 if (lex_peek eq '(')
170             {
171 7         11 lex_read(1);
172 7         7 $parens++;
173             }
174 13         32 lex_read_space;
175             }
176             }
177            
178             # Allow colon before "my"/"our" - just shift it to the correct position
179 193         341 my $saw_colon;
180 193 0       349 if (lex_peek eq ':')
181             {
182 16         31 $saw_colon++;
183 16         25 lex_read(1);
184 16         20 lex_read_space;
185             }
186            
187 193 0       431 if (lex_peek eq '\\')
188             {
189 0         0 $traits{ref_alias} = 1;
190 0         0 lex_read(1);
191 0         0 lex_read_space;
192             }
193            
194 193 0       610 if (lex_peek(3) =~ /\A(my|our)/)
195             {
196 2         6 $varkind = $1;
197 2         6 lex_read(length $varkind);
198 2         3 lex_read_space;
199             }
200            
201 193 0       443 if (lex_peek eq '\\')
202             {
203 0 0       0 croak("cannot be a double-ref-alias") if $traits{ref_alias}++;
204 0         0 lex_read(1);
205 0         0 lex_read_space;
206             }
207            
208 193 100       519 lex_stuff(':') if $saw_colon; # re-insert colon
209 193         315 $peek = lex_peek;
210            
211             # :$foo
212 193 100 100     868 if ($peek eq ':')
    50 66        
213             {
214 16         63 lex_read(1);
215 16         19 lex_read_space;
216 16         36 $varname = parse_variable;
217 16         19 $named = 1;
218 16         22 $traits{_optional} = 1;
219 16         31 push @paramname, substr($varname, 1);
220 16         25 lex_read_space;
221             }
222             # $foo
223             elsif ($peek eq '$' or $peek eq '@' or $peek eq '%')
224             {
225 177         487 $varname = parse_variable(1);
226 177 100       496 $traits{_optional} = 0 unless @paramname;
227 177         315 lex_read_space;
228             }
229            
230 193         206 undef($peek);
231            
232 193         486 for (1 .. $parens)
233             {
234 7 0       22 lex_peek(1) eq ')'
235             ? lex_read(1)
236             : croak("Expected close parentheses after named parameter name");
237 7         14 lex_read_space;
238             }
239            
240 193 0       374 if (lex_peek eq '!')
    0          
241             {
242 1         3 $traits{optional} = 0;
243 1         3 lex_read(1);
244 1         2 lex_read_space;
245             }
246             elsif (lex_peek eq '?')
247             {
248 4         14 $traits{optional} = 1;
249 4         8 lex_read(1);
250 4         7 lex_read_space;
251             }
252            
253 193         504 my (@constraints, $default, $default_when);
254            
255 193         361 while (lex_peek(5) eq 'where')
256             {
257 4         10 lex_read(5);
258 4         5 lex_read_space;
259 4         14 push @constraints, parse_block_or_match;
260 4         120 lex_read_space;
261             }
262            
263 193         700 while (lex_peek(5) =~ m{ \A (is|does|but) \s }xsm)
264             {
265 14         48 lex_read(length($1));
266 14         20 lex_read_space;
267 14         39 my ($name, undef, $args) = parse_trait;
268 14         27 $traits{$name} = $args;
269 14         44 lex_read_space;
270             }
271            
272 193 0       623 if (lex_peek(5) =~ m{ \A ( (?: [/]{2} | [|]{2} )?= ) }x)
273             {
274 13         36 $default_when = $1;
275 13         26 lex_read(length($1));
276 13         17 lex_read_space;
277             $default = lex_peek(5) =~ m{ \A (?: when\b | [,)] ) }x
278 3     3   8034 ? sub { (); }
279 13 0       95 : parse_arithexpr;
280 13         180 lex_read_space;
281 13         16 $traits{_optional} = 1;
282             }
283            
284 193   100     857 $traits{optional} //= $traits{_optional};
285 193         233 delete($traits{_optional});
286            
287             $traits{slurpy} = 1
288             if defined($varname)
289             && !$traits{ref_alias}
290 193 100 33     1279 && $varname =~ /\A[\@\%]/;
      66        
291            
292 193         4405 return $class->new(
293             %args,
294             type => $type,
295             name => $varname,
296             constraints => \@constraints,
297             named => !!$named,
298             named_names => \@paramname,
299             default => $default,
300             default_when => $default_when,
301             traits => \%traits,
302             ((kind => $varkind) x!!(defined $varkind)),
303             );
304             }
305              
306             sub sanity_check
307             {
308 193     193 1 1299 my $self = shift;
309            
310 193         241 my $traits = $self->traits;
311 193         330 my $name = $self->name;
312            
313 193 100       402 if ($self->named)
314             {
315             length($_) || croak("Bad name for parameter $name")
316 19 50 33     19 for @{ $self->named_names or die };
  19         118  
317            
318 19 50       33 croak("Bad parameter $name") if $self->invocant;
319 19 50       28 croak("Bad parameter $name") if $self->slurpy;
320             }
321            
322 193 100       3373 if ($self->kind eq 'my')
323             {
324 182 50       627 croak("Bad name for lexical variable: $name") if $name =~ /(::|\^)/;
325             }
326             else
327             {
328 11 50       35 croak("Bad name for package variable: $name") if length($name) < 2;
329             }
330            
331 193 50 66     311 croak("Bad parameter $name") if $self->invocant && $self->slurpy;
332             }
333              
334             sub injection
335             {
336 301     301 1 297 my $self = shift;
337 301         287 my ($sig) = @_;
338            
339 301         445 my $var = $self->name;
340 301         234 my $is_dummy = 0;
341 301 100       554 if (length($var) == 1)
342             {
343 8         9 $var .= 'tmp';
344 8         8 $is_dummy = 1;
345             }
346            
347 301         532 my ($val, $condition) = $self->_injection_extract_and_coerce_value($sig);
348            
349 301         689 my $code = $self->_injection_assignment($sig, $var, $val)
350             . $self->_injection_conditional_type_check($sig, $condition, $var);
351            
352 301 100       1478 $is_dummy ? "{ $code }" : $code;
353             }
354              
355             sub _injection_assignment
356             {
357 301     301   343 my $self = shift;
358 301         329 my ($sig, $var, $val) = @_;
359 301         5061 my $kind = $self->kind;
360            
361 301 100       2430 sprintf(
    100          
362             '%s %s = %s;',
363             (
364             $kind eq 'our' ? "our $var; local" :
365             $kind eq 'my' ? 'my' :
366             'local'
367             ),
368             $var,
369             $val,
370             );
371             }
372              
373             sub _injection_conditional_type_check
374             {
375 301     301   284 my $self = shift;
376 301         344 my ($sig, $condition, $var) = @_;
377            
378 301         4205 my $sigil = $self->sigil;
379 301 100       1461 my $type =
    100          
    100          
380             ($sigil eq '@') ? sprintf('for (%s) { %s }', $var, $self->_injection_type_check('$_')) :
381             ($sigil eq '%') ? sprintf('for (values %s) { %s }', $var, $self->_injection_type_check('$_')) :
382             ($condition eq '1') ? sprintf('%s;', $self->_injection_type_check($var)) :
383             sprintf('if (%s) { %s }', $condition, $self->_injection_type_check($var));
384            
385 301 100       882 return '' if $type =~ /\{ \}\z/;
386            
387 195 100       472 return sprintf(
388             'unless ($____nobble_checks) { %s };',
389             $type,
390             ) if $sig->nobble_checks;
391            
392 170         331 return $type;
393             }
394              
395             sub _injection_extract_and_coerce_value
396             {
397 301     301   271 my $self = shift;
398 301         286 my ($sig) = @_;
399            
400 301 100       463 $self->coerce
401             or return $self->_injection_extract_value(@_);
402            
403 6 50       22 my $type = $self->type
404 0         0 or croak("Parameter ${\ $self->name } cannot coerce without a type constraint");
405 6 50       35 $type->has_coercion
406 0         0 or croak("Parameter ${\ $self->name } cannot coerce because type constraint has no coercions defined");
407            
408 6         71 my ($val, $condition) = $self->_injection_extract_value(@_);
409            
410             my $coerce_variable = sub {
411 6     6   7 my $variable = shift;
412 6 50       13 if ($type->coercion->can_be_inlined)
413             {
414 0         0 $type->coercion->inline_coercion($variable),
415             }
416             else
417             {
418 6         127 sprintf(
419             '$%s::PARAMS[%d]->{type}->coerce(%s)',
420             __PACKAGE__,
421             $self->ID,
422             $variable,
423             );
424             }
425 6         32 };
426            
427 6         94 my $sigil = $self->sigil;
428            
429 6 100 33     74 if ($sigil eq '@')
    50          
    50          
    50          
430             {
431 2         3 $val = sprintf(
432             '(map { %s } %s)',
433             $coerce_variable->('$_'),
434             $val,
435             );
436             }
437            
438             elsif ($sigil eq '%')
439             {
440 0         0 $val = sprintf(
441             'do { my %%tmp = %s; for (values %%tmp) { %s }; %%tmp }',
442             $val,
443             $coerce_variable->('$_'),
444             );
445             }
446            
447             elsif ($sigil eq '$' and $type->coercion->can_be_inlined)
448             {
449 0         0 $val = sprintf(
450             'do { my $tmp = %s; %s}',
451             $val,
452             $coerce_variable->('$tmp'),
453             );
454             }
455            
456             elsif ($sigil eq '$')
457             {
458 4         138 $val = $coerce_variable->($val);
459             }
460            
461 6 50       34 wantarray ? ($val, $condition) : $val;
462             }
463              
464             sub _injection_default_value
465             {
466 602     602   1485 my $self = shift;
467 602         546 my ($fallback) = @_;
468            
469 602 100       1226 return sprintf('$%s::PARAMS[%d]{default}->()', __PACKAGE__, $self->ID) if $self->default;
470 576 100       1362 return $fallback if defined $fallback;
471            
472 231 100       398 return sprintf(
473             'Carp::croak(sprintf q/Named parameter `%%s` is required/, %s)',
474             B::perlstring($self->named_names->[0]),
475             ) if $self->named;
476            
477 230 100       325 return sprintf(
478             'Carp::croak(q/Invocant %s is required/)',
479             $self->name,
480             ) if $self->invocant;
481            
482 134         525 return sprintf(
483             'Carp::croak(q/Positional parameter %d is required/)',
484             $self->position,
485             );
486             }
487              
488             sub _injection_extract_value
489             {
490 301     301   268 my $self = shift;
491 301         275 my ($sig) = @_;
492            
493 301         224 my $condition;
494             my $val;
495 301         272 my $slurpy_style = '';
496            
497 301 100       411 if ($self->slurpy)
    100          
    100          
498             {
499 35 100 66     686 if ($self->sigil eq '%'
      66        
      66        
500             or ($self->sigil eq '$'
501             and $self->type
502 13         259 and do { require Types::Standard; $self->type->is_a_type_of(Types::Standard::HashRef()) }))
  13         41  
503             {
504 13 100       176 my @names = map(@{$_->named ? $_->named_names : []}, @{$sig->params});
  33         91  
  13         28  
505 13 100       28 if (@names)
506             {
507 6 50       23 croak("Cannot alias slurpy hash for a function with named parameters")
508             if $self->alias;
509            
510 6 100       50 my $delete = $_->name eq '%_' ? '' : sprintf(
511             'delete $tmp{$_} for (%s);',
512             join(q[,], map B::perlstring($_), @names),
513             );
514 6         119 my $ix = 1 + $sig->last_position;
515 6         40 $val = sprintf(
516             'do { use warnings FATAL => qw(all); my %%tmp = ($#_==%d && ref($_[%d]) eq q(HASH)) ? %%{$_[%d]} : @_[ %d .. $#_ ]; %s %%tmp ? %%tmp : (%s) }',
517             ($ix) x 4,
518             $delete,
519             $self->_injection_default_value('()'),
520             );
521             }
522             else
523             {
524 7         108 $val = sprintf(
525             'do { use warnings FATAL => qw(all); my %%tmp = @_[ %d .. $#_ ]; %%tmp ? @_[ %d .. $#_ ] : (%s) }',
526             $sig->last_position + 1,
527             $sig->last_position + 1,
528             $self->_injection_default_value('()'),
529             );
530             }
531 13         19 $condition = 1;
532 13         16 $slurpy_style = '%';
533             }
534             else
535             {
536 22 50       5308 croak("Cannot have a slurpy array for a function with named parameters")
537             if $sig->has_named;
538 22         420 $val = sprintf(
539             '($#_ >= %d) ? @_[ %d .. $#_ ] : (%s)',
540             $sig->last_position + 1,
541             $sig->last_position + 1,
542             $self->_injection_default_value('()'),
543             );
544 22         37 $condition = 1;
545 22         28 $slurpy_style = '@';
546             }
547            
548 35 100       577 if ($self->sigil eq '$')
549             {
550 13 100       125 $val = $slurpy_style eq '%' ? "+{ $val }" : "[ $val ]";
551 13         18 $slurpy_style = '$';
552             }
553             }
554             elsif ($self->named)
555             {
556 38     38   118630 no warnings 'uninitialized';
  38         55  
  38         5875  
557             my $when = +{
558             '//=' => 'defined',
559             '||=' => '!!',
560             '=' => 'exists',
561 19   50     118 }->{ $self->default_when } || 'exists';
562            
563             $val = join '', map(
564             sprintf('%s($_{%s}) ? $_{%s} : ', $when, $_, $_),
565 19         38 map B::perlstring($_), @{$self->named_names}
  19         436  
566             ), $self->_injection_default_value();
567            
568             $condition = join ' or ', map(
569             sprintf('%s($_{%s})', $when, $_),
570 19         26 map B::perlstring($_), @{$self->named_names}
  19         133  
571             );
572             }
573             elsif ($self->invocant)
574             {
575 96         195 $val = sprintf('@_ ? shift(@_) : %s', $self->_injection_default_value());
576 96         133 $condition = 1;
577             }
578             else
579             {
580 38     38   150 no warnings 'uninitialized';
  38         50  
  38         13306  
581             my $when = +{
582             '//=' => 'defined($_[%d])',
583             '||=' => '!!($_[%d])',
584             '=' => '($#_ >= %d)',
585 151   100     1026 }->{ $self->default_when } || '($#_ >= %d)';
586            
587 151         436 my $pos = $self->position;
588 151         667 $val = sprintf($when.' ? $_[%d] : %s', $pos, $pos, $self->_injection_default_value());
589 151         357 $condition = sprintf($when, $self->position);
590             }
591            
592 301 100       1140 $condition = 1 if $self->_injection_default_value('@@') ne '@@';
593            
594 301 50       815 wantarray ? ($val, $condition) : $val;
595             }
596              
597             sub _injection_type_check
598             {
599 301     301   270 my $self = shift;
600 301         316 my ($var) = @_;
601            
602 301         275 my $check = '';
603 301 100       990 if ( my $type = $self->type )
604             {
605             my $can_xs =
606             $INC{'Mouse/Util.pm'}
607             && Mouse::Util::MOUSE_XS()
608 88   66     549 && ($type->{_is_core} or $type->is_parameterized && $type->parent->{_is_core});
609            
610 88 100 100     331 if (!$can_xs and $type->can_be_inlined)
611             {
612 78         1589 $check .= sprintf(
613             '%s;',
614             $type->inline_assert($var),
615             );
616             }
617             else
618             {
619 10         134 $check .= sprintf(
620             '$%s::PARAMS[%d]->{type}->assert_valid(%s);',
621             __PACKAGE__,
622             $self->ID,
623             $var,
624             );
625             }
626             }
627            
628 301         4259 for my $i (0 .. $#{$self->constraints})
  301         957  
629             {
630 4         30 $check .= sprintf(
631             'do { local $_ = %s; $%s::PARAMS[%d]->{constraints}[%d]->() } or Carp::croak(sprintf("%%s failed value constraint", %s));',
632             $var,
633             __PACKAGE__,
634             $self->ID,
635             $i,
636             B::perlstring($var),
637             );
638             }
639            
640 301         753 return $check;
641             }
642              
643             1;
644              
645              
646             __END__
647              
648             =pod
649              
650             =encoding utf-8
651              
652             =for stopwords invocant invocants lexicals unintuitive booleans globals
653              
654             =head1 NAME
655              
656             Kavorka::Parameter - a single parameter in a function signature
657              
658             =head1 DESCRIPTION
659              
660             Kavorka::Parameter is a class where each instance represents a
661             parameter in a function signature. This class is used to help parse
662             the function signature, and also to inject Perl code into the final
663             function.
664              
665             Instances of this class are also returned by Kavorka's function
666             introspection API.
667              
668             =head2 Introspection API
669              
670             A parameter instance has the following methods:
671              
672             =over
673              
674             =item C<ID>
675              
676             An opaque numeric identifier for this parameter.
677              
678             =item C<package>
679              
680             Returns the package name the parameter was declared in.
681              
682             =item C<type>
683              
684             A L<Type::Tiny> object representing the type constraint for the
685             parameter, or undef.
686              
687             =item C<name>
688              
689             The name of the variable associated with this parameter, including
690             its sigil.
691              
692             =item C<constraints>
693              
694             An arrayref of additional constraints upon the value. These are given
695             as coderefs.
696              
697             =item C<named>
698              
699             A boolean indicating whether this is a named parameter.
700              
701             =item C<named_names>
702              
703             An arrayref of names for this named parameter.
704              
705             =item C<position>
706              
707             The position for a positional parameter.
708              
709             =item C<default>
710              
711             A coderef supplying the default value for this parameter.
712              
713             =item C<default_when>
714              
715             The string "=", "//=" or "||=".
716              
717             =item C<traits>
718              
719             A hashref, where the keys represent names of parameter traits, and
720             the values are booleans.
721              
722             =item C<sigil>
723              
724             The sigil of the variable for this parameter.
725              
726             =item C<kind>
727              
728             Returns "our" for package variables; "global" for namespace-qualified
729             package variables (i.e. containing "::"); "magic" for C<< $_ >> and
730             escape char variables like C<< ${^HELLO} >>; "my" otherwise.
731              
732             =item C<readonly>, C<ro>
733              
734             A boolean indicating whether this variable will be read-only.
735              
736             =item C<rw>
737              
738             A boolean indicating whether this variable will be read-write.
739              
740             =item C<locked>
741              
742             A boolean indicating whether this variable is a locked hash(ref).
743              
744             =item C<alias>
745              
746             A boolean indicating whether this variable will be an alias.
747              
748             =item C<copy>
749              
750             A boolean indicating whether this variable will be a copy (non-alias).
751              
752             =item C<slurpy>
753              
754             A boolean indicating whether this variable is slurpy.
755              
756             =item C<optional>
757              
758             A boolean indicating whether this variable is optional.
759              
760             =item C<invocant>
761              
762             A boolean indicating whether this variable is an invocant.
763              
764             =item C<coerce>
765              
766             A boolean indicating whether this variable should coerce.
767              
768             =back
769              
770             =head2 Other Methods
771              
772             =over
773              
774             =item C<parse>
775              
776             An internal method used to parse a parameter. Only makes sense to use
777             within a L<Parse::Keyword> parser.
778              
779             =item C<injection>
780              
781             The string of Perl code to inject for this parameter.
782              
783             =item C<sanity_check>
784              
785             Tests that the parameter is sane. (For example it would not be sane to
786             have an invocant that is an optional parameter.)
787              
788             =back
789              
790             =head1 BUGS
791              
792             Please report any bugs to
793             L<http://rt.cpan.org/Dist/Display.html?Queue=Kavorka>.
794              
795             =head1 SEE ALSO
796              
797             L<Kavorka::Manual::API>,
798             L<Kavorka::Signature>.
799              
800             =head1 AUTHOR
801              
802             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
803              
804             =head1 COPYRIGHT AND LICENCE
805              
806             This software is copyright (c) 2013-2014, 2017 by Toby Inkster.
807              
808             This is free software; you can redistribute it and/or modify it under
809             the same terms as the Perl 5 programming language system itself.
810              
811             =head1 DISCLAIMER OF WARRANTIES
812              
813             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
814             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
815             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
816