From b5392fc0ee7ca0bb9211eae3867542f319429364 Mon Sep 17 00:00:00 2001 From: CrawfordCurrie Date: Thu, 4 Nov 2010 11:19:07 +0000 Subject: [PATCH] Item9948: reverted the rgeisterMETA API to reflect the original intent. Added the 'many' and 'alias' keys to meta-data registrations to support array types and query aliases respectively. Refactored exported knowledge about registered tags from Query::Node back to where it belongs, in Meta. Deprecated the registerMETA method in Func; it duplicates the method in Meta, which is already a public API git-svn-id: http://svn.foswiki.org/trunk@9858 0b4bb1d4-4e5a-0410-9cc4-b2b747904278 --- UnitTestContrib/test/unit/MetaTests.pm | 22 +++-- core/data/System/QuerySearch.txt | 5 +- core/lib/Foswiki/Func.pm | 67 +------------ core/lib/Foswiki/Meta.pm | 126 ++++++++++++++++++++++--- core/lib/Foswiki/Query/Node.pm | 40 ++++---- 5 files changed, 154 insertions(+), 106 deletions(-) diff --git a/UnitTestContrib/test/unit/MetaTests.pm b/UnitTestContrib/test/unit/MetaTests.pm index e478fb9cd4..af7cb89e84 100644 --- a/UnitTestContrib/test/unit/MetaTests.pm +++ b/UnitTestContrib/test/unit/MetaTests.pm @@ -564,7 +564,7 @@ sub test_registerMETA { $this->assert($o->isValidEmbedding( 'TREE', { })); # required param - Foswiki::Func::registerMETA('TREE', 'scalar', require => [ 'spread' ]); + Foswiki::Func::registerMETA('TREE', require => [ 'spread' ]); $this->assert(!$o->isValidEmbedding( 'TREE', { })); $this->assert(!$o->isValidEmbedding( 'TREE', { type => 'ash', height => '15' })); @@ -572,7 +572,7 @@ sub test_registerMETA { 'TREE', { type => 'ash', height => '15', spread=>'5' })); # required param and allowed param - Foswiki::Func::registerMETA('TREE', 'scalar', require => [ 'spread' ], + Foswiki::Func::registerMETA('TREE', require => [ 'spread' ], allow => [ 'height' ]); $this->assert(!$o->isValidEmbedding( 'TREE', { type => 'ash', height => '15', spread=>'5' })); @@ -580,7 +580,7 @@ sub test_registerMETA { 'TREE', { spread => '5', height => '15' })); # Function and require. - Foswiki::Func::registerMETA('TREE', 'scalar', require => [ 'height' ], + Foswiki::Func::registerMETA('TREE', require => [ 'height' ], function => sub { my ($name, $args) = @_; $this->assert_equals('TREE', $name); @@ -590,7 +590,7 @@ sub test_registerMETA { 'TREE', { height=>10 })); # required param, allowed param and function - Foswiki::Func::registerMETA('TREE', 'scalar', require => [ 'spread' ], + Foswiki::Func::registerMETA('TREE', require => [ 'spread' ], allow => [ 'height' ], function => sub { my ($name, $args) = @_; @@ -603,7 +603,7 @@ sub test_registerMETA { 'TREE', { spread=>15, height=>10 }), $Foswiki::Meta::reason); # allowed param only, function rewrites args - Foswiki::Func::registerMETA('TREE', 'scalar', allow => [ 'height' ], + Foswiki::Func::registerMETA('TREE', allow => [ 'height' ], function => sub { my ($name, $args) = @_; $this->assert_equals('TREE', $name); @@ -623,6 +623,7 @@ sub test_registerArrayMeta { my $this = shift; my $test = <<'TEST'; Properties: %QUERY{"META:SLPROPERTY.name"}% +A property: %QUERY{"slug[name='PreyOf'].values"}% Values: %QUERY{"META:SLPROPERTYVALUE.value"}% TEST my $text = <<'HERE'; @@ -640,12 +641,13 @@ TEST HERE Foswiki::Meta::registerMETA( 'SLPROPERTY', - 'array', + many => 1, + alias => 'slug', require => [qw(name values)], ); Foswiki::Meta::registerMETA( 'SLPROPERTYVALUE', - 'array', + many => 1, require => [qw(name value)], ); my $topicObject = @@ -655,6 +657,7 @@ HERE # All meta should have found its way into text $this->assert_equals(<<'EXPECTED', $topicObject->expandMacros($test)); Properties: System.SemanticIsPartOf,Example.Property,PreyOf,Eat,IsPartOf +A property: Snakes Values: System.UserDocumentationCategory,UserDocumentationCategory,Snakes,Mosquitos,Flies,UserDocumentationCategory EXPECTED } @@ -664,6 +667,7 @@ sub test_registerScalarMeta { my $this = shift; my $test = <<'TEST'; Properties: %QUERY{"META:SLPROPERTY.name"}% +Alias: %QUERY{"slug.name"}% Values: %QUERY{"META:SLPROPERTYVALUE.value"}% TEST my $text = <<'HERE'; @@ -681,12 +685,11 @@ TEST HERE Foswiki::Meta::registerMETA( 'SLPROPERTY', - 'scalar', + alias => 'slug', require => [qw(name values)], ); Foswiki::Meta::registerMETA( 'SLPROPERTYVALUE', - 'scalar', require => [qw(name value)], ); my $topicObject = @@ -696,6 +699,7 @@ HERE # All meta should have found its way into text $this->assert_equals(<<'EXPECTED', $topicObject->expandMacros($test)); Properties: System.SemanticIsPartOf +Alias: System.SemanticIsPartOf Values: System.UserDocumentationCategory EXPECTED } diff --git a/core/data/System/QuerySearch.txt b/core/data/System/QuerySearch.txt index 265c004c06..4a025cb065 100644 --- a/core/data/System/QuerySearch.txt +++ b/core/data/System/QuerySearch.txt @@ -56,7 +56,9 @@ All meta-data in a topic is referenced according to a simple plan. * =name= * =value= -See MetaData for details of what all these entries mean. +See MetaData for details of what all these entries mean. Note that the set +of meta-data types (and the aliases used to refer to them) may be extended +by Foswiki extensions. Most things at the top level of the plan - =META:TOPICPARENT=, =META:TOPICINFO= etc - are _structures_ which are indexed by _keys_. For example, =META:TOPICINFO= has 4 entries, which are indexed by the keys =author=, =date=, =format= and =version=. =META:FILEATTACHMENT=, =META:FIELD= and =META:PREFERENCE= are all _arrays_, which means they can have any number of records under them. Arrays are indexed by _numbers_ - for example, the first entry in the =META:FIELD= array is entry 0. @@ -68,6 +70,7 @@ It's a bit clumsy having to type =META:FILEATTACHMENT= every time you want to re * =form= means the same as =META:FORM=, so to test if a topic has a form named 'UserForm' you test for ="form.name ~ '*.UserForm'"= * =fields= means the same as =META:FIELD=, You can also use the name of the form (the value of =form.name= e.g. =PersonForm=) * =preferences= means the same as =META:PREFERENCE= + * extensions may add additional aliases when they register new meta-data types Fields in this plan are referenced using a simple _field specifier_ syntax: | *Syntax* | *Means* | *Examples* | diff --git a/core/lib/Foswiki/Func.pm b/core/lib/Foswiki/Func.pm index 30809f1edc..ff7cb7e4e4 100644 --- a/core/lib/Foswiki/Func.pm +++ b/core/lib/Foswiki/Func.pm @@ -674,73 +674,14 @@ sub registerRESTHandler { =begin TML ----+++ registerMETA($name, $type, %syntax) - -Foswiki supports embedding meta-data into topics. For example, - -=%META:BOOK{title="Transit" author="Edmund Cooper" isbn="0-571-05724-1"}%= - -This meta-data is validated when it is read from the store. Meta-data -that is not registered, or doesn't pass validation, is ignored. This -function allows you to register a new META datum, passing the name and type in -=$name=. =$type=, =%syntax= is a set of optional checks that describe how to -validate the fields of the datum. - -The following values for $type are supported: - * =scalar= - where the value for only one META datum may be returned from a - query on a given topic, Eg. =META:FORM= - * =array= - where multiple values for a META datum may be returned from a - query on a given topic, Eg. =META:FILEATTACHMENT= - -The following checks are supported: - -=function=>\&fn= In this case the function =fn= will be called when the -datum is encountered, passing in the name of the macro and the -argument hash. The function must return a non-zero/undef value if the tag -is acceptable, or 0 otherwise. For example: - -registerMETA('BOOK', function => sub { - my ($name, $args) = @_; - # $name will be BOOK - return defined $args->{title}; -} - -can be used to check that =%META:BOOK{}= contains a title. - -=require=>[]= is used to check that a list of named parameters are present on -the tag. For example, - -registerMETA('BOOK', require => [ 'title', 'author' ]); - -can be used to check that both =title= and =author= are present. - -=allow=>[]= lets you specify other optional parameters that are allowed -on the tag. If you specify =allow= then the validation will fail if the -tag contains any parameters that are _not_ in the =allow= or =require= lists. -If you don't specify =allow= then all parameters will be allowed. - -Checks are cumulative, so if you: - -registerMETA('BOOK', - function => \&checkParameters, - require => [ 'title' ], - allow => [ 'author', 'isbn' ]); - -then all these conditions will be tested. Note that =require= and =allow= -are tested _after_ =function= is called, to give the function a chance to -rewrite the parameter list. - -If no checker is registered for a META tag, then it will automatically -be accepted into the topic meta-data. - -Note that the checker only verifies the *presence* of parameters, and -not their *values*. +---+++ registerMETA($macro, $spec) +Deprecated: please use Foswiki::Meta::registerMETA instead. =cut sub registerMETA { - my ( $macro, $type, %spec ) = @_; - Foswiki::Meta::registerMETA( $macro, $type, %spec ); + #my ( $macro, %spec ) = @_; + Foswiki::Meta::registerMETA( @_ ) } =begin TML diff --git a/core/lib/Foswiki/Meta.pm b/core/lib/Foswiki/Meta.pm index ddb03edfc8..85d2db9252 100644 --- a/core/lib/Foswiki/Meta.pm +++ b/core/lib/Foswiki/Meta.pm @@ -136,13 +136,19 @@ our $SUMMARY_DEFAULT_CONTEXT = 30; our $CHANGES_SUMMARY_LINECOUNT = 6; our $CHANGES_SUMMARY_PLAINTRUNC = 70; -# META:x validation. See Foswiki::Func::registerMETA for more information. -# Note that 'other' is *not* the same as 'allow'; it doesn't imply any -# exclusion of tags that contain unaccepted params. It's really just for -# documentation (and DB schema initialisation). -# _default is set on base meta-data types (those not added by -# Foswiki::Func::registerMETA) to differentiate the minimum required -# meta-data and that added by extensions. +=begin TML +PUBLIC %VALIDATE; + +META:x validation. This hash maps from META: names to the type record +registered by registerMETA. See registerMETA for more information on what +these records contain. + +_default is set on base meta-data types (those not added by +Foswiki::Func::registerMETA) to differentiate the minimum required +meta-data and that added by extensions. + +=cut + our %VALIDATE = ( TOPICINFO => { allow => [ @@ -150,10 +156,12 @@ our %VALIDATE = ( rev comment encoding ) ], _default => 1, + alias => 'info', }, TOPICMOVED => { require => [qw( from to by date )], _default => 1, + alias => 'moved', }, # Special case, see Item2554; allow an empty TOPICPARENT, as this was @@ -161,6 +169,7 @@ our %VALIDATE = ( TOPICPARENT => { allow => [qw( name )], _default => 1, + alias => 'parent', }, FILEATTACHMENT => { require => [qw( name )], @@ -169,37 +178,128 @@ our %VALIDATE = ( comment attr ) ], _default => 1, + alias => 'attachments', + many => 1, }, FORM => { require => [qw( name )], _default => 1, + alias => 'form', }, FIELD => { require => [qw( name value )], other => [qw( title )], _default => 1, + alias => 'fields', + many => 1, }, PREFERENCE => { require => [qw( name value )], other => [qw( type )], _default => 1, + alias => 'preference', + many => 1, } ); +our %aliases; +our %isArrayType; + +BEGIN { + foreach my $name (keys %VALIDATE) { + my $d = $VALIDATE{$name}; + $aliases{$d->{alias}} = "META:$name" if $d->{alias}; + $isArrayType{$name} = $d->{many}; + } +} + =begin TML ----++ StaticMethod registerMETA($name, $type, %check) +---++ StaticMethod registerMETA($name, %syntax) + +Foswiki supports embedding meta-data into topics. For example, + +=%META:BOOK{title="Transit" author="Edmund Cooper" isbn="0-571-05724-1"}%= + +This meta-data is validated when it is read from the store. Meta-data +that is not registered, or doesn't pass validation, is ignored. This +function allows you to register a new META datum, passing the name in +=$name=. =%syntax= contains information about the syntax and semantics of +the tag. + +The following entries are supported in =%syntax= + +=many=>1=. By default meta-data are single valued i.e. can only occur once +in a topic. If you require the meta-data to be repeated many times (like +META:FIELD and META:ATTACHMENT) then you must set this option. For example, +to declare a many-valued =BOOK= meta-data type: + +registerMeta('BOOK', many => 1) + + +=require=>[]= is used to check that a list of named parameters are present on +the tag. For example, + +registerMETA('BOOK', require => [ 'title', 'author' ]); + +can be used to check that both =title= and =author= are present. + +=allow=>[]= lets you specify other optional parameters that are allowed +on the tag. If you specify =allow= then the validation will fail if the +tag contains any parameters that are _not_ in the =allow= or =require= lists. +If you don't specify =allow= then all parameters will be allowed. + +=require= and =allow= only verify the *presence* of parameters, and +not their *values*. -See Foswiki::Func::registerMETA for full doc of this function. +=other=[]= lets you declare other legal parameters, and is provided +mainly to support the initialisation of DB schema. It it is like +=allow= except that it doesn't imply any exclusion of META that contains +unallowed params. + +=function=>\&fn= causes the function =fn= to be called when the +datum is encountered when reading a topic, passing in the name of the +macro and the argument hash. The function must return a non-zero/undef +value if the tag is acceptable, or 0 otherwise. For example: + +registerMETA('BOOK', function => sub { + my ($name, $args) = @_; + # $name will be BOOK + return isValidTitle($args->{title}); +} + +can be used to check that =%META:BOOK{}= contains a valid title. + +Checks are cumulative, so if you: + +registerMETA('BOOK', + function => \&checkParameters, + require => [ 'title' ], + allow => [ 'author', 'isbn' ]); + +then all these conditions will be tested. Note that =require= and =allow= +are tested _after_ =function= is called, to give the function a chance to +rewrite the parameter list. + +If no checker is registered for a META tag, then it will automatically +be accepted into the topic meta-data. + +=alias=>'name'= lets you set an alias for the datum that will be added to +the query language. For example, =alias=>'info'= is used to alias +'META:TOPICINFO' in queries. + +registerMeta('BOOK', alias => 'book', many => 1) + +This lets you use syntax such as =books[author='Anais Nin']= in queries. +See QuerySearch for more on aliases. =cut sub registerMETA { - my ( $name, $type, %check ) = @_; - if ($type eq 'array') { - $Foswiki::Query::Node::isArrayType{$name} = 1; - } + my ( $name, %check ) = @_; $VALIDATE{$name} = \%check; + $aliases{$check{alias}} = "META:$name" if $check{alias}; + $isArrayType{$name} = $check{many}; } ############# GENERIC METHODS ############# diff --git a/core/lib/Foswiki/Query/Node.pm b/core/lib/Foswiki/Query/Node.pm index ee0bd16bc2..8b44b4d0aa 100644 --- a/core/lib/Foswiki/Query/Node.pm +++ b/core/lib/Foswiki/Query/Node.pm @@ -34,35 +34,35 @@ our @ISA = ('Foswiki::Infix::Node'); use Assert; use Error qw( :try ); +use Foswiki::Meta (); + +# Cache of the names of $Foswiki::cfg items that are accessible +our $isAccessibleCfg; + =begin TML ----++ PUBLIC $aliases +---++ PUBLIC %aliases A hash mapping short aliases for META: entry names. For example, this hash -maps 'form' to 'META:FORM'. Published so extensions can extend the range -of supported types. +maps 'form' to 'META:FORM'. Published because extensions (search +implementations) have made use of it in the past, though not part of the +offical API. + +This hash is maintained by Foswiki::Meta and is *strictly read-only* ---++ PUBLIC %isArrayType Maps META: entry type names to true if the type is an array type (such as -FIELD, ATTACHMENT or PREFERENCE). Published so extensions can extend the range -of supported types. The type name should be given without the leading 'META:' +FIELD, ATTACHMENT or PREFERENCE). Published because extensions (search +implementations) have made use of it in the past, though not part of the +offical API. The type name should be given without the leading 'META:' -=cut - -our %aliases = ( - attachments => 'META:FILEATTACHMENT', - fields => 'META:FIELD', - form => 'META:FORM', - info => 'META:TOPICINFO', - moved => 'META:TOPICMOVED', - parent => 'META:TOPICPARENT', - preferences => 'META:PREFERENCE', -); +This hash is maintained by Foswiki::Meta and is *strictly read-only* -our %isArrayType; -map { $isArrayType{$_} = 1 } qw( FILEATTACHMENT FIELD PREFERENCE ); +=cut -# Cache of the names of $Foswiki::cfg items that are accessible -our $isAccessibleCfg; +# These used to be declared here, but have been refactored back into +# Foswiki::Meta +*aliases = \%Foswiki::Meta::aliases; +*isArrayType = \%Foswiki::Meta::isArrayType; #