File Coverage

blib/lib/Text/BibTeX/BibFormat.pm
Criterion Covered Total %
statement 90 117 76.9
branch 26 60 43.3
condition 7 12 58.3
subroutine 21 24 87.5
pod 1 17 5.8
total 145 230 63.0


line stmt bran cond sub pod time code
1             # ----------------------------------------------------------------------
2             # NAME : BibFormat.pm
3             # CLASSES : Text::BibTeX::BibFormat
4             # RELATIONS : sub-class of Text::BibTeX::StructuredEntry
5             # super-class of Text::BibTeX::BibEntry
6             # DESCRIPTION: Provides methods for final output formatting of
7             # bibliographic entries.
8             # CREATED : 1997/11/24, GPW
9             # MODIFIED :
10             # VERSION : $Id$
11             # COPYRIGHT : Copyright (c) 1997 by Gregory P. Ward. All rights reserved.
12             #
13             # This file is part of the Text::BibTeX library. This is free
14             # software; you can redistribute it and/or modify it under the
15             # same terms as Perl itself.
16             # ----------------------------------------------------------------------
17              
18             package Text::BibTeX::BibFormat;
19              
20 1     1   7 use Carp;
  1         2  
  1         114  
21 1     1   8 use strict;
  1         2  
  1         24  
22 1     1   5 use vars qw(@ISA $VERSION);
  1         1  
  1         44  
23              
24 1     1   6 use Text::BibTeX::Name;
  1         2  
  1         29  
25 1     1   7 use Text::BibTeX::NameFormat;
  1         1  
  1         35  
26 1     1   6 use Text::BibTeX::Structure;
  1         2  
  1         61  
27              
28             @ISA = qw(Text::BibTeX::StructuredEntry);
29             $VERSION = 0.88;
30              
31 1     1   7 use Text::BibTeX qw(:subs display_list :nameparts :joinmethods);
  1         2  
  1         1701  
32              
33             =head1 NAME
34              
35             Text::BibTeX::BibFormat - formats bibliography entries
36              
37             =head1 SYNOPSIS
38              
39             # Assuming $entry comes from a database of the 'Bib' structure
40             # (i.e., that it's blessed into the BibEntry class, which inherits
41             # the format method from BibFormat):
42             @blocks = $entry->format;
43              
44             =head1 DESCRIPTION
45              
46             The C class is a base class of
47             C for formatting bibliography entries. It thus
48             performs the main job of any program that would hope to supplant BibTeX
49             itself; the other important job (sorting) is handled by its companion
50             class, C.
51              
52             C (the C prefix will be dropped for brevity)
53             pays attention to almost all of the structure options described in
54             L; it only ignores those that cover sorting,
55             currently just C. In particular, all of the "markup" options
56             control what language is generated by C; if none of those
57             options are set, then it will generate plain, unmarked text.
58              
59             The only method in C's documented interface (so far) is
60             C. (The class defines many other methods, but these should not
61             be necessary to outsiders, so they are undocumented and subject to
62             change.)
63              
64             =head1 METHODS
65              
66             =over 4
67              
68             =cut
69              
70             # ----------------------------------------------------------------------
71             # Ordinary subroutines:
72              
73             sub connect_words
74             {
75 0     0 0 0 my ($s1, $s2) = @_;
76              
77 0 0       0 return $s1 . ((length ($s2) < 3) ? '~' : ' ') . $s2;
78             }
79              
80              
81             # ----------------------------------------------------------------------
82             # Utility methods (eg. apply a bit of markup to a string or field)
83              
84             sub markup_field
85             {
86 2     2 0 6 my ($self, $markup, $field) = @_;
87              
88 2 50 33     11 $markup = $self->structure->get_options ("${markup}_mkup")
89             unless (ref $markup eq 'ARRAY' && @$markup == 2);
90 2 50       6 croak "${markup}_mkup option not defined"
91             unless defined $markup;
92              
93 2 50       6 $self->exists ($field)
94             ? $markup->[0] . $self->get ($field) . $markup->[1]
95             : '';
96             }
97              
98              
99             sub markup_string
100             {
101 23     23 0 46 my ($self, $markup, $string) = @_;
102              
103 23 50 33     76 $markup = $self->structure->get_options ("${markup}_mkup")
104             unless (ref $markup eq 'ARRAY' && @$markup == 2);
105 23 50       47 croak "${markup}_mkup option not defined"
106             unless defined $markup;
107              
108 23         99 $markup->[0] . $string . $markup->[1];
109             }
110              
111              
112             # ----------------------------------------------------------------------
113             # Formatting methods I: utility methods called by the entry-formatters
114              
115             sub format_authors
116             {
117 9     9 0 11 my $self = shift;
118              
119 9 50       24 return '' unless $self->exists ('author');
120 9         30 my @authors = $self->names ('author');
121 9         27 $self->format_names (\@authors)
122             }
123              
124              
125             sub format_editors
126             {
127 0     0 0 0 my $self = shift;
128              
129             # The word used to indicate editorship should be customizable --
130             # might want it in another language, or abbreviated, or both.
131 0 0       0 return '' unless $self->exists ('editor');
132 0         0 my @editors = $self->names ('editor');
133 0 0       0 my $tackon = (@editors == 1) ? ', editor' : ', editors';
134 0         0 $self->format_names (\@editors) . $tackon;
135             }
136              
137              
138             sub format_names
139             {
140 9     9 0 16 my ($self, $names) = @_;
141 9         12 my ($format, $name);
142              
143 9         29 my ($order, $style) =
144             $self->structure->get_options ('nameorder', 'namestyle');
145 9 50 66     44 croak "format_names: bad nameorder option \"$order\""
146             unless $order eq 'first' || $order eq 'last';
147 9 50       50 croak "format_names: bad namestyle option \"$style\""
148             unless $style =~ /^(full|abbrev|nopunct|nospace)$/;
149              
150 9 100       20 $order = ($order eq 'first') ? 'fvlj' : 'vljf';
151 9         40 $format = Text::BibTeX::NameFormat->new ($order, ! ($style eq 'full'));
152              
153 9 100 100     106 $format->set_text (&BTN_FIRST, undef, undef, undef, '')
154             if $style eq 'nopunct' || $style eq 'nospace';
155 9 100       67 $format->set_options (&BTN_FIRST, 1, &BTJ_NOTHING, &BTJ_SPACE)
156             if $style eq 'nospace';
157              
158 9         20 foreach $name (@$names)
159             {
160 16         36 $name = $name->format ($format);
161 16 50       56 $name = 'et. al.' if $name eq 'others';
162             }
163              
164 9         24 return $self->markup_string ('name', display_list($names,0));
165             }
166              
167              
168             sub format_atitle
169             {
170 7     7 0 14 my $self = shift;
171              
172 7         14 my $lower = $self->structure->get_options ('atitle_lower');
173 7         28 my $title = $self->get ('title');
174 7 100       36 $title = change_case ('t', $title) if $lower;
175 7         14 $self->markup_string ('atitle', $title);
176             # $markup->[0] . $title . $markup->[1];
177             }
178              
179              
180             sub format_btitle
181             {
182 2     2 0 4 my $self = shift;
183              
184 2         9 $self->markup_field ('btitle', 'title');
185             # my $markup = $self->structure->get_options ('btitle_mkup');
186             # my $title = $self->get ('title');
187             # $markup->[0] . $title . $markup->[1];
188             }
189              
190              
191             # sub format_xref_article
192             # {
193             # my $self = shift;
194              
195             # # N.B. this assumes that the appropriate fields from the cross-
196             # # referenced entry have already been put into the current entry!
197              
198             # # XXX hard-coded LaTeX markup here!!!
199              
200             # my ($key, $journal, $crossref);
201             # $key = $self->get ('key');
202             # $journal = $self->get ('journal');
203             # $crossref = $self->get ('crossref');
204             # if (defined $key)
205             # {
206             # return "In $key \cite{$crossref}";
207             # }
208             # else
209             # {
210             # if (defined $journal)
211             # {
212             # return "In {\em $journal} \cite{$crossref}";
213             # }
214             # else
215             # {
216             # $self->warn ("need key or journal for crossref");
217             # return " \cite{$crossref}";
218             # }
219             # }
220             # }
221              
222              
223             sub format_pages
224             {
225 0     0 0 0 my $self = shift;
226              
227 0         0 my $pages = $self->get ('pages');
228 0 0       0 if ($pages =~ /[,+-]/) # multiple pages?
229             {
230 0         0 $pages =~ s/([^-])-([^-])/$1--$2/g;
231 0         0 return connect_words ("pages", $pages);
232             }
233             else
234             {
235 0         0 return connect_words ("page", $pages);
236             }
237             }
238              
239              
240             sub format_vol_num_pages
241             {
242 7     7 0 13 my $self = shift;
243              
244 7         12 my ($vol, $num, $pages) = $self->get ('volume', 'number', 'pages');
245 7         14 my $vnp = '';
246 7 50       17 $vnp .= $vol if defined $vol;
247 7 50       16 $vnp .= "($num)" if defined $num;
248 7 50       24 $vnp .= ":$pages" if defined $pages;
249 7         24 return $vnp;
250             }
251              
252              
253             sub format_bvolume
254             {
255 2     2 0 5 my $self = shift;
256 2         3 my $volser; # potentially volume and series
257              
258 2 50       5 if ($self->exists ('volume'))
259             {
260 0         0 $volser = connect_words ('volume', $self->get ('volume'));
261 0 0       0 $volser .= ' of ' . $self->markup_field ('btitle', 'series')
262             if $self->exists ('series');
263 0         0 return $volser;
264             }
265             else
266             {
267 2         6 return '';
268             }
269             }
270              
271              
272             sub format_number_series
273             {
274 2     2 0 4 my ($self, $mid_sentence) = @_;
275              
276 2 50       6 if ($self->exists ('volume'))
277             {
278             # if 'volume' field exists, then format_bvolume took care of
279             # formatting it, so don't do anything here
280 0         0 return '';
281             }
282             else
283             {
284 2 50       5 if ($self->exists ('number'))
285             {
286 0         0 my $numser;
287              
288 0 0       0 $numser = connect_words ($mid_sentence ? 'number' : 'Number',
289             $self->get ('number'));
290 0 0       0 if ($self->exists ('series'))
291             {
292 0         0 $numser .= ' in ' . $self->get ('series');
293             }
294             else
295             {
296 0         0 $self->warn ("there's a number but no series " .
297             "(is this warning redundant?!?)");
298             }
299 0         0 return $numser;
300             }
301             else
302             {
303             # No 'number' -- just return the 'series' (or undef if none)
304 2         7 return $self->get ('series');
305             }
306             } # no 'volume' field
307             } # format_number_series
308              
309              
310             sub format_edition
311             {
312 2     2 0 3 my ($self, $mid_sentence) = @_;
313              
314             # XXX more fodder for I18N here: the word 'edition'
315 2 50       6 return '' unless $self->exists ('edition');
316 0 0       0 my $case_transform = $mid_sentence ? 'l' : 't';
317 0         0 return change_case ($case_transform, $self->get ('edition')) . ' edition';
318              
319             } # format_edition
320              
321              
322             sub format_date
323             {
324 9     9 0 15 my $self = shift;
325              
326 9         20 my @date = grep ($_, $self->get ('month', 'year'));
327 9         38 return join (' ', @date);
328             }
329              
330              
331             # ----------------------------------------------------------------------
332             # The actual entry-formatting methods:
333             # format_article
334             # format_book
335             # format_inbook
336             # ...and so on.
337              
338             # Each of these returns a list of blocks.
339             # A block is a list of sentences.
340             # A sentence is either a string or a list of clauses.
341             # Any clause, sentence, or block in any list may be empty or undefined;
342             # it should be removed before output.
343             # If a sentence consists of a list of clauses, they should be joined
344             # together with ", " to form the sentence-as-string.
345             #
346             # For example, the formatted entry for an article (in the absence of
347             # cross-references) consists of four blocks:
348             # - the name block, which has a single sentence; this sentence
349             # has a single clause (the list of author names), and thus is
350             # represented as a string like "Joe Blow, Fred Jones, and John Smith"
351             # - the title block, which has a single sentence; this sentence
352             # has a single clause, the title of the article, eg. "The mating
353             # habits of foobars"
354             # - the journal block, which consists of a single sentence that has
355             # three clauses: the journal name, the volume/number/pages, and
356             # the date. When the three clauses are joined, we get something like
357             # "Journal of Foo, 4(5):122--130, May 1996" for the single sentence
358             # in the block.
359             # - the note block -- if the entry has no `note' field, this block
360             # will be an undefined value rather than a list of sentences
361             #
362             # These four blocks are returned from `format_article' (and thus from
363             # `format') as a list-of-lists-of-(strings or lists-of-strings. That
364             # is, each format methods returns a list of blocks, each of which is in
365             # turn a list of sentences. (Hence "list of lists of X".) Each
366             # sentence is either a string ("list of lists of strings") or a list of
367             # clauses ("list of lists of lists of strings'). Clear? Hope so!
368             #
369             # [ # enter list of blocks
370             # ["Joe Blow, Fred Jones, and John Smith"] # name block:
371             # # 1 sentence w/ 1 clause
372             # ["The mating habits of foobars"] # title block:
373             # # 1 sentence w/ 1 clause
374             # [["Journal of Foo", # journal block:
375             # "4(5):122--130", # 1 sentence w/ 3 clauses
376             # "May 1996"]]
377             # undef
378             # ]
379             #
380             # A note: the journal name will normally have a bit of markup around it,
381             # say to italicize it -- that's determined by the calling application,
382             # though; the default markups are all empty strings. There could
383             # probably be arbitrary markup for every element of an entry, but I
384             # haven't gone that far yet.
385             #
386             # It is then the responsibility of the calling application to apply the
387             # appropriate punctuation and munge all those lists of strings together
388             # into something worth printing. The canonical application for doing
389             # this is btformat, which supports LaTeX 2.09, LaTeX2e, and HTML markup
390             # and output.
391              
392              
393             sub format_article
394             {
395 7     7 0 11 my $self = shift;
396              
397              
398 7         17 my $name_block = [$self->format_authors];
399 7         22 my $title_block = [$self->format_atitle];
400 7         23 my $journal_block = [[$self->markup_string('journal', $self->get ('journal')),
401             $self->format_vol_num_pages,
402             $self->format_date]];
403              
404             # if ($self->exists ('crossref'))
405             # {
406             # push (@blocks, [[$self->format_xref_article,
407             # $self->format_pages]]);
408             # }
409             # else
410             # {
411             # }
412              
413             # push (@blocks, [$self->get ('note')]) if $self->exists ('note');
414             # @blocks;
415              
416 7         20 ($name_block, $title_block, $journal_block, $self->get ('note'));
417             } # format_article
418              
419              
420             sub format_book
421             {
422 2     2 0 4 my $self = shift;
423              
424 2 50       6 my $name_block = # author(s) or editor(s)
425             ($self->exists ('author'))
426             ? [$self->format_authors]
427             : [$self->format_editors];
428 2         11 my $title_block = # title (and volume)
429             [[$self->format_btitle, $self->format_bvolume]];
430 2         9 my $from_block = # number/series; publisher, address,
431             [$self->format_number_series (0), # edition, date
432             [$self->get ('publisher'), $self->get ('address'),
433             $self->format_edition (0), $self->format_date]];
434              
435 2         6 ($name_block, $title_block, $from_block, $self->get('note'));
436              
437             } # format_book
438              
439              
440             # ----------------------------------------------------------------------
441             # Finally, the `format' method -- just calls one of the
442             # type-specific format methods (format_article, etc.)
443              
444             =item format ()
445              
446             Formats a single entry for inclusion in the bibliography of some
447             document. The exact processing performed is highly dependent on the
448             entry type and the fields present; in general, you should be able to
449             join C's outputs together to create a single paragraph for
450             inclusion in a document of whatever markup language you're working with.
451              
452             Returns a list of "blocks," which can either be jammed together like
453             sentences (for a traditional "tight" bibliography) or printed on
454             separate lines (for an "open" bibliography format). Each block is a
455             reference to a list of sentences; sentences should be joined together
456             with an intervening period. Each sentence is either a single string or
457             a list of clauses; clauses should be joined together with an intervening
458             comma. Each clause is just a simple string.
459              
460             See the source code for C for an example of how to use the
461             output of C.
462              
463             =cut
464              
465             sub format
466             {
467 9     9 1 599 my $self = shift;
468              
469 9         30 my $type = $self->type;
470 9         21 my $key = $self->key;
471 9         22 my $method_name = 'format_' . $type;
472 9         34 my $method = $self->can ($method_name);
473 9 50       23 unless ($method)
474             {
475 0         0 $self->warn ("can't format entry: " .
476             "no method $method_name (for type $type)");
477 0         0 return;
478             }
479            
480 9         17 return &$method ($self);
481             }
482              
483             1;
484              
485             =back
486              
487             =head1 SEE ALSO
488              
489             L, L,
490             L
491              
492             =head1 AUTHOR
493              
494             Greg Ward
495              
496             =head1 COPYRIGHT
497              
498             Copyright (c) 1997-2000 by Gregory P. Ward. All rights reserved. This file
499             is part of the Text::BibTeX library. This library is free software; you
500             may redistribute it and/or modify it under the same terms as Perl itself.