From: Lukas Mai Date: Sun, 15 Sep 2013 16:04:40 +0000 (+0200) Subject: rework keyword properties; add 'defaults', 'strict' X-Git-Tag: v1.0301~6 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=f7651a6e5b18523fd6e00f809a8c40dd0127251a;p=p5sagit%2FFunction-Parameters.git rework keyword properties; add 'defaults', 'strict' --- diff --git a/lib/Function/Parameters.pm b/lib/Function/Parameters.pm index 4bd2e1c..018faf9 100644 --- a/lib/Function/Parameters.pm +++ b/lib/Function/Parameters.pm @@ -64,43 +64,30 @@ sub _delete_default { my @bare_arms = qw(function method); my %type_map = ( - function => { - name => 'optional', - default_arguments => 1, - check_argument_count => 0, - named_parameters => 1, - types => 1, - reify_type => \&_reify_type_default, + function => {}, # all default settings + function_strict => { + defaults => 'function', + strict => 1, }, - method => { - name => 'optional', - default_arguments => 1, - check_argument_count => 0, - named_parameters => 1, - types => 1, - reify_type => \&_reify_type_default, - attrs => ':method', - shift => '$self', - invocant => 1, + method => { + defaults => 'function', + attributes => ':method', + shift => '$self', + invocant => 1, }, - classmethod => { - name => 'optional', - default_arguments => 1, - check_argument_count => 0, - named_parameters => 1, - types => 1, - reify_type => \&_reify_type_default, - attributes => ':method', - shift => '$class', - invocant => 1, + method_strict => { + defaults => 'method', + strict => 1, + }, + classmethod => { + defaults => 'method', + shift => '$class', + }, + classmethod_strict => { + defaults => 'classmethod', + strict => 1, }, ); -for my $k (keys %type_map) { - $type_map{$k . '_strict'} = { - %{$type_map{$k}}, - check_argument_count => 1, - }; -} our @type_reifiers = \&_reify_type_default; @@ -134,31 +121,35 @@ sub import { my ($name, $proto_type) = @$item; _assert_valid_identifier $name; - unless (ref $proto_type) { - # use '||' instead of 'or' to preserve $proto_type in the error message - $proto_type = $type_map{$proto_type} - || confess qq["$proto_type" doesn't look like a valid type (one of ${\join ', ', sort keys %type_map})]; - } + $proto_type = {defaults => $proto_type} unless ref $proto_type; my %type = %$proto_type; + while (my $defaults = delete $type{defaults}) { + my $base = $type_map{$defaults} + or confess qq["$defaults" doesn't look like a valid type (one of ${\join ', ', sort keys %type_map})]; + %type = (%$base, %type); + } + my %clean; - $clean{name} = delete $type{name} || 'optional'; + $clean{name} = delete $type{name} // 'optional'; $clean{name} =~ /^(?:optional|required|prohibited)\z/ or confess qq["$clean{name}" doesn't look like a valid name attribute (one of optional, required, prohibited)]; - $clean{shift} = delete $type{shift} || ''; + $clean{shift} = delete $type{shift} // ''; _assert_valid_identifier $clean{shift}, 1 if $clean{shift}; - $clean{attrs} = join ' ', map delete $type{$_} || (), qw(attributes attrs); + $clean{attrs} = join ' ', map delete $type{$_} // (), qw(attributes attrs); _assert_valid_attributes $clean{attrs} if $clean{attrs}; $clean{default_arguments} = _delete_default \%type, 'default_arguments', 1; $clean{named_parameters} = _delete_default \%type, 'named_parameters', 1; $clean{types} = _delete_default \%type, 'types', 1; - $clean{check_argument_count} = _delete_default \%type, 'check_argument_count', 0; $clean{invocant} = _delete_default \%type, 'invocant', 0; + $clean{check_argument_count} = _delete_default \%type, 'check_argument_count', 0; + $clean{check_argument_types} = _delete_default \%type, 'check_argument_types', 0; + $clean{check_argument_count} = $clean{check_argument_types} = 1 if delete $type{strict}; if (my $rt = delete $type{reify_type}) { ref $rt eq 'CODE' or confess qq{"$rt" doesn't look like a type reifier}; @@ -191,11 +182,12 @@ sub import { $type->{name} eq 'required' ? FLAG_NAME_OK : FLAG_ANON_OK | FLAG_NAME_OK ; - $flags |= FLAG_DEFAULT_ARGS if $type->{default_arguments}; - $flags |= FLAG_CHECK_NARGS | FLAG_CHECK_TARGS if $type->{check_argument_count}; - $flags |= FLAG_INVOCANT if $type->{invocant}; - $flags |= FLAG_NAMED_PARAMS if $type->{named_parameters}; - $flags |= FLAG_TYPES_OK if $type->{types}; + $flags |= FLAG_DEFAULT_ARGS if $type->{default_arguments}; + $flags |= FLAG_CHECK_NARGS if $type->{check_argument_count}; + $flags |= FLAG_CHECK_TARGS if $type->{check_argument_types}; + $flags |= FLAG_INVOCANT if $type->{invocant}; + $flags |= FLAG_NAMED_PARAMS if $type->{named_parameters}; + $flags |= FLAG_TYPES_OK if $type->{types}; $^H{HINTK_FLAGS_ . $kw} = $flags; $^H{HINTK_SHIFT_ . $kw} = $type->{shift}; $^H{HINTK_ATTRS_ . $kw} = $type->{attrs}; @@ -606,6 +598,28 @@ a reference to a hash with the following keys: =over +=item C + +Valid values: One of the predefined types C, C, +C, C, C, C. +This will set the defaults for all other keys from the specified type, which is +useful if you only want to override some properties: + + use Function::Parameters { defmethod => { defaults => 'method', shift => '$this' } }; + +This example defines a keyword called C that works like the standard +C keyword, but the implicit object variable is called C<$this> instead +of C<$self>. + +Using the string types directly is equivalent to C with no further +customization: + + use Function::Parameters { + foo => 'function', # like: foo => { defaults => 'function' }, + bar => 'function_strict', # like: bar => { defaults => 'function_strict' }, + baz => 'method_strict', # like: baz => { defaults => 'method_strict' }, + }; + =item C Valid values: C (default), C (all functions defined with @@ -646,8 +660,16 @@ automatically check that they have been passed all required arguments and no excess arguments. If this check fails, an exception will by thrown via L|Carp>. -Currently this flag is overloaded to also enable type checks (see -L below). +=item C + +Valid values: booleans. If turned on, functions defined with this keyword will +automatically check that the arguments they are passed pass the declared type +constraints (if any). See L below. + +=item C + +Valid values: booleans. This turns on both C and +C. =item C @@ -668,10 +690,10 @@ The default type reifier is equivalent to: The predefined type C is equivalent to: { - name => 'optional', - invocant => 0, - default_arguments => 1, - check_argument_count => 0, + name => 'optional', + default_arguments => 1, + strict => 0, + invocant => 0, } These are all default values, so C is also equivalent to C<{}>. @@ -679,29 +701,23 @@ These are all default values, so C is also equivalent to C<{}>. C is equivalent to: { - name => 'optional', - shift => '$self', - invocant => 1, - attributes => ':method', - default_arguments => 1, - check_argument_count => 0, + defaults => 'function', + attributes => ':method', + shift => '$self', + invocant => 1, } C is equivalent to: { - name => 'optional', - shift => '$class', - invocant => 1, - attributes => ':method', - default_arguments => 1, - check_argument_count => 0, + defaults => 'method', + shift => '$class', } C, C, and C are like C, C, and -C, respectively, but with C<< check_argument_count => 1 >>. +C, respectively, but with C<< strict => 1 >>. =back diff --git a/t/bonus.t b/t/bonus.t index 0f7abea..31b5381 100644 --- a/t/bonus.t +++ b/t/bonus.t @@ -7,7 +7,7 @@ use strict; use Function::Parameters { fun => { - check_argument_count => 1, + defaults => 'function_strict', }, }; diff --git a/t/checkered.t b/t/checkered.t index b0313d2..2f80c38 100644 --- a/t/checkered.t +++ b/t/checkered.t @@ -7,12 +7,11 @@ use strict; use Function::Parameters { fun => { - check_argument_count => 1, - default_arguments => 1, + strict => 1, }, sad => { - check_argument_count => 0, + strict => 0, }, }; diff --git a/t/checkered_2.t b/t/checkered_2.t index cc46171..887ebe2 100644 --- a/t/checkered_2.t +++ b/t/checkered_2.t @@ -7,15 +7,13 @@ use strict; use Function::Parameters { method => { - check_argument_count => 1, - shift => '$self', - attributes => ':method', + defaults => 'method', + strict => 1, }, cathod => { - check_argument_count => 0, - shift => '$self', - attrs => ':method', + defaults => 'method', + strict => 0, }, fun => 'function', diff --git a/t/foreign/Method-Signatures-Simple/03-config.t b/t/foreign/Method-Signatures-Simple/03-config.t index ba9e530..5ca4b9e 100644 --- a/t/foreign/Method-Signatures-Simple/03-config.t +++ b/t/foreign/Method-Signatures-Simple/03-config.t @@ -10,8 +10,8 @@ use Test::More tests => 3; use Function::Parameters; use Function::Parameters { - action => { shift => '$monster', invocant => 1 }, - constructor => { shift => '$species', invocant => 1 }, + action => { defaults => 'method', shift => '$monster' }, + constructor => { defaults => 'method', shift => '$species' }, function => 'function', }; diff --git a/t/types_custom.t b/t/types_custom.t index 02e46fc..7198c2d 100644 --- a/t/types_custom.t +++ b/t/types_custom.t @@ -7,7 +7,7 @@ use Test::Fatal; use Function::Parameters qw(:strict); use Function::Parameters { - def => { check_argument_count => 1 }, + def => { strict => 1 }, }; { diff --git a/t/types_custom_2.t b/t/types_custom_2.t index fa8ec06..d8d6d1f 100644 --- a/t/types_custom_2.t +++ b/t/types_custom_2.t @@ -44,7 +44,7 @@ use Function::Parameters do { ); +{ fun => { - check_argument_count => 1, + strict => 1, reify_type => sub { $Types{ $_[0] } || $Types{Any} }, }, } diff --git a/t/types_custom_3.t b/t/types_custom_3.t index 769ce0e..ac61f6d 100644 --- a/t/types_custom_3.t +++ b/t/types_custom_3.t @@ -15,7 +15,7 @@ use Test::More tests => 8; use Function::Parameters { fun => { - check_argument_count => 1, + strict => 1, reify_type => sub { my ($type, $package) = @_; if ($package ne $type) { diff --git a/t/types_moose_3.t b/t/types_moose_3.t index 52dd01c..b3cda18 100644 --- a/t/types_moose_3.t +++ b/t/types_moose_3.t @@ -10,7 +10,7 @@ use Test::More use Test::Fatal; use Function::Parameters { - def => { check_argument_count => 1 }, + def => { strict => 1 }, }; def foo(Int $n, CodeRef $f, $x) {