summaryrefslogtreecommitdiff
path: root/.library/IkiWiki/Plugin/field.pm
diff options
context:
space:
mode:
authorThomas Schwinge <thomas@codesourcery.com>2012-05-24 23:08:09 +0200
committerThomas Schwinge <thomas@codesourcery.com>2012-05-24 23:08:09 +0200
commit2910b7c5b1d55bc304344b584a25ea571a9075fb (patch)
treebfbfbc98d4c0e205d2726fa44170a16e8421855e /.library/IkiWiki/Plugin/field.pm
parent35b719f54c96778f571984065579625bc9f15bf5 (diff)
Prepare toolchain/logs/master branch.
Diffstat (limited to '.library/IkiWiki/Plugin/field.pm')
-rw-r--r--.library/IkiWiki/Plugin/field.pm722
1 files changed, 0 insertions, 722 deletions
diff --git a/.library/IkiWiki/Plugin/field.pm b/.library/IkiWiki/Plugin/field.pm
deleted file mode 100644
index d77e7282..00000000
--- a/.library/IkiWiki/Plugin/field.pm
+++ /dev/null
@@ -1,722 +0,0 @@
-#!/usr/bin/perl
-# Ikiwiki field plugin.
-# See doc/plugin/contrib/field.mdwn for documentation.
-package IkiWiki::Plugin::field;
-use warnings;
-use strict;
-=head1 NAME
-
-IkiWiki::Plugin::field - front-end for per-page record fields.
-
-=head1 VERSION
-
-This describes version B<1.20101101> of IkiWiki::Plugin::field
-
-=cut
-
-our $VERSION = '1.20101115';
-
-=head1 PREREQUISITES
-
- IkiWiki
-
-=head1 AUTHOR
-
- Kathryn Andersen (RUBYKAT)
- http://github.com/rubykat
-
-=head1 COPYRIGHT
-
-Copyright (c) 2009-2010 Kathryn Andersen
-
-This program is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
-
-=cut
-
-use IkiWiki 3.00;
-
-my %Fields = (
- _first => {
- id => '_first',
- seq => 'BB',
- },
- _last => {
- id => '_last',
- seq => 'YY',
- },
- _middle => {
- id => '_middle',
- seq => 'MM',
- },
-);
-my @FieldsLookupOrder = ();
-
-my %Cache = ();
-
-sub field_get_value ($$);
-
-sub import {
- hook(type => "getsetup", id => "field", call => \&getsetup);
- hook(type => "checkconfig", id => "field", call => \&checkconfig);
- hook(type => "scan", id => "field", call => \&scan, last=>1);
- hook(type => "pagetemplate", id => "field", call => \&pagetemplate);
-}
-
-# ===============================================
-# Hooks
-# ---------------------------
-sub getsetup () {
- return
- plugin => {
- safe => 1,
- rebuild => undef,
- },
- field_register => {
- type => "hash",
- example => "field_register => {meta => 'last'}",
- description => "simple registration of fields by plugin",
- safe => 0,
- rebuild => undef,
- },
- field_allow_config => {
- type => "boolean",
- example => "field_allow_config => 1",
- description => "allow config settings to be queried",
- safe => 0,
- rebuild => undef,
- },
- field_tags => {
- type => "hash",
- example => "field_tags => {BookAuthor => '/books/authors'}",
- description => "fields flagged as tag-fields",
- safe => 0,
- rebuild => undef,
- },
-}
-
-sub checkconfig () {
- # use the simple by-plugin pagestatus method for
- # those plugins registered with the field_register config option.
- if (defined $config{field_register})
- {
- if (ref $config{field_register} eq 'ARRAY')
- {
- foreach my $id (@{$config{field_register}})
- {
- field_register(id=>$id);
- }
- }
- elsif (ref $config{field_register} eq 'HASH')
- {
- foreach my $id (keys %{$config{field_register}})
- {
- field_register(id=>$id, order=>$config{field_register}->{$id});
- }
- }
- else
- {
- field_register(id=>$config{field_register});
- }
- }
- if (!defined $config{field_allow_config})
- {
- $config{field_allow_config} = 0;
- }
-} # checkconfig
-
-sub scan (@) {
- my %params=@_;
- my $page=$params{page};
- my $content=$params{content};
-
- # scan for tag fields
- if ($config{field_tags})
- {
- foreach my $field (keys %{$config{field_tags}})
- {
- my @values = field_get_value($field, $page);
- if (@values)
- {
- foreach my $tag (@values)
- {
- if ($tag)
- {
- my $link = $config{field_tags}{$field} . '/'
- . titlepage($tag);
- add_link($page, $link, lc($field));
- }
- }
- }
- }
- }
-} # scan
-
-sub pagetemplate (@) {
- my %params=@_;
- my $page=$params{page};
- my $template=$params{template};
-
- field_set_template_values($template, $page);
-} # pagetemplate
-
-# ===============================================
-# Field interface
-# ---------------------------
-
-sub field_register (%) {
- my %param=@_;
- if (!exists $param{id})
- {
- error 'field_register requires id parameter';
- return 0;
- }
- if (exists $param{call} and !ref $param{call})
- {
- error 'field_register call parameter must be function';
- return 0;
- }
-
- my $id = $param{id};
- $Fields{$id} = \%param;
-
- # add this to the ordering hash
- # first, last, order; by default, middle
- my $when = ($param{first}
- ? '_first'
- : ($param{last}
- ? '_last'
- : ($param{order}
- ? ($param{order} eq 'first'
- ? '_first'
- : ($param{order} eq 'last'
- ? '_last'
- : ($param{order} eq 'middle'
- ? '_middle'
- : $param{order}
- )
- )
- )
- : '_middle'
- )
- ));
- add_lookup_order($id, $when);
- return 1;
-} # field_register
-
-sub field_get_value ($$) {
- my $field_name = shift;
- my $page = shift;
-
- # This will return the first value it finds
- # where the value returned is not undefined.
- # This will return an array of values if wantarray is true.
-
- # The reason why it checks every registered plugin rather than have
- # plugins declare which fields they know about, is that it is quite
- # possible that a plugin doesn't know, ahead of time, what fields
- # will be available; for example, a YAML format plugin would return
- # any field that happens to be defined in a YAML page file, which
- # could be anything!
-
- # check the cache first
- my $lc_field_name = lc($field_name);
- if (wantarray)
- {
- if (exists $Cache{$page}{$lc_field_name}{array}
- and defined $Cache{$page}{$lc_field_name}{array})
- {
- return @{$Cache{$page}{$lc_field_name}{array}};
- }
- }
- else
- {
- if (exists $Cache{$page}{$lc_field_name}{scalar}
- and defined $Cache{$page}{$lc_field_name}{scalar})
- {
- return $Cache{$page}{$lc_field_name}{scalar};
- }
- }
-
- if (!@FieldsLookupOrder)
- {
- build_fields_lookup_order();
- }
-
- # Get either the scalar or the array value depending
- # on what is requested - don't get both because it wastes time.
- if (wantarray)
- {
- my @array_value = undef;
- foreach my $id (@FieldsLookupOrder)
- {
- # get the data from the pagestate hash if it's there
- if (exists $pagestate{$page}{$id}{$field_name}
- and defined $pagestate{$page}{$id}{$field_name})
- {
- @array_value = (ref $pagestate{$page}{$id}{$field_name}
- ? @{$pagestate{$page}{$id}{$field_name}}
- : ($pagestate{$page}{$id}{$field_name}));
- }
- elsif (exists $pagestate{$page}{$id}{$lc_field_name}
- and defined $pagestate{$page}{$id}{$lc_field_name})
- {
- @array_value = (ref $pagestate{$page}{$id}{$lc_field_name}
- ? @{$pagestate{$page}{$id}{$lc_field_name}}
- : ($pagestate{$page}{$id}{$lc_field_name}));
- }
- elsif (exists $Fields{$id}{call})
- {
- @array_value = $Fields{$id}{call}->($field_name, $page);
- }
- if (@array_value and $array_value[0])
- {
- last;
- }
- }
- if (!@array_value)
- {
- @array_value = field_calculated_values($field_name, $page);
- }
- # cache the value
- $Cache{$page}{$lc_field_name}{array} = \@array_value;
- return @array_value;
- }
- else # scalar
- {
- my $value = undef;
- foreach my $id (@FieldsLookupOrder)
- {
- # get the data from the pagestate hash if it's there
- # but only if it's already a scalar
- if (exists $pagestate{$page}{$id}{$field_name}
- and !ref $pagestate{$page}{$id}{$field_name})
- {
- $value = $pagestate{$page}{$id}{$field_name};
- }
- elsif (exists $pagestate{$page}{$id}{$lc_field_name}
- and !ref $pagestate{$page}{$id}{$lc_field_name})
- {
- $value = $pagestate{$page}{$id}{$lc_field_name};
- }
- elsif (exists $Fields{$id}{call})
- {
- $value = $Fields{$id}{call}->($field_name, $page);
- }
- if (defined $value)
- {
- last;
- }
- }
- if (!defined $value)
- {
- $value = field_calculated_values($field_name, $page);
- }
- # cache the value
- $Cache{$page}{$lc_field_name}{scalar} = $value;
- return $value;
- }
-
- return undef;
-} # field_get_value
-
-# set the values for the given HTML::Template template
-sub field_set_template_values ($$;@) {
- my $template = shift;
- my $page = shift;
- my %params = @_;
-
- my $get_value_fn = (exists $params{value_fn}
- ? $params{value_fn}
- : \&field_get_value);
-
- # Find the parameter names in this template
- # and see if you can find their values.
-
- # The reason we check the template for field names is because we
- # don't know what fields the registered plugins provide; and this is
- # reasonable because for some plugins (e.g. a YAML data plugin) they
- # have no way of knowing, ahead of time, what fields they might be
- # able to provide.
-
- my @parameter_names = $template->param();
- foreach my $field (@parameter_names)
- {
- # Don't redefine if the field already has a value set.
- next if ($template->param($field));
-
- my $type = $template->query(name => $field);
- if ($type eq 'LOOP' and $field =~ /_LOOP$/oi)
- {
- # Loop fields want arrays.
- # Figure out what field names to look for:
- # * names are from the enclosed loop fields
- my @loop_fields = $template->query(loop => $field);
-
- my @loop_vals = ();
- my %loop_field_arrays = ();
- foreach my $fn (@loop_fields)
- {
- if ($fn !~ /^__/o) # not a special loop variable
- {
- my @ival_array = $get_value_fn->($fn, $page);
- if (@ival_array)
- {
- $loop_field_arrays{$fn} = \@ival_array;
- }
- }
- }
- foreach my $fn (sort keys %loop_field_arrays)
- {
- my $i = 0;
- foreach my $v (@{$loop_field_arrays{$fn}})
- {
- if (!defined $loop_vals[$i])
- {
- $loop_vals[$i] = {};
- }
- $loop_vals[$i]{$fn} = $v;
- $i++;
- }
- }
- $template->param($field => \@loop_vals);
- }
- else # not a loop field
- {
- my $value = $get_value_fn->($field, $page);
- if (defined $value)
- {
- $template->param($field => $value);
- }
- }
- }
-} # field_set_template_values
-
-# ===============================================
-# Private Functions
-# ---------------------------
-
-# Calculate the lookup order
-# <module, >module, AZ
-# This is crabbed from the PmWiki Markup function
-sub add_lookup_order {
- my $id = shift;
- my $when = shift;
-
- # may have given an explicit ordering
- if ($when =~ /^[A-Z][A-Z]$/o)
- {
- $Fields{$id}{seq} = $when;
- }
- else
- {
- my $cmp = '=';
- my $seq_field = $when;
- if ($when =~ /^([<>])(.+)$/o)
- {
- $cmp = $1;
- $seq_field = $2;
- }
- $Fields{$seq_field}{dep}{$id} = $cmp;
- if (exists $Fields{$seq_field}{seq}
- and defined $Fields{$seq_field}{seq})
- {
- $Fields{$id}{seq} = $Fields{$seq_field}{seq} . $cmp;
- }
- }
- if ($Fields{$id}{seq})
- {
- foreach my $i (keys %{$Fields{$id}{dep}})
- {
- my $m = $Fields{$id}{dep}{$i};
- add_lookup_order($i, "$m$id");
- }
- delete $Fields{$id}{dep};
- }
-}
-
-sub build_fields_lookup_order {
-
- # remove the _first, _last and _middle dummy fields
- # because we don't need them anymore
- delete $Fields{_first};
- delete $Fields{_last};
- delete $Fields{_middle};
- my %lookup_spec = ();
- # Make a hash of the lookup sequences
- foreach my $id (sort keys %Fields)
- {
- my $seq = ($Fields{$id}{seq}
- ? $Fields{$id}{seq}
- : 'MM');
- if (!exists $lookup_spec{$seq})
- {
- $lookup_spec{$seq} = {};
- }
- $lookup_spec{$seq}{$id} = 1;
- }
-
- # get the field-lookup order by (a) sorting by lookup_spec
- # and (b) sorting by field-name for the fields that registered
- # the same field-lookup order
- foreach my $ord (sort keys %lookup_spec)
- {
- push @FieldsLookupOrder, sort keys %{$lookup_spec{$ord}};
- }
-} # build_fields_lookup_order
-
-# standard values deduced from other values
-sub field_calculated_values {
- my $field_name = shift;
- my $page = shift;
-
- my $value = undef;
-
- # Exception for titles
- # If the title hasn't been found, construct it
- if ($field_name eq 'title')
- {
- $value = pagetitle(IkiWiki::basename($page));
- }
- # and set "page" if desired
- elsif ($field_name eq 'page')
- {
- $value = $page;
- }
- # the page above this page; aka the current directory
- elsif ($field_name eq 'parent_page')
- {
- if ($page =~ m{^(.*)/[-\.\w]+$}o)
- {
- $value = $1;
- }
- }
- elsif ($field_name eq 'basename')
- {
- $value = IkiWiki::basename($page);
- }
- elsif ($config{field_allow_config}
- and $field_name =~ /^config-(.*)$/oi)
- {
- my $cfield = $1;
- if (exists $config{$cfield})
- {
- $value = $config{$cfield};
- }
- }
- elsif ($field_name =~ /^(.*)-tagpage$/o)
- {
- my @array_value = undef;
- my $real_fn = $1;
- if (exists $config{field_tags}{$real_fn}
- and defined $config{field_tags}{$real_fn})
- {
- my @values = field_get_value($real_fn, $page);
- if (@values)
- {
- foreach my $tag (@values)
- {
- if ($tag)
- {
- my $link = $config{field_tags}{$real_fn} . '/' . $tag;
- push @array_value, $link;
- }
- }
- if (wantarray)
- {
- return @array_value;
- }
- else
- {
- $value = join(",", @array_value) if $array_value[0];
- }
- }
- }
- }
- return (wantarray ? ($value) : $value);
-} # field_calculated_values
-
-# match field funcs
-# page-to-check, wanted
-sub match_a_field ($$) {
- my $page=shift;
- my $wanted=shift;
-
- # The field name is first; the rest is the match
- my $field_name;
- my $glob;
- if ($wanted =~ /^(\w+)\s+(.*)$/o)
- {
- $field_name = $1;
- $glob = $2;
- }
- else
- {
- return IkiWiki::FailReason->new("cannot match field");
- }
-
- # turn glob into a safe regexp
- my $re=IkiWiki::glob2re($glob);
-
- my $val = IkiWiki::Plugin::field::field_get_value($field_name, $page);
-
- if (defined $val) {
- if ($val=~/^$re$/i) {
- return IkiWiki::SuccessReason->new("$re matches $field_name of $page", $page => $IkiWiki::DEPEND_CONTENT, "" => 1);
- }
- else {
- return IkiWiki::FailReason->new("$re does not match $field_name of $page", "" => 1);
- }
- }
- else {
- return IkiWiki::FailReason->new("$page does not have a $field_name", "" => 1);
- }
-} # match_a_field
-
-# check against individual items of a field
-# (treat the field as an array)
-# page-to-check, wanted
-sub match_a_field_item ($$) {
- my $page=shift;
- my $wanted=shift;
-
- # The field name is first; the rest is the match
- my $field_name;
- my $glob;
- if ($wanted =~ /^(\w+)\s+(.*)$/o)
- {
- $field_name = $1;
- $glob = $2;
- }
- else
- {
- return IkiWiki::FailReason->new("cannot match field");
- }
-
- # turn glob into a safe regexp
- my $re=IkiWiki::glob2re($glob);
-
- my @val_array = IkiWiki::Plugin::field::field_get_value($field_name, $page);
-
- if (@val_array)
- {
- foreach my $val (@val_array)
- {
- if (defined $val) {
- if ($val=~/^$re$/i) {
- return IkiWiki::SuccessReason->new("$re matches $field_name of $page", $page => $IkiWiki::DEPEND_CONTENT, "" => 1);
- }
- }
- }
- # not found
- return IkiWiki::FailReason->new("$re does not match $field_name of $page", "" => 1);
- }
- else {
- return IkiWiki::FailReason->new("$page does not have a $field_name", "" => 1);
- }
-} # match_a_field_item
-
-# ===============================================
-# PageSpec functions
-# ---------------------------
-
-package IkiWiki::PageSpec;
-
-sub match_field ($$;@) {
- my $page=shift;
- my $wanted=shift;
- return IkiWiki::Plugin::field::match_a_field($page, $wanted);
-} # match_field
-
-sub match_destfield ($$;@) {
- my $page=shift;
- my $wanted=shift;
- my %params=@_;
-
- return IkiWiki::FailReason->new("cannot match destpage") unless exists $params{destpage};
-
- # Match the field on the destination page, not the source page
- return IkiWiki::Plugin::field::match_a_field($params{destpage}, $wanted);
-} # match_destfield
-
-sub match_field_item ($$;@) {
- my $page=shift;
- my $wanted=shift;
- return IkiWiki::Plugin::field::match_a_field_item($page, $wanted);
-} # match_field
-
-sub match_destfield_item ($$;@) {
- my $page=shift;
- my $wanted=shift;
- my %params=@_;
-
- return IkiWiki::FailReason->new("cannot match destpage") unless exists $params{destpage};
-
- # Match the field on the destination page, not the source page
- return IkiWiki::Plugin::field::match_a_field_item($params{destpage}, $wanted);
-} # match_destfield
-
-sub match_field_tagged ($$;@) {
- my $page=shift;
- my $wanted=shift;
- my %params=@_;
-
- # The field name is first; the rest is the match
- my $field_name;
- my $glob;
- if ($wanted =~ /^(\w+)\s+(.*)$/o)
- {
- $field_name = $1;
- $glob = $2;
- }
- else
- {
- return IkiWiki::FailReason->new("cannot match field");
- }
- return match_link($page, $glob, linktype => lc($field_name), @_);
-}
-
-sub match_destfield_tagged ($$;@) {
- my $page=shift;
- my $wanted=shift;
- my %params=@_;
-
- return IkiWiki::FailReason->new("cannot match destpage") unless exists $params{destpage};
-
- # Match the field on the destination page, not the source page
- return IkiWiki::Plugin::field::match_field_tagged($params{destpage}, $wanted);
-}
-
-# ===============================================
-# SortSpec functions
-# ---------------------------
-package IkiWiki::SortSpec;
-
-sub cmp_field {
- my $field = shift;
- error(gettext("sort=field requires a parameter")) unless defined $field;
-
- my $left = IkiWiki::Plugin::field::field_get_value($field, $a);
- my $right = IkiWiki::Plugin::field::field_get_value($field, $b);
-
- $left = "" unless defined $left;
- $right = "" unless defined $right;
- return $left cmp $right;
-}
-
-sub cmp_field_natural {
- my $field = shift;
- error(gettext("sort=field requires a parameter")) unless defined $field;
-
- eval q{use Sort::Naturally};
- error $@ if $@;
-
- my $left = IkiWiki::Plugin::field::field_get_value($field, $a);
- my $right = IkiWiki::Plugin::field::field_get_value($field, $b);
-
- $left = "" unless defined $left;
- $right = "" unless defined $right;
- return Sort::Naturally::ncmp($left, $right);
-}
-
-1;