Skip to content

Commit

Permalink
Item9948: reverted the rgeisterMETA API to reflect the original inten…
Browse files Browse the repository at this point in the history
…t. 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
  • Loading branch information
CrawfordCurrie authored and CrawfordCurrie committed Nov 4, 2010
1 parent aca0f25 commit b5392fc
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 106 deletions.
22 changes: 13 additions & 9 deletions UnitTestContrib/test/unit/MetaTests.pm
Expand Up @@ -564,23 +564,23 @@ 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' }));
$this->assert($o->isValidEmbedding(
'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' }));
$this->assert($o->isValidEmbedding(
'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);
Expand All @@ -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) = @_;
Expand All @@ -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);
Expand All @@ -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';
Expand All @@ -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 =
Expand All @@ -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
}
Expand All @@ -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';
Expand All @@ -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 =
Expand All @@ -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
}
Expand Down
5 changes: 4 additions & 1 deletion core/data/System/QuerySearch.txt
Expand Up @@ -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.

Expand All @@ -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* |
Expand Down
67 changes: 4 additions & 63 deletions core/lib/Foswiki/Func.pm
Expand Up @@ -674,73 +674,14 @@ sub registerRESTHandler {

=begin TML
---+++ registerMETA($name, $type, %syntax)
Foswiki supports embedding meta-data into topics. For example,
=%<nop>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:
<verbatim>
registerMETA('BOOK', function => sub {
my ($name, $args) = @_;
# $name will be BOOK
return defined $args->{title};
}
</verbatim>
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,
<verbatim>
registerMETA('BOOK', require => [ 'title', 'author' ]);
</verbatim>
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:
<verbatim>
registerMETA('BOOK',
function => \&checkParameters,
require => [ 'title' ],
allow => [ 'author', 'isbn' ]);
</verbatim>
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
Expand Down
126 changes: 113 additions & 13 deletions core/lib/Foswiki/Meta.pm
Expand Up @@ -136,31 +136,40 @@ 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 => [
qw( author version date format reprev
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
# erroneously generated at some point in the past
TOPICPARENT => {
allow => [qw( name )],
_default => 1,
alias => 'parent',
},
FILEATTACHMENT => {
require => [qw( name )],
Expand All @@ -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,
=%<nop>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:
<verbatim>
registerMeta('BOOK', many => 1)
</verbatim>
=require=>[]= is used to check that a list of named parameters are present on
the tag. For example,
<verbatim>
registerMETA('BOOK', require => [ 'title', 'author' ]);
</verbatim>
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:
<verbatim>
registerMETA('BOOK', function => sub {
my ($name, $args) = @_;
# $name will be BOOK
return isValidTitle($args->{title});
}
</verbatim>
can be used to check that =%META:BOOK{}= contains a valid title.
Checks are cumulative, so if you:
<verbatim>
registerMETA('BOOK',
function => \&checkParameters,
require => [ 'title' ],
allow => [ 'author', 'isbn' ]);
</verbatim>
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.
<verbatim>
registerMeta('BOOK', alias => 'book', many => 1)
</verbatim>
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 #############
Expand Down

0 comments on commit b5392fc

Please sign in to comment.