# ------------------------------------------------------- Monkey::BibTeX
package Monkey::BibTeX;
import Monkey;
$Monkey::Action{fullreference} = 'Monkey::BibTeX::FullReference';
$Monkey::Action{frombibtex} = 'Monkey::BibTeX::FromBibTeX';
$Monkey::Action{bibtex} = 'Monkey::BibTeX::Do';
$Monkey::Action{savebibtex} = 'Monkey::BibTeX::Save';
$Monkey::Action{referencesbibtex} = 'Monkey::BibTeX::ReferencesBibTeX';
our @BibTeXParameters = qw(
full_reference
bibtex
author
year
bibtitle
bibtype
journal
volume
issue
booktitle
edition
editor
location
date
institution
number
publisher
pages_start
pages_end
isbn
url
);
push @Monkey::QueryParameters, @BibTeXParameters;
sub Do
{
require Monkey::APAParser;
my %Page;
if( Monkey::Page::Exists($Parameter{id}) ) {
%Page = Monkey::Page::Open($Parameter{id}, $Parameter{revision});
foreach (@BibTeXParameters) {
$Parameter{$_} = $Page{$_} unless exists $Parameter{$_};
$Parameter{$_} = Monkey::APAParser->cleanup($Parameter{$_});
}
}
return ('bibtex', { page => \%Page });
}
sub FullReference
{
require Monkey::APAParser;
my $parser = Monkey::APAParser->new();
my $error = $parser->parse( $Parameter{full_reference} );
%Parameter = (%Parameter, %$parser) unless $error;
return ('bibtex');
}
sub FromBibTeX
{
require Text::BibTeX;
my $entry = new Text::BibTeX::Entry;
$entry->parse_s( $Parameter{bibtex} );
my $result = $entry->{values};
foreach (
[ author => 'author' ],
[ booktitle => 'booktitle' ],
[ chapter => 'chapter' ],
[ edition => 'edition' ],
[ editor => 'editor' ],
[ institution => 'institution' ],
[ journal => 'journal' ],
[ number => 'issue' ],
[ organization => 'institution' ],
[ publisher => 'publisher' ],
[ school => 'institution' ],
[ title => 'bibtitle' ],
[ volume => 'volume' ],
[ year => 'year' ],
[ ISBN => 'isbn' ],
[ ISSN => 'isbn' ],
[ URL => 'webpage' ],
) {
my ($from, $to) = @$_;
if( $result->{$from} =~ /\S/ ) {
$result->{$from} =~ s/[\{\}]//sg;
$Parameter{$to} = $result->{$from};
}
}
($Parameter{pages_start}, $Parameter{pages_end}) = ($1, $2)
if $result->{pages} =~ /(\d+)(?:\D+(\d+))?/;
$Parameter{bibtype} = $entry->type;
return ('bibtex');
}
sub ToBibTeX
{
require Monkey::APAParser;
my %Page = @_;
my %BibTeX;
my %map = (
(map { $_ => $_ } @BibTeXParameters),
issue => undef,
webpage => 'URL',
bibtitle => 'title',
isbn => undef,
institution => undef,
pages_start => undef,
pages_end => undef,
bibtype => undef,
bibtex => undef,
full_reference => undef,
);
foreach (@BibTeXParameters) {
next unless $map{$_};
$BibTeX{$map{$_}} = Monkey::APAParser->cleanup($Page{$_});
}
$BibTeX{number} = $Page{issue} if $Page{issue};
$BibTeX{keywords} = $Page{tags} if $Page{tags};
if( $Page{isbn} ) {
my $key = 'ISBN';
$key = 'ISSN' if $Page{bibtype} =~ /journal/i;
$BibTeX{$key} = $Page{isbn}
}
if( $Page{institution} ) {
$BibTeX{{
'phdthesis' => 'school',
'proceedings' => 'organization',
'inproceedings' => 'organization',
'techreport' => 'institution',
}->{$Page{bibtype}}} = $Page{institution};
}
if( $Page{pages_start} ) {
$BibTeX{pages} = $Page{pages_start};
$BibTeX{pages} .= '--' . $Page{pages_end} if $Page{pages_end};
}
if( $Page{tags} ) {
$BibTeX{keywords} = $Page{tags};
}
require Text::BibTeX::Bib;
my $entry = new Text::BibTeX::BibEntry;
$entry->set( %BibTeX );
my $type = $Page{bibtype} || 'misc';
$entry->set_type($type);
$entry->set_metatype(Text::BibTeX::Entry::BTE_REGULAR());
my @names = $entry->names('author');
my $authors = join '',
map { join '', $_->part('von'), $_->part('last') } @names;
$entry->set_key( $authors . $BibTeX{year} );
return $entry;
}
sub Save
{
require Monkey::APAParser;
return &Do unless $Parameter{submit} eq 'Save';
my @authors = grep $_, split /\s+and\s+|\b,\s+/, $Parameter{author};
$Parameter{author} = join ' and ', @authors;
my @editors = grep $_, split /\b\s*and\s+|\b,\s+/, $Parameter{editor};
$Parameter{editor} = join ' and ', @editors;
foreach(
[ (@authors || @editors || $Parameter{institution}), 'author' ],
[ $Parameter{year}, 'year' ],
[ $Parameter{bibtitle}, 'bibtitle' ],
[ $Parameter{bibtype}, 'bibtype' ],
[ $Parameter{bibtype} ne 'None of the above', 'bibtype' ],
) {
return ('bibtex', { required => $_->[1] }) unless $_->[0];
}
my $entry = ToBibTeX(%Parameter);
my $id = $Parameter{id};
unless( $id ) {
my @names = $entry->names('author');
my $authors = join ', ',
map { join ' ', $_->part('von'), $_->part('last') } @names;
$id = "$authors, $Parameter{year}";
$id =~ s/\s*$//;
while( Monkey::Page::Exists($id) ) {
if( $id =~ /\d{4}$/ ) { $id .= 'a'; }
elsif( $id =~ /n\.?d\.?$/ ) { $id = "n.d-a"; }
elsif( $id =~ s/(\P{IsAlpha})([a-z])$/my $a=$2; $1 . ++$a/e ) { 1; }
elsif( $id =~ /forthcoming$/ ) { $id = "forthcoming-a"; }
}
}
my %Page = (
Monkey::Page::Open($id),
summary => 'BibTeX updated',
map { $_ => Monkey::APAParser->cleanup($Parameter{$_}) } @BibTeXParameters,
);
delete $Page{$_} foreach(qw(full_reference bibtex));
return Monkey::Edit::Conflict()
unless %Page = Monkey::Page::Save( %Page );
Monkey::RecentChanges::Add( %Page );
return ( redirect => $Parameter{ScriptURL} . '?' . QuoteURL($id));
}
sub ReferencesBibTeX {
my %Page = Monkey::Page::Open($Parameter{id});
Monkey::Syntax::Translate( $Page{text} );
my $references = Monkey::BibIndex::References(Monkey::Syntax::Links());
my $text = join '', map {
Monkey::BibTeX::ToBibTeX( %$_ )->print_s . "\n\n"
} @$references;
return (
'raw',
$text,
{
type => 'text/plain',
'content-length' => length($text)
}
);
}
1;
package Text::BibTeX::Entry;
use Text::BibTeX qw(change_case);
use Text::BibTeX::NameFormat;
import Monkey;
sub apa {
my ($self) = @_;
my $type = $self->type;
return unless $type;
my $method = "apa_$type";
eval {
my $ref = $self->$method . $self->apa_url;
$ref =~ s/~/\ /sg;
$ref =~ s/\.\././s;
return $ref;
};
}
sub apa_book {
my ($self) = @_;
my @authors = $self->names('author');
my @editors = $self->names('editor');
my (undef, $Ed) = $self->apa_editors;
my ($authors, $editors);
if( @authors ) {
$authors = $self->apa_authors(@authors);
$editors = ' (' . $self->apa_editors(@editors) . ", $Ed)" if @editors;
}
elsif( @editors ) {
$authors = $self->apa_authors(@editors) . " ($Ed)";
}
return $authors
. $self->apa_year
. $self->apa_booktitle
. $editors
. '.'
. $self->apa_publisher;
}
sub apa_inbook {
my ($self) = @_;
my ($editors, $Ed) = $self->apa_editors;
return $self->apa_authors
. $self->apa_year
. QuoteHTML($self->{values}->{title}, 'pass entities')
. ". In $editors ($Ed), "
. $self->apa_booktitle
. $self->apa_pages('pp')
. '.'
. $self->apa_publisher;
}
sub apa_booktitle {
my ($self, $title) = @_;
($title) = grep $_, ($title, $self->{values}->{booktitle}, $self->{values}->{title});
$title = QuoteHTML($title, 'pass entities');
return "$title" . $self->apa_edition;
}
sub apa_article {
my ($self) = @_;
my ($title, $journal, $volume, $number) =
map { QuoteHTML( $self->{values}->{$_}, 'pass entities' ) }
qw( title journal volume number );
my $issue = "($number)" if length($number);
my $pages = $self->apa_pages;
$pages = ",$pages" if $pages;
return $self->apa_authors
. $self->apa_year
. "$title. $journal, $volume$issue$pages."
}
sub apa_proceedings {
my ($self) = @_;
my ($editors, $Ed) = $self->apa_editors;
return "$editors ($Ed)"
. $self->apa_year
. $self->apa_booktitle
. '.'
. $self->apa_publisher;
}
sub apa_inproceedings {
my ($self) = @_;
my %values = %{$self->{values}};
my ($editors, $Ed) = $self->apa_editors;
$editors .= ' ($Ed), ' if $editors;
return $self->apa_authors
. $self->apa_year('date')
. QuoteHTML($self->{values}->{title}, 'pass entities')
. ". In $editors"
. $self->apa_booktitle
. $self->apa_pages('pp')
. '.'
. $self->apa_publisher;
}
sub apa_techreport {
my ($self) = @_;
return $self->apa_institution
. $self->apa_year
. $self->apa_booktitle
. '. '
. (join ': ',
$self->apa_location,
$self->apa_editors($self->names('author')));
}
sub apa_webpage {
my ($self) = @_;
return $self->apa_book;
}
sub apa_url {
my ($self) = @_;
my $quoted = QuoteHTML($self->{values}->{URL});
if ($self->{values}->{URL}) {
return " Available from $quoted."
}
}
sub apa_year {
my ($self, $with_date) = @_;
my ($year, $date) = map { QuoteHTML($self->{values}->{$_}) } qw( year date );
$date =~ s/,?\s*\d{4}//; # lose the year;
$year .= ", $date" if $with_date;
return " ($year). ";
}
sub apa_authors {
my ($self, @authors) = @_;
@authors = $self->names('author') unless @authors;
my $formatter = new Text::BibTeX::NameFormat( 'vljf', 1 );
@authors = map { $formatter->apply($_) } @authors;
return $self->apa_namelist(@authors);
}
sub apa_editors {
my ($self, @editors) = @_;
@editors = $self->names('editor') unless @editors;
my $formatter = new Text::BibTeX::NameFormat( 'fvlj', 1 );
@editors = map { $formatter->apply($_) } @editors;
my $Ed = @editors > 1 ? 'Eds.' : 'Ed.';
my $names = $self->apa_namelist(@editors);
return ($names, $Ed) if wantarray;
return $names;
}
sub apa_namelist {
my ($self, @names) = @_;
$names[$#names] = "& $names[$#names]"
if @names > 1 && $names[$#names] !~ /^et\b/i;
return QuoteHTML( (join ', ', @names), 'pass entities' );
}
sub apa_edition {
my ($self) = @_;
my $edition = QuoteHTML($self->{values}->{edition}, 'pass entities');
return " ($edition ed.)" if $edition;
}
sub apa_pages {
my ($self, $pp) = @_;
my $pages = QuoteHTML($self->{values}->{pages}, 'pass entities');
return unless $pages;
$pages =~ s/--/-/;
if( $pp ) {
my $pp = 'p';
$pp = 'pp' if $pages =~ /-/;
return " ($pp. $pages)";
}
return " $pages";
}
sub apa_institution {
my ($self) = @_;
my @institutions = grep $_, map { QuoteHTML($self->{values}->{$_}, 'pass entities') } qw( institution school organization );
return shift @institutions;
}
sub apa_location {
my ($self) = @_;
if( $self->{values}->{location} ) {
return QuoteHTML( $self->{values}->{location}, 'pass entities' );
}
}
sub apa_publisher {
my ($self) = @_;
my $result = join ': ', grep $_,
$self->apa_location,
QuoteHTML($self->{values}->{publisher}, 'pass entities');
return " $result." if $result =~ /\S/;
}
1;