File Coverage

blib/lib/Lingua/Conjunction.pm
Criterion Covered Total %
statement 36 44 81.8
branch 15 24 62.5
condition 4 6 66.6
subroutine 10 13 76.9
pod 7 7 100.0
total 72 94 76.6


line stmt bran cond sub pod time code
1             package Lingua::Conjunction;
2              
3             # ABSTRACT: Convert lists into simple linguistic conjunctions
4              
5 3     3   103265 use v5.8;
  3         10  
6              
7 3     3   16 use strict;
  3         6  
  3         53  
8 3     3   19 use warnings;
  3         5  
  3         74  
9              
10 3     3   14 use Carp qw/ croak /;
  3         6  
  3         160  
11 3     3   17 use Exporter qw/ import /;
  3         6  
  3         2896  
12              
13             our @EXPORT = qw( conjunction );
14             our @EXPORT_OK = @EXPORT;
15              
16             =head1 NAME
17              
18             Lingua::Conjunction - Convert lists into simple linguistic conjunctions
19              
20             =head1 VERSION
21              
22             Version 2.3
23              
24             =cut
25              
26             our $VERSION = '2.3';
27              
28             =head1 SYNOPSIS
29              
30             Language-specific definitions.
31             These may not be correct, and certainly they are not complete.
32             E-mail corrections and additions to C<< >>,
33             and an updated version will be released.
34              
35             =cut
36              
37             # Format of %language is as follows:
38             # Two-letter ISO language codes... see L from CPAN for more details.
39             # sep = item separator (usually a comma)
40             # alt = alternate ("phrase") separator
41             # pen = 1 = use penultimate separator/0 = don't use penultimate
42             # (ie, "Jack, Jill and Spot" vs. "Jack, Jill, and Spot")
43             # con = conjunction ("and")
44             # dis = disjunction ("or"), well, grammatically still a "conjunction"...
45              
46             my %language = (
47             'af' => { sep => ',', alt => ';', pen => 1, con => 'en', dis => 'of' },
48             'da' => { sep => ',', alt => ';', pen => 1, con => 'og', dis => 'eller' },
49             'de' => { sep => ',', alt => ';', pen => 1, con => 'und', dis => 'oder' },
50             'en' => { sep => ',', alt => ';', pen => 1, con => 'and', dis => 'or' },
51             'es' => { sep => ',', alt => ';', pen => 1, con => 'y', dis => 'o' },
52             'fi' => { sep => ',', alt => ';', pen => 1, con => 'ja', dis => 'tai' },
53             'fr' => { sep => ',', alt => ';', pen => 0, con => 'et', dis => 'ou' },
54             'id' => { sep => ',', alt => ';', pen => 1, con => 'dan', dis => 'atau' },
55             'it' => { sep => ',', alt => ';', pen => 1, con => 'e', dis => 'o' },
56             'la' => { sep => ',', alt => ';', pen => 1, con => 'et', dis => 'vel' },
57             'nl' => { sep => ',', alt => ';', pen => 1, con => 'en', dis => 'of' },
58             'no' => { sep => ',', alt => ';', pen => 0, con => 'og', dis => 'eller' },
59             'pt' => { sep => ',', alt => ';', pen => 1, con => 'e', dis => 'ou' },
60             'sw' => { sep => ',', alt => ';', pen => 1, con => 'na', dis => 'au' },
61             );
62              
63             # Conjunction types. TODO: Someday we'll add either..or, neither..nor
64             my %types = (
65             'and' => 'con',
66             'or' => 'dis'
67             );
68              
69             my %punct = %{ $language{_get_language()} };
70             my $list_type = $types{'and'};
71              
72             =head1 SUBROUTINES/METHODS
73              
74             =head2 conjunction
75              
76             Lingua::Conjunction exports a single subroutine, C, that
77             converts a list into a properly punctuated text string.
78              
79             You can cause C to use the connectives of other languages, by
80             calling the appropriate subroutine:
81              
82             Lingua::Conjunction->lang('en'); # use 'and'
83             Lingua::Conjunction->lang('es'); # use 'y'
84             Lingua::Conjunction->lang(); # Tries to determine your language, otherwise falls back to 'en'
85              
86             Supported languages in this version are
87             Afrikaans,
88             Danish,
89             Dutch,
90             English,
91             French,
92             German,
93             Indonesian,
94             Italian,
95             Latin,
96             Norwegian,
97             Portuguese,
98             Spanish,
99             and Swahili.
100              
101             You can also set connectives individually:
102              
103             Lingua::Conjunction->separator("...");
104             Lingua::Conjunction->separator_phrase("--");
105             Lingua::Conjunction->connector_type("or");
106              
107             # emits "Jack... Jill... or Spot"
108             $name_list = conjunction('Jack', 'Jill', 'Spot');
109              
110             =cut
111              
112             sub conjunction {
113             # See List::ToHumanString
114 11   100 11 1 1117 my @list = grep defined && /\S/, @_;
115              
116 11 50       30 return if(scalar(@list) == 0);
117 11 100       29 return $list[0] if(scalar(@list) == 1);
118 9 100       38 return join(" $punct{$list_type} ", @list) if(scalar(@list) == 2);
119              
120 5 100       14 if ( $punct{pen} ) {
121 3 50       64 return join "$punct{sep} ", @list[ 0 .. $#_ - 1 ],
122             "$punct{$list_type} $_[-1]",
123             unless grep /$punct{sep}/, @list;
124 0         0 return join "$punct{alt} ", @list[ 0 .. $#_ - 1 ],
125             "$punct{$list_type} $_[-1]";
126             } else {
127 2 50       46 return join "$punct{sep} ", @list[ 0 .. $#_ - 2 ],
128             "$_[-2] $punct{$list_type} $_[-1]",
129             unless grep /$punct{sep}/, @list;
130 0         0 return join "$punct{alt} ", @list[ 0 .. $#_ - 2 ],
131             "$_[-2] $punct{$list_type} $_[-1]";
132             }
133             }
134              
135             =head2 separator
136              
137             Sets the separator, usually ',' or ';'.
138              
139             Lingua::Conjunction->separator(',');
140              
141             =cut
142              
143             sub separator {
144 0     0 1 0 $punct{sep} = $_[1];
145             }
146              
147             =head2 separator_phrase
148              
149             Sets the alternate (phrase) separator.
150              
151             Lingua::Conjunction->separator_phrase(';');
152              
153             The C is used whenever the separator already appears in
154             an item of the list. For example:
155              
156             # emits "Doe, a deer; Ray; and Me"
157             $name_list = conjunction('Doe, a deer', 'Ray', 'Me');
158              
159             =cut
160              
161             sub separator_phrase {
162 0     0 1 0 $punct{alt} = $_[1];
163             }
164              
165             =head2 penultimate
166              
167             Enables/disables punultimate separator.
168              
169             You may use the C routine to diable the separator after the
170             next to last item.
171             In English, The Oxford Comma is a highly debated issue.
172              
173             # emits "Jack, Jill and Spot"
174             Lingua::Conjunction->penultimate(0);
175             $name_list = conjunction('Jack', 'Jill', 'Spot');
176              
177             The original author was told that the penultimate comma is not standard for some
178             languages, such as Norwegian.
179             Hence the defaults set in the C<%languages>.
180              
181             Lingua::Conjunction->penultimate(0);
182              
183             =cut
184              
185             sub penultimate {
186 1     1 1 3 $punct{pen} = $_[1];
187             }
188              
189             =head2 connector_type
190              
191             Use "and" or "or", with appropriate translation for the current language
192              
193             Lingua::Conjunction->connector_type('and');
194              
195             =cut
196              
197             sub connector_type {
198 1 50   1 1 4 croak "Undefined connector type \`$_[1]\'", unless ( $types{ $_[1] } );
199 1         3 $list_type = $types{ $_[1] };
200             }
201              
202             =head2 connector
203              
204             Sets the for the current connector_type.
205              
206             Lingua::Conjunction->connector(SCALAR)
207              
208             =cut
209              
210             sub connector {
211 0     0 1 0 $punct{$list_type} = $_[1];
212             }
213              
214             =head2 lang
215              
216             Sets the language to use.
217             If no arguments are given,
218             it tries its best to guess.
219              
220             Lingua::Conjunction->lang('de'); # Changes the language to German
221              
222             =cut
223              
224             sub lang {
225 1   33 1 1 5 my $language = $_[1] || _get_language();
226             croak "Undefined language \`$language\'",
227 1 50       12 unless ( defined( $language{$language} ) );
228 1         5 %punct = %{ $language{$language} };
  1         8  
229             }
230              
231             # https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html
232             # https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html
233             sub _get_language
234             {
235 3 100   3   12 if($ENV{'LANGUAGE'}) {
236 2         9 foreach my $l(split/:/, $ENV{'LANGUAGE'}) {
237 2 50       7 if($language{$l}) {
238 2         13 return $l;
239             }
240             }
241             }
242 1         2 foreach my $variable('LC_ALL', 'LC_MESSAGES', 'LANG') {
243 3         4 my $val = $ENV{$variable};
244 3 50       7 next unless(defined($val));
245              
246 0         0 $val = substr($val, 0, 2);
247 0 0       0 if($language{$val}) {
248 0         0 return $val;
249             }
250             }
251 1         5 return 'en';
252             }
253              
254             =head1 AUTHORS
255              
256             =over 4
257              
258             =item *
259              
260             Robert Rothenberg
261              
262             =item *
263              
264             Damian Conway
265              
266             =back
267              
268             =head1 MAINTAINER
269              
270             2021-present Maintained by Nigel Horne, C<< >>
271              
272             =head1 CONTRIBUTORS
273              
274             =for stopwords Ade Ishs Mohammad S Anwar Nigel Horne
275              
276             =over 4
277              
278             =item *
279              
280             Ade Ishs
281              
282             =item *
283              
284             Mohammad S Anwar
285              
286             =item *
287              
288             Nigel Horne C<< >>
289              
290             =back
291              
292             =head1 SEE ALSO
293              
294             C, C
295              
296             The I in Section 4.2 has a simular subroutine called
297             C. The differences are that
298             1. this routine handles multiple languages and
299             2. being a module, you do not have to add the subroutine to a script every time you need it.
300              
301             =head1 SOURCE
302              
303             The development version is on github at L
304             and may be cloned from L
305              
306             =head1 SUPPORT
307              
308             You can find documentation for this module with the perldoc command.
309              
310             perldoc Lingua::Conjunction
311              
312             You can also look for information at:
313              
314             =over 4
315              
316             =item * MetaCPAN
317              
318             L
319              
320             =item * RT: CPAN's request tracker
321              
322             L
323              
324             =item * CPANTS
325              
326             L
327              
328             =item * CPAN Testers' Matrix
329              
330             L
331              
332             =item * CPAN Ratings
333              
334             L
335              
336             =item * CPAN Testers Dependencies
337              
338             L
339              
340             =back
341              
342             =head1 BUGS
343              
344             Please report any bugs or feature requests on the bugtracker website
345             L
346              
347             When submitting a bug or request, please include a test-file or a
348             patch to an existing test-file that illustrates the bug or desired
349             feature.
350              
351             =head1 COPYRIGHT AND LICENSE
352              
353             This software is Copyright (c) 1999-2020 by Robert Rothenberg.
354              
355             This is free software, licensed under:
356              
357             The Artistic License 2.0 (GPL Compatible)
358              
359             =cut
360              
361             1;