File Coverage

blib/lib/Bible/Reference.pm
Criterion Covered Total %
statement 427 429 99.5
branch 149 170 87.6
condition 76 101 75.2
subroutine 27 27 100.0
pod 17 17 100.0
total 696 744 93.5


line stmt bran cond sub pod time code
1             package Bible::Reference;
2             # ABSTRACT: Simple Bible reference parser, tester, and canonicalizer
3              
4 1     1   240133 use 5.020;
  1         9  
5              
6 1     1   508 use exact;
  1         39348  
  1         4  
7 1     1   3139 use exact::class;
  1         12210  
  1         20  
8              
9             our $VERSION = '1.14'; # VERSION
10              
11             has acronyms => 0;
12             has sorting => 1;
13             has require_verse_match => 0;
14             has require_book_ucfirst => 0;
15             has minimum_book_length => 3;
16             has add_detail => 0;
17              
18             my $bibles = {
19             ESV => [
20             [
21             [ 'Genesis', 'Ge', 'Gn', 'Gen' ],
22             [ 'Exodus', 'Ex', 'Exo' ],
23             [ 'Leviticus', 'Lv', 'Lev' ],
24             [ 'Numbers', 'Nu', 'Nm', 'Num' ],
25             [ 'Deuteronomy', 'Dt', 'Deu' ],
26             [ 'Joshua', 'Jsh', 'Jos', 'Josh' ],
27             [ 'Judges', 'Jdg', 'Judg' ],
28             [ 'Ruth', 'Ru', 'Rut' ],
29             [ '1 Samuel', '1Sa', '1Sm', '1Sam' ],
30             [ '2 Samuel', '2Sa', '2Sm', '2Sam' ],
31             [ '1 Kings', '1Ki', '1Kg', '1Kgs', '1Kin' ],
32             [ '2 Kings', '2Ki', '2Kg', '2Kgs', '2Kin' ],
33             [ '1 Chronicles', '1Ch', '1Cr', '1Chr' ],
34             [ '2 Chronicles', '2Ch', '2Cr', '2Chr' ],
35             [ 'Ezra', 'Ezr' ],
36             [ 'Nehemiah', 'Ne', 'Neh' ],
37             [ 'Esther', 'Est', 'Esth' ],
38             [ 'Job', 'Jb', 'Jo', 'Job' ],
39             [ 'Psalm', 'Ps', 'Psa', 'Psalms' ],
40             [ 'Proverbs', 'Pr', 'Prv', 'Pro', 'Prov' ],
41             [ 'Ecclesiastes', 'Ec', 'Ecc', 'Eccl' ],
42             [ 'Song of Solomon', 'SS', 'SoS', 'Song of Songs' ],
43             [ 'Isaiah', 'Is', 'Isa' ],
44             [ 'Jeremiah', 'Jr', 'Jer' ],
45             [ 'Lamentations', 'Lm', 'La', 'Lam' ],
46             [ 'Ezekiel', 'Ezk', 'Ez', 'Eze', 'Ezek' ],
47             [ 'Daniel', 'Da', 'Dn', 'Dan' ],
48             [ 'Hosea', 'Ho', 'Hs', 'Hos' ],
49             [ 'Joel', 'Jl', 'Joe', 'Joel' ],
50             [ 'Amos', 'Am', 'Amo' ],
51             [ 'Obadiah', 'Ob', 'Oba' ],
52             [ 'Jonah', 'Jnh', 'Jon', 'Jona' ],
53             [ 'Micah', 'Mi', 'Mic' ],
54             [ 'Nahum', 'Na', 'Nah' ],
55             [ 'Habakkuk', 'Hab' ],
56             [ 'Zephaniah', 'Zp', 'Zep', 'Zph', 'Zeph' ],
57             [ 'Haggai', 'Hg', 'Hag' ],
58             [ 'Zechariah', 'Zec', 'Zch', 'Zech' ],
59             [ 'Malachi', 'Ml', 'Mal' ],
60             [ 'Matthew', 'Mt', 'Mat', 'Matt' ],
61             [ 'Mark', 'Mk', 'Mr', 'Mc', 'Mark' ],
62             [ 'Luke', 'Lk', 'Lu', 'Luk' ],
63             [ 'John', 'Joh' ],
64             [ 'Acts', 'Ac', 'Act' ],
65             [ 'Romans', 'Ro', 'Rm', 'Rom', 'Roms' ],
66             [ '1 Corinthians', '1Co', '1Cor' ],
67             [ '2 Corinthians', '2Co', '2Cor' ],
68             [ 'Galatians', 'Ga', 'Gl', 'Gal' ],
69             [ 'Ephesians', 'Ep', 'Eph' ],
70             [ 'Philippians', 'Php', 'Phil' ],
71             [ 'Colossians', 'Cl', 'Col' ],
72             [ '1 Thessalonians', '1Th', '1The' ],
73             [ '2 Thessalonians', '2Th', '2The' ],
74             [ '1 Timothy', '1Ti', '1Tm', '1Tim' ],
75             [ '2 Timothy', '2Ti', '2Tm', '2Tim' ],
76             [ 'Titus', 'Ti', 'Tt' ],
77             [ 'Philemon', 'Phm', 'Phlm', 'Phile' ],
78             [ 'Hebrews', 'He', 'Heb' ],
79             [ 'James', 'Jam', 'Jms', 'Jas' ],
80             [ '1 Peter', '1Pt', '1Pe', '1Pet' ],
81             [ '2 Peter', '2Pt', '2Pe', '2Pet' ],
82             [ '1 John', '1Jn', '1Jo', '1Joh' ],
83             [ '2 John', '2Jn', '2Jo', '2Joh' ],
84             [ '3 John', '3Jn', '3Jo', '3Joh' ],
85             [ 'Jude', 'Jud', 'Jude' ],
86             [ 'Revelation', 'Rv', 'Rev' ],
87             ],
88             [
89             [
90             31, 25, 24, 26, 32, 22, 24, 22, 29, 32, 32, 20, 18, 24, 21, 16, 27, 33, 38, 18, 34, 24, 20,
91             67, 34, 35, 46, 22, 35, 43, 55, 32, 20, 31, 29, 43, 36, 30, 23, 23, 57, 38, 34, 34, 28, 34,
92             31, 22, 33, 26,
93             ],
94             [
95             22, 25, 22, 31, 23, 30, 25, 32, 35, 29, 10, 51, 22, 31, 27, 36, 16, 27, 25, 26, 36, 31, 33,
96             18, 40, 37, 21, 43, 46, 38, 18, 35, 23, 35, 35, 38, 29, 31, 43, 38,
97             ],
98             [
99             17, 16, 17, 35, 19, 30, 38, 36, 24, 20, 47, 8, 59, 57, 33, 34, 16, 30, 37, 27, 24, 33, 44,
100             23, 55, 46, 34,
101             ],
102             [
103             54, 34, 51, 49, 31, 27, 89, 26, 23, 36, 35, 16, 33, 45, 41, 50, 13, 32, 22, 29, 35, 41, 30,
104             25, 18, 65, 23, 31, 40, 16, 54, 42, 56, 29, 34, 13,
105             ],
106             [
107             46, 37, 29, 49, 33, 25, 26, 20, 29, 22, 32, 32, 18, 29, 23, 22, 20, 22, 21, 20, 23, 30, 25,
108             22, 19, 19, 26, 68, 29, 20, 30, 52, 29, 12,
109             ],
110             [
111             18, 24, 17, 24, 15, 27, 26, 35, 27, 43, 23, 24, 33, 15, 63, 10, 18, 28, 51, 9, 45, 34, 16,
112             33,
113             ],
114             [ 36, 23, 31, 24, 31, 40, 25, 35, 57, 18, 40, 15, 25, 20, 20, 31, 13, 31, 30, 48, 25 ],
115             [ 22, 23, 18, 22 ],
116             [
117             28, 36, 21, 22, 12, 21, 17, 22, 27, 27, 15, 25, 23, 52, 35, 23, 58, 30, 24, 42, 15, 23, 29,
118             22, 44, 25, 12, 25, 11, 31, 13,
119             ],
120             [
121             27, 32, 39, 12, 25, 23, 29, 18, 13, 19, 27, 31, 39, 33, 37, 23, 29, 33, 43, 26, 22, 51, 39,
122             25,
123             ],
124             [ 53, 46, 28, 34, 18, 38, 51, 66, 28, 29, 43, 33, 34, 31, 34, 34, 24, 46, 21, 43, 29, 53 ],
125             [
126             18, 25, 27, 44, 27, 33, 20, 29, 37, 36, 21, 21, 25, 29, 38, 20, 41, 37, 37, 21, 26, 20, 37,
127             20, 30,
128             ],
129             [
130             54, 55, 24, 43, 26, 81, 40, 40, 44, 14, 47, 40, 14, 17, 29, 43, 27, 17, 19, 8, 30, 19, 32,
131             31, 31, 32, 34, 21, 30,
132             ],
133             [
134             17, 18, 17, 22, 14, 42, 22, 18, 31, 19, 23, 16, 22, 15, 19, 14, 19, 34, 11, 37, 20, 12, 21,
135             27, 28, 23, 9, 27, 36, 27, 21, 33, 25, 33, 27, 23,
136             ],
137             [ 11, 70, 13, 24, 17, 22, 28, 36, 15, 44 ],
138             [ 11, 20, 32, 23, 19, 19, 73, 18, 38, 39, 36, 47, 31 ],
139             [ 22, 23, 15, 17, 14, 14, 10, 17, 32, 3 ],
140             [
141             22, 13, 26, 21, 27, 30, 21, 22, 35, 22, 20, 25, 28, 22, 35, 22, 16, 21, 29, 29, 34, 30, 17,
142             25, 6, 14, 23, 28, 25, 31, 40, 22, 33, 37, 16, 33, 24, 41, 30, 24, 34, 17,
143             ],
144             [
145             6, 12, 8, 8, 12, 10, 17, 9, 20, 18, 7, 8, 6, 7, 5, 11, 15, 50, 14, 9, 13, 31, 6,
146             10, 22, 12, 14, 9, 11, 12, 24, 11, 22, 22, 28, 12, 40, 22, 13, 17, 13, 11, 5, 26, 17, 11,
147             9, 14, 20, 23, 19, 9, 6, 7, 23, 13, 11, 11, 17, 12, 8, 12, 11, 10, 13, 20, 7, 35, 36,
148             5, 24, 20, 28, 23, 10, 12, 20, 72, 13, 19, 16, 8, 18, 12, 13, 17, 7, 18, 52, 17, 16, 15,
149             5, 23, 11, 13, 12, 9, 9, 5, 8, 28, 22, 35, 45, 48, 43, 13, 31, 7, 10, 10, 9, 8, 18,
150             19, 2, 29, 176, 7, 8, 9, 4, 8, 5, 6, 5, 6, 8, 8, 3, 18, 3, 3, 21, 26, 9, 8,
151             24, 13, 10, 7, 12, 15, 21, 10, 20, 14, 9, 6,
152             ],
153             [
154             33, 22, 35, 27, 23, 35, 27, 36, 18, 32, 31, 28, 25, 35, 33, 33, 28, 24, 29, 30, 31, 29, 35,
155             34, 28, 28, 27, 28, 27, 33, 31,
156             ],
157             [ 18, 26, 22, 16, 20, 12, 29, 17, 18, 20, 10, 14 ],
158             [ 17, 17, 11, 16, 16, 13, 13, 14 ],
159             [
160             31, 22, 26, 6, 30, 13, 25, 22, 21, 34, 16, 6, 22, 32, 9, 14, 14, 7, 25, 6, 17, 25, 18,
161             23, 12, 21, 13, 29, 24, 33, 9, 20, 24, 17, 10, 22, 38, 22, 8, 31, 29, 25, 28, 28, 25, 13,
162             15, 22, 26, 11, 23, 15, 12, 17, 13, 12, 21, 14, 21, 22, 11, 12, 19, 12, 25, 24,
163             ],
164             [
165             19, 37, 25, 31, 31, 30, 34, 22, 26, 25, 23, 17, 27, 22, 21, 21, 27, 23, 15, 18, 14, 30, 40,
166             10, 38, 24, 22, 17, 32, 24, 40, 44, 26, 22, 19, 32, 21, 28, 18, 16, 18, 22, 13, 30, 5, 28,
167             7, 47, 39, 46, 64, 34,
168             ],
169             [ 22, 22, 66, 22, 22 ],
170             [
171             28, 10, 27, 17, 17, 14, 27, 18, 11, 22, 25, 28, 23, 23, 8, 63, 24, 32, 14, 49, 32, 31, 49,
172             27, 17, 21, 36, 26, 21, 26, 18, 32, 33, 31, 15, 38, 28, 23, 29, 49, 26, 20, 27, 31, 25, 24,
173             23, 35,
174             ],
175             [ 21, 49, 30, 37, 31, 28, 28, 27, 27, 21, 45, 13 ],
176             [ 11, 23, 5, 19, 15, 11, 16, 14, 17, 15, 12, 14, 16, 9 ],
177             [ 20, 32, 21 ],
178             [ 15, 16, 15, 13, 27, 14, 17, 14, 15 ],
179             [ 21 ],
180             [ 17, 10, 10, 11 ],
181             [ 16, 13, 12, 13, 15, 16, 20 ],
182             [ 15, 13, 19 ],
183             [ 17, 20, 19 ],
184             [ 18, 15, 20 ],
185             [ 15, 23 ],
186             [ 21, 13, 10, 14, 11, 15, 14, 23, 17, 12, 17, 14, 9, 21 ],
187             [ 14, 17, 18, 6 ],
188             [
189             25, 23, 17, 25, 48, 34, 29, 34, 38, 42, 30, 50, 58, 36, 39, 28, 27, 35, 30, 34, 46, 46, 39,
190             51, 46, 75, 66, 20,
191             ],
192             [ 45, 28, 35, 41, 43, 56, 37, 38, 50, 52, 33, 44, 37, 72, 47, 20 ],
193             [
194             80, 52, 38, 44, 39, 49, 50, 56, 62, 42, 54, 59, 35, 35, 32, 31, 37, 43, 48, 47, 38, 71, 56,
195             53,
196             ],
197             [ 51, 25, 36, 54, 47, 71, 53, 59, 41, 42, 57, 50, 38, 31, 27, 33, 26, 40, 42, 31, 25 ],
198             [
199             26, 47, 26, 37, 42, 15, 60, 40, 43, 48, 30, 25, 52, 28, 41, 40, 34, 28, 41, 38, 40, 30, 35,
200             27, 27, 32, 44, 31,
201             ],
202             [ 32, 29, 31, 25, 21, 23, 25, 39, 33, 21, 36, 21, 14, 23, 33, 27 ],
203             [ 31, 16, 23, 21, 13, 20, 40, 13, 27, 33, 34, 31, 13, 40, 58, 24 ],
204             [ 24, 17, 18, 18, 21, 18, 16, 24, 15, 18, 33, 21, 14 ],
205             [ 24, 21, 29, 31, 26, 18 ],
206             [ 23, 22, 21, 32, 33, 24 ],
207             [ 30, 30, 21, 23 ],
208             [ 29, 23, 25, 18 ],
209             [ 10, 20, 13, 18, 28 ],
210             [ 12, 17, 18 ],
211             [ 20, 15, 16, 16, 25, 21 ],
212             [ 18, 26, 17, 22 ],
213             [ 16, 15, 15 ],
214             [ 25 ],
215             [ 14, 18, 19, 16, 14, 20, 28, 13, 28, 39, 40, 29, 25 ],
216             [ 27, 26, 18, 17, 20 ],
217             [ 25, 25, 22, 19, 14 ],
218             [ 21, 22, 18 ],
219             [ 10, 29, 24, 21, 21 ],
220             [ 13 ],
221             [ 15 ],
222             [ 25 ],
223             [ 20, 29, 22, 11, 14, 17, 17, 13, 21, 11, 19, 17, 18, 20, 8, 21, 18, 24, 21, 15, 27, 21 ],
224             ],
225             ],
226             };
227              
228 3     3   22 sub _build_bible_template ( $source_name, $new_name, $bibles, $books_cb = undef, $verses_cb = undef ) {
  3         10  
  3         6  
  3         6  
  3         5  
  3         5  
  3         4  
229 3         7 $bibles->{$new_name} = [ map { [ map { [@$_] } @$_ ] } @{ $bibles->{$source_name} } ];
  6         16  
  432         1385  
  3         10  
230 3 100       17 $books_cb->( $bibles->{$new_name}[0] ) if ($books_cb);
231 3 100       24 $verses_cb->( $bibles->{$new_name}[1] ) if ($verses_cb);
232 3         9 return;
233             }
234              
235             _build_bible_template(
236             'ESV' => 'RSVCE',
237             $bibles,
238             sub ($books) {
239             splice( @$books, 25, 0,
240             [ 'Baruch', 'Ba', 'Br', 'Bar' ],
241             );
242              
243             splice( @$books, 22, 0,
244             [ 'Wisdom', 'Wi', 'Ws', 'Wis' ],
245             [ 'Sirach', 'Si', 'Sr', 'Sir' ],
246             );
247              
248             splice( @$books, 17, 0,
249             [ '1 Maccabees', '1Ma', '1Mac' ],
250             [ '2 Maccabees', '2Ma', '2Mac' ],
251             );
252              
253             splice( @$books, 16, 0,
254             [ 'Tobit', 'Tb', 'Tob' ],
255             [ 'Judith', 'Judi' ],
256             );
257             },
258             sub ($verses) {
259             push( @{ $verses->[26] }, 64, 42 );
260             splice( @$verses, 25, 0, [ 21, 35, 37, 37, 9, 73 ] );
261             splice( @$verses, 22, 0,
262             [ 16, 24, 19, 20, 23, 25, 30, 21, 18, 21, 26, 27, 19, 31, 19, 29, 21, 25, 22 ],
263             [
264             30, 18, 31, 31, 15, 37, 36, 19, 18, 31, 34, 18, 26, 27, 20, 30, 32, 33, 30, 31, 28, 27, 27,
265             34, 26, 29, 30, 26, 28, 25, 31, 24, 31, 26, 20, 26, 31, 34, 35, 30, 23, 25, 33, 23, 26, 20,
266             25, 25, 16, 29, 30,
267             ],
268             );
269             splice( @$verses, 16, 1,
270             [ 22, 14, 17, 21, 22, 17, 18, 21, 6, 12, 19, 22, 18, 15 ],
271             [ 16, 28, 10, 15, 24, 21, 32, 36, 14, 23, 23, 20, 20, 19, 13, 25 ],
272             [ 22, 23, 15, 19, 14, 14, 10, 17, 32, 1 ],
273             [ 64, 70, 60, 61, 68, 63, 50, 32, 73, 89, 74, 53, 53, 49, 41, 24 ],
274             [ 36, 32, 40, 50, 27, 31, 42, 36, 29, 38, 38, 45, 26, 46, 39 ],
275             );
276             },
277             );
278              
279             _build_bible_template(
280             'ESV' => 'RSV',
281             $bibles,
282             sub ($books) {
283             push( @$books,
284             [ 'Tobit', 'Tb', 'Tob' ],
285             [ 'Judith', 'Judi', 'Jdt' ],
286             [ 'Greek Esther', 'GkEsth' ],
287             [ 'Wisdom', 'Wi', 'Ws', 'Wis', 'Wisdom of Solomon' ],
288             [ 'Sirach', 'Si', 'Sr', 'Sir', 'Ben Sira', 'Wisdom of Ben Sira' ],
289             [ 'Baruch', 'Ba', 'Br', 'Bar' ],
290             [ 'Letter of Jeremiah', 'LJ', 'Let', 'EpJer' ],
291             [ 'Song of the Three Young Men', 'SgThr', 'Three', 'Prayer of Azariah' ],
292             [ 'Susanna', 'Sus' ],
293             [ 'Bel and the Dragon', 'Bel' ],
294             [ '1 Maccabees', '1Ma', '1Mac', '1Macc' ],
295             [ '2 Maccabees', '2Ma', '2Mac', '2Macc' ],
296             [ '1 Esdras', '1Es', '1Esd', '1Esdr' ],
297             [ 'Prayer of Manasseh', 'PM', 'Pra', 'Man', 'PrMan' ],
298             [ 'Psalm 151', 'Ps151', 'Psa151' ],
299             [ '3 Maccabees', '3Ma', '3Mac', '3Macc' ],
300             [ '2 Esdras', '2Es', '2Esd', '2Esdr' ],
301             [ '4 Maccabees', '4Ma', '4Mac', '4Macc' ],
302             );
303             },
304             sub ($verses) {
305             push( @$verses,
306             [ 22, 14, 17, 21, 21, 17, 18, 21, 6, 12, 19, 22, 18, 15 ],
307             [ 16, 28, 10, 15, 24, 21, 32, 36, 14, 23, 23, 20, 20, 19, 13, 25 ],
308             [ 22, 23, 15, 19, 14, 14, 10, 17, 32, 1 ],
309             [ 16, 24, 19, 20, 23, 25, 30, 21, 18, 21, 26, 27, 19, 31, 19, 29, 21, 25, 22 ],
310             [
311             30, 18, 31, 31, 15, 37, 36, 19, 18, 31, 34, 18, 26, 27, 20, 30, 32, 33, 30, 31, 28, 27, 27,
312             34, 26, 29, 30, 26, 28, 25, 31, 24, 31, 26, 20, 26, 31, 34, 35, 30, 23, 25, 33, 23, 26, 20,
313             25, 25, 16, 29, 30,
314             ],
315             [ 21, 35, 37, 37, 9 ],
316             [ 73 ],
317             [ 68 ],
318             [ 64 ],
319             [ 42 ],
320             [ 64, 70, 60, 61, 68, 63, 50, 32, 73, 89, 74, 53, 53, 49, 41, 24 ],
321             [ 36, 32, 40, 50, 27, 31, 42, 36, 29, 38, 38, 45, 26, 46, 39 ],
322             [ 58, 30, 24, 63, 73, 34, 15, 96, 55 ],
323             [ 15 ],
324             [ 7 ],
325             [ 29, 33, 30, 21, 51, 41, 23 ],
326             [ 40, 48, 36, 52, 56, 59, 140, 63, 47, 59, 46, 51, 58, 48, 63, 78 ],
327             [ 35, 24, 21, 26, 38, 35, 23, 29, 32, 21, 27, 19, 27, 20, 32, 25, 24, 24 ],
328             );
329             },
330             );
331              
332             $bibles->{Protestant} = $bibles->{ESV};
333             $bibles->{Catholic} = $bibles->{RSVCE};
334             $bibles->{Orthodox} = $bibles->{RSV};
335              
336             # has _bibles => $bibles;
337             has _bibles => { map { $_ => [ map { [ map { [ @$_] } @$_ ] } @{ $bibles->{$_} } ] } keys %$bibles };
338             has _bible => 'Protestant';
339             has _bible_data => {};
340             has _data => [];
341             has _cache => {};
342              
343 22     22 1 26975 sub bible ( $self, $name = undef ) {
  22         59  
  22         60  
  22         38  
344 22 100       94 return $self->_bible unless ($name);
345              
346 18   50     98 my $input = lc( $name || '' );
347 18         42 my ($bible) = grep { lc $_ eq $input } keys %{ $self->_bibles };
  118         503  
  18         65  
348              
349 18 100       306 croak "Could not determine a valid Bible type from input" unless ($bible);
350 17         99 $self->_bible($bible);
351              
352 17         149 my $books = [ map { [@$_] } @{ $self->_bibles->{ $self->_bible }[0] } ];
  1186         2967  
  17         64  
353              
354 17         63 my $bible_data;
355 17         66 for my $book_data (@$books) {
356 1186         2159 my ( $book, @acronyms ) = @$book_data;
357              
358 1186         3519 $bible_data->{book_to_acronym}{$book} = $acronyms[0];
359 1186         1581 push( @{ $bible_data->{books} }, $book );
  1186         2413  
360             }
361 17         54 my $book_count;
362 17         48 $bible_data->{book_order} = { map { $_ => ++$book_count } @{ $bible_data->{books} } };
  1186         2198  
  17         61  
363              
364 17         122 my $canonical = [ map { $_->[0] } @$books ];
  1186         1806  
365 17         105 my $options = { map { shift @$_ => $_ } @$books };
  1186         1971  
366             my $re_map = { map {
367 17         129 my $book = $_;
  1186         1792  
368 1186         1711 my $book_str = $_;
369 1186 50       4172 my @prefix = (
    100          
    100          
    100          
    100          
370             ( $book_str =~ s/^(\d)\s// ) ? (
371             (
372             (
373             ( $1 == 1 ) ? ( qw( I First ) ) :
374             ( $1 == 2 ) ? ( qw( II Second ) ) :
375             ( $1 == 3 ) ? ( qw( III Third ) ) :
376             ( $1 == 4 ) ? ( qw( IV Fourth ) ) : ()
377             ),
378             $1 . '*',
379             ),
380             $1,
381             ) : ()
382             );
383              
384 1186         3729 my @letters = split( '', $book_str );
385 1186         1596 my $unique;
386 1186         2372 while (@letters) {
387 3742         24970 $unique .= shift @letters;
388             last if (
389             length $unique >= $self->minimum_book_length
390             and (
391             not @prefix and
392             scalar( grep { index( $_, $unique ) == 0 } @$canonical ) == 1 or
393             @prefix and
394 3742 100 100     8208 scalar( grep { index( $_, $prefix[-1] . ' ' . $unique ) == 0 } @$canonical ) == 1
      100        
395             )
396             );
397             }
398              
399 1186         2563 my @matches = $unique;
400 1186         6194 push( @matches, $unique .= shift @letters ) while (@letters);
401              
402             @matches = map {
403 1186         2037 my $match = $_;
  6053         8641  
404              
405 6053         8600 $match .= ')i?(';
406 6053         21751 $match =~ s/^(\w)/$1)i-?(/;
407              
408 6053 100       16056 (@prefix) ? ( map { ')' . $_ . ':i?(' . ' ' . $match } @prefix ) : $match;
  6704         15171  
409             } @matches;
410              
411             map {
412 14048         22238 my $re = reverse $_;
413              
414 14048         20499 $re =~ s/\*/'[A-z]+'/ge;
  1676         4078  
415 14048         26895 $re =~ s/\s+/'[\s_]*'/ge;
  7842         19740  
416              
417 14048         41531 $re => $book;
418 1186         1924 } @matches, @{ $options->{$book} };
  1186         2577  
419             } @$canonical };
420              
421 17         4481 my @re_parts = sort { length $b <=> length $a } keys %$re_map;
  113191         139926  
422              
423 17         711 my $re_refs = '(?i:[\d:,;\s\-]|\bdna\b|\bro\b|&)*\.?';
424 17         81 my $re_refs_req =
425             '(?i:[\d:,;\s\-]|\bdna\b|\bro\b|&)*' .
426             '(?:\d\s*:\s*\d)' .
427             '(?i:[\d:,;\s\-]|\bdna\b|\bro\b|&)*\.?';
428              
429 17         134 my $re_refs_string = '\b(' . join( '|', map { $re_refs . $_ } @re_parts ) . ')\b';
  14048         26541  
430 17         905 my $re_refs_req_string = '\b(' . join( '|', map { $re_refs_req . $_ } @re_parts ) . ')\b';
  14048         30071  
431              
432 17         699353 $bible_data->{re_refs_s} = qr/$re_refs_string/;
433 17         2038007 $bible_data->{re_refs_sr} = qr/$re_refs_req_string/;
434 17         8110 $bible_data->{re_books_s} = [ map { [ qr/\b$_\b/, $re_map->{$_} ] } @re_parts ];
  14048         201914  
435              
436 17         13650 $re_refs_string =~ s/\(\?\-?i\)//g;
437 17         13727 $re_refs_req_string =~ s/\(\?\-?i\)//g;
438              
439 17         600794 $bible_data->{re_refs_i} = qr/$re_refs_string/i;
440 17         1835091 $bible_data->{re_refs_ir} = qr/$re_refs_req_string/i;
441             $bible_data->{re_books_i} = [ map {
442 17         6984 my $this_book = $re_map->{$_};
  14048         36833  
443 14048         48324 s/\(\?\-?i\)//g;
444 14048         190621 [ qr/\b$_\b/i, $this_book ];
445             } @re_parts ];
446              
447             $bible_data->{lengths} = {
448             map {
449 1186         14264 $bible_data->{books}[$_] => [ @{ $self->_bibles->{$bible}[1][$_] } ]
  1186         2261  
450 17         496 } 0 .. @{ $bible_data->{books} } - 1
  17         143  
451             };
452              
453 17         1198 $self->_bible_data($bible_data);
454 17         122396 return $bible;
455             }
456              
457 2     2 1 140 sub new ( $self, %params ) {
  2         5  
  2         6  
  2         3  
458 2         19 $self = $self->SUPER::new(%params);
459 2   33     1562 $self->bible( $params{bible} || $self->_bible );
460 2         16 return $self;
461             }
462              
463 202     202   376 sub _list ( $start, $stop ) {
  202         294  
  202         292  
  202         255  
464 202 50       470 $start++ if ( $start == 0 );
465 202 50       434 $stop++ if ( $stop == 0 );
466              
467 202         781 my ( $x, $y ) = sort { $a <=> $b } $start, $stop;
  404         572  
468 202         611 my @list = $x .. $y;
469 202 100       437 @list = reverse(@list) if ( $x < $start );
470              
471 202         1353 return @list;
472             };
473              
474 180     180 1 293 sub expand_ranges ( $self, $book, $text, $compress = 0 ) {
  180         280  
  180         268  
  180         428  
  180         302  
  180         255  
475 178     178   263 my $expand = sub ( $start, $stop ) {
  178         264  
  178         386  
  178         371  
476 178 100       673 my $start_ch = ( $start =~ s/(\d+):// ) ? $1 : 0;
477 178 100       503 my $stop_ch = ( $stop =~ s/(\d+):// ) ? $1 : 0;
478              
479 178 100 100     784 if ( not $start_ch and $stop_ch and $start > $stop_ch ) {
      100        
480             # A: "5-3:4" = translated to "5:1-3:4"
481              
482 1         4 $start_ch = $start;
483 1         3 $start = 1;
484             }
485              
486 178         280 my $skip_chapter_assumption_check = 0;
487 178 100 100     612 if ( $start_ch and $stop_ch and $start and $stop and $start_ch == $stop_ch ) {
      66        
      66        
      66        
488 2 100       7 if ( $start <= $stop ) {
489             # B: "3:4-3:7" = translated to "3:4-7"
490              
491 1         3 $stop_ch = 0;
492             }
493             else {
494             # Q: "3:37-3:4" is the reverse of 3:4-3:37
495              
496 1         2 $stop_ch = 0;
497 1         3 $skip_chapter_assumption_check = 1;
498             }
499             }
500              
501 178         270 my $expance = '';
502              
503 178 100 100     814 if ( not $start_ch and not $stop_ch ) {
    100 100        
    100 66        
    50 33        
504             # C: "3-3" = consider as "3"
505             # D: "3-5" = consider as a simple range
506             # E: "5-3" = consider as a simple reversed range
507              
508 99         264 $expance = join( ',', _list( $start, $stop ) );
509             }
510              
511             elsif ( $start_ch and not $stop_ch ) {
512             # F: "1:3-15" = consider 3-15 as verses
513             # G: "1:15-3" = consider 3 a chapter
514             # H: "1:3-3" = consider the second 3 a chapter
515             # I: "3:2-3" = consider 2-3 as verses
516             # J: "3:3-2" = consider 3-2 as verses
517              
518 62 100 100     267 if ( $start >= $stop and $stop > $start_ch and not $skip_chapter_assumption_check ) {
      100        
519 4         9 $stop_ch = $stop;
520 4         16 $stop = $self->_bible_data->{lengths}{$book}[ $start_ch - 1 ];
521             }
522              
523 62 100       253 $expance = join( ';', grep { defined }
  124         374  
524             $start_ch . ':' . join( ',', _list( $start, $stop ) ),
525             ( ($stop_ch) ? join( ';', _list( $start_ch + 1, $stop_ch ) ) : undef ),
526             );
527             }
528              
529             elsif ( not $start_ch and $stop_ch ) {
530             # K: "3-5:2" = 3-4 are full chapters; plus 5:1-5:2
531             # L: "3-3:2" = interpretted as "3:1-2"
532              
533 10         27 $start_ch = $start;
534 10         23 $start = 1;
535              
536 10         36 $expance = join( ':',
537             join( ';', _list( $start_ch, $stop_ch ) ),
538             join( ',', _list( $start, $stop ) ),
539             );
540             }
541              
542             elsif ( $start_ch and $stop_ch ) {
543             # M: "3:4-4:7" becomes "3:4-*;4:1-7"
544             # N: "4:7-3:4" becomes reverse of "3:4-*;4:1-7"
545             # O: "3:4-5:2" becomes "3:4-*;4;5:1-2"
546             # P: "5:2-3:4" becomes reverse of "3:4-*;4;5:2-*"
547              
548 7         11 my $reversed = 0;
549 7 100       16 if ( $start_ch >= $stop_ch ) {
550 3         11 ( $start_ch, $stop_ch, $start, $stop ) = ( $stop_ch, $start_ch, $stop, $start );
551 3         5 $reversed = 1;
552             }
553              
554 7 100       22 my $reverse = sub { ($reversed) ? reverse(@_) : @_ };
  24         320  
555              
556 21         62 $expance = join( ';', grep { defined }
557             $reverse->(
558             $start_ch . ':' . join( ',', $reverse->( _list(
559             $start,
560 7 100       30 $self->_bible_data->{lengths}{$book}[ $start_ch - 1 ],
561             ) ) ),
562             (
563             ( $stop_ch - $start_ch > 1 )
564             ? join( ',', $reverse->( _list( $start_ch + 1, $stop_ch - 1 ) ) )
565             : undef
566             ),
567             $stop_ch . ':' . join( ',', $reverse->( _list( 1, $stop ) ) ),
568             ),
569             );
570             }
571              
572 178         871 $expance;
573 180         1988 };
574              
575 180         798 $text =~ s/[\s,]+/,/g;
576 180         557 $text =~ s/^,//g;
577 180         870 $text =~ s/(\d+(?::\d+)?)\-(\d+(?::\d+)?)/ $expand->( $1, $2 ) /ge;
  178         423  
578 180 50       474 $text =~ s/([,;])/$1 /g unless $compress;
579              
580 180         2547 return $text;
581             };
582              
583 22     22 1 11371 sub in ( $self, @input ) {
  22         61  
  22         117  
  22         44  
584 22 50       99 return $self unless (@input);
585              
586             my $re_refs = $self->_bible_data->{
587 22 100       100 're_refs_' .
    100          
588             ( ( $self->require_book_ucfirst ) ? 's' : 'i' ) .
589             ( ( $self->require_verse_match ) ? 'r' : '' )
590             };
591              
592             my $re_books = ( $self->require_book_ucfirst )
593             ? $self->_bible_data->{re_books_s}
594 22 100       835 : $self->_bible_data->{re_books_i};
595              
596 22         527 for my $string (@input) {
597 173   100     760 $string = scalar( reverse $string // '' );
598 173         283 my @processed;
599 173         249 while (1) {
600 508         636744 my ( $pre, $ref, $post ) = split( /$re_refs/, $string, 2 );
601 508 100       2019 last unless ($ref);
602              
603 335         972 $ref =~ s/(\d)([[:alpha:]])/$1 $2/;
604              
605 335         635 $string = $post;
606              
607 335 100       1534 my $space = ( $ref =~ s/^((?i:\W|\bdna\b|\bro\b|&)+)// ) ? $1 : '';
608 335         1201 $ref =~ s/\s+/ /g;
609 335         633 $pre = $pre . $space;
610 335         712 push( @processed, $pre );
611              
612 335         473 my $book;
613 335         724 for (@$re_books) {
614 151930 100       438032 if ( $ref =~ /$_->[0]/ ) {
615 335         901 $book = $_->[1];
616 335         675 last;
617             }
618             }
619              
620 335         756 my $ref_out = [$book];
621 335         688 my $numbers = [];
622              
623 335         1522 $ref =~ s/(?:\bdna\b|\bro\b|&)/,/g;
624 335         836 $ref = scalar reverse $ref;
625              
626 335 100       1249 if ( $ref =~ /([\d:,;\s\-]+)$/ ) {
627 159         664 my $range = $self->expand_ranges( $book, $1, 1 );
628              
629 159         308 my $verse_context = 0;
630 159         264 my $last_d = 0;
631              
632 159         880 while ( $range =~ s/^(\d+)([:,;]?)\D*//g ) {
633 1174   100     3666 my ( $d, $s ) = ( $1, $2 || '' );
634              
635 1174 100 100     3591 $verse_context = 0 if ( $s eq ':' or $d <= $last_d );
636              
637 1174 100       1888 unless ($verse_context) {
638 664         1869 push( @$numbers, [$d] );
639             }
640             else {
641 510 100       673 push( @{ $numbers->[-1] }, [] ) unless ( @{ $numbers->[-1] } > 1 );
  127         282  
  510         1122  
642 510         701 push( @{ $numbers->[-1][-1] }, $d );
  510         1154  
643             }
644              
645 1174 100       2045 $last_d = ($verse_context) ? $d : 0;
646              
647 1174 100       2161 $verse_context = 1 if ( $s eq ':' );
648 1174 100       5012 $verse_context = 0 if ( $s eq ';' );
649             }
650             }
651              
652 335 100       855 push( @$ref_out, $numbers ) if (@$numbers);
653 335         752 push( @processed, $ref_out );
654             }
655              
656 173         408 push( @processed, $string );
657             push(
658 173         670 @{ $self->_data },
659 173 100       286 [ grep { length } map { ( ref $_ ) ? $_ : scalar reverse $_ } reverse @processed ],
  843         2152  
  843         4102  
660             );
661             }
662              
663 22         204 return $self;
664             }
665              
666 21     21 1 99388 sub clear ($self) {
  21         67  
  21         39  
667 21         266 $self->_data([]);
668 21         898 return $self;
669             }
670              
671 4     4 1 820 sub books ($self) {
  4         45  
  4         41  
672 4 50       25 return (wantarray) ? @{ $self->_bible_data->{books} } : $self->_bible_data->{books};
  4         18  
673             }
674              
675 56     56 1 140029 sub as_array ( $self, $data = undef ) {
  56         94  
  56         92  
  56         107  
676 56 50 100     295 if (
      0        
      66        
677             $data or
678             not $self->_cache->{data} or
679             not (
680             $self->_cache->{sorting} and $self->_cache->{sorting} == $self->sorting and
681             $self->_cache->{acronyms} and $self->_cache->{acronyms} == $self->acronyms
682             )
683             ) {
684 56   100     718 $data //= [ map { grep { ref } @$_ } @{ $self->_data } ];
  201         528  
  941         1701  
  17         59  
685             $data = [
686 56         134 map { [
687             map {
688 445         725 ( ref $_ ) ? [
689             map {
690 654 100       1640 ( ref $_ ) ? [
691             map {
692 902 100       1691 ( ref $_ ) ? [
  1067 50       4187  
693             @$_
694             ] : $_
695             } @$_
696             ] : $_
697             } @$_
698             ] : $_
699             } @$_
700             ] }
701             @$data
702             ];
703              
704             $data = [ map {
705 56 100       207 my $book = $_->[0];
  39         68  
706              
707 39 100       85 if ( ref $_->[1] ) {
708             $_->[1] = [ map {
709 82   100     242 $_->[1] //= [ 1 .. ( $self->_bible_data->{lengths}{$book}[ $_->[0] - 1 ] || 0 ) ];
      100        
710 82         1213 $_;
711 19         26 } @{ $_->[1] } ];
  19         34  
712             }
713             else {
714 20         29 my $chapter;
715 20         27 $_->[1] = [ map { [ ++$chapter, [ 1 .. $_ ] ] } @{ $self->_bible_data->{lengths}{$book} } ];
  209         1494  
  20         49  
716             }
717              
718 39         84 $_;
719             } @$data ] if ( $self->add_detail );
720              
721 56 100       676 if ( $self->sorting ) {
722 55         542 my $data_by_book = {};
723 55 100       138 push( @{ $data_by_book->{ $_->[0] } }, @{ $_->[1] || [] } ) for (@$data);
  406         910  
  406         1276  
724              
725             $data = [
726             map {
727 253         983 my $book = [ $_->[1] ];
728              
729 253         340 my $dedup;
730 253         320 for my $chapter ( @{ $data_by_book->{ $_->[1] } } ) {
  253         530  
731 1029   100     4059 $dedup->{ $chapter->[0] } //= {};
732 1029         1281 $dedup->{ $chapter->[0] }{$_} = 1 for ( @{ $chapter->[1] } );
  1029         9049  
733             }
734              
735             my $chapters = [
736             map {
737 908         1993 my $chapter = [$_];
738 908         1164 my @verses = keys %{ $dedup->{$_} };
  908         2863  
739 908 100       1929 push( @$chapter, [ sort { $a <=> $b } @verses ] ) if @verses;
  24661         31526  
740 908         1969 $chapter;
741             }
742 253         874 sort { $a <=> $b }
  2423         3157  
743             keys %$dedup
744             ];
745              
746 253 100       619 push( @$book, $chapters ) if (@$chapters);
747              
748 253         2277 $book;
749             }
750 665         1182 sort { $a->[0] <=> $b->[0] }
751 55         287 map { [ $self->_bible_data->{book_order}{$_}, $_ ] }
  253         2316  
752             keys %$data_by_book
753             ];
754             }
755              
756 56 100       333 if ( $self->acronyms ) {
757 1         19 for (@$data) {
758 22         217 $_->[0] = $self->_bible_data->{book_to_acronym}{ $_->[0] };
759             }
760             }
761              
762 56         719 $self->_cache->{data} = $data;
763             }
764              
765 56 100       2020 return (wantarray) ? @{ $self->_cache->{data} } : $self->_cache->{data};
  1         6  
766             }
767              
768 1     1 1 29 sub as_hash ( $self, $data = undef ) {
  1         4  
  1         2  
  1         2  
769 1         3 my $build = {};
770              
771 1         7 for my $book_block ( $self->as_array($data) ) {
772 22         56 my ( $book_name, $chapters ) = @$book_block;
773              
774 22         36 $build->{$book_name} = {};
775 22         38 for (@$chapters) {
776 77 100       95 push( @{ $build->{$book_name}{ $_->[0] } }, @{ $_->[1] || [] } );
  77         150  
  77         231  
777             }
778             }
779              
780 1 50       7 return (wantarray) ? %$build : $build;
781             }
782              
783 83     83   150 sub _compress_range ( $items = [] ) {
  83         128  
  83         106  
784 83         125 my ( $last, @items, @range );
785              
786             my $flush_range = sub {
787 192 100   192   376 if (@range) {
788 72         101 pop @items;
789 72         169 push( @items, join( '-', $range[0], $range[-1] ) );
790 72         150 @range = ();
791             }
792 83         246 };
793              
794 83         164 for my $item (@$items) {
795 493 100 100     1202 if ( not $last or $last + 1 != $item ) {
796 109         227 $flush_range->();
797 109         173 push( @items, $item );
798             }
799             else {
800 384         585 push( @range, $last, $item );
801             }
802              
803 493         696 $last = $item;
804             }
805 83         170 $flush_range->();
806              
807 83 50       400 return (wantarray) ? @items : join( ', ', @items );
808             }
809              
810 51     51   79 sub _as_type ( $self, $type, $data = undef ) {
  51         99  
  51         80  
  51         82  
  51         77  
811 51         138 $data = $self->as_array($data);
812              
813             return [
814             map {
815 51         477 my $book = $_->[0];
  165         307  
816              
817 165 100       292 if ( $_->[1] ) {
818 69         112 my ( @build, @buffer );
819              
820             my $flush_buffer = sub {
821 76 100   76   153 if (@buffer) {
822 24         56 push( @build, join( '; ', _compress_range(\@buffer) ) );
823 24         58 @buffer = ();
824             }
825 69         229 };
826              
827 69         114 for ( @{ $_->[1] } ) {
  69         140  
828 467         699 my $chapter = $_->[0];
829              
830 467 100       721 if ( $_->[1] ) {
831 70 100       194 if ( $type eq 'verses' ) {
    100          
    100          
832 11         17 push( @build, map { "$book $chapter:$_" } @{ $_->[1] } );
  58         122  
  11         18  
833             }
834             elsif ( $type eq 'runs' ) {
835 11         22 push( @build, map { "$book $chapter:$_" } _compress_range( $_->[1] ) );
  14         53  
836             }
837             elsif ( $type eq 'chapters' ) {
838 11         28 push( @build, "$book $chapter:" . join( ', ', _compress_range( $_->[1] ) ) );
839             }
840             else {
841 37         86 $flush_buffer->();
842 37         100 push( @build, $chapter . ':' . join( ', ', _compress_range( $_->[1] ) ) );
843             }
844             }
845             else {
846 397 100       609 unless ( $type eq 'books' ) {
847 198         407 push( @build, "$book $chapter" );
848             }
849             else {
850 199         342 push( @buffer, $chapter );
851             }
852             }
853             }
854              
855 69 100       153 unless ( $type eq 'books' ) {
856 30         303 @build;
857             }
858             else {
859 39         83 $flush_buffer->();
860 39         195 $book . ' ' . join( '; ', @build );
861             }
862             }
863             else {
864 96         196 $book;
865             }
866             } @$data
867             ];
868             }
869              
870 1     1 1 28 sub as_verses ( $self, $data = undef ) {
  1         3  
  1         3  
  1         4  
871 1         5 my $items = $self->_as_type( 'verses', $data );
872 1 50       8 return (wantarray) ? @$items : $items;
873             }
874              
875 1     1 1 42 sub as_runs ( $self, $data = undef ) {
  1         81  
  1         4  
  1         2  
876 1         32 my $items = $self->_as_type( 'runs', $data );
877 1 50       9 return (wantarray) ? @$items : $items;
878             }
879              
880 1     1 1 36 sub as_chapters ( $self, $data = undef ) {
  1         3  
  1         4  
  1         3  
881 1         11 my $items = $self->_as_type( 'chapters', $data );
882 1 50       9 return (wantarray) ? @$items : $items;
883             }
884              
885 48     48 1 109 sub as_books ( $self, $data = undef ) {
  48         76  
  48         96  
  48         68  
886 48         123 my $items = $self->_as_type( 'books', $data );
887 48 100       236 return (wantarray) ? @$items : $items;
888             }
889              
890 40     40 1 80 sub refs ( $self, $data = undef ) {
  40         61  
  40         71  
  40         61  
891 40         86 return join( '; ', $self->as_books($data) );
892             }
893              
894 1     1 1 31 sub as_text ($self) {
  1         4  
  1         2  
895             my @text = map {
896 18 100       64 join( '', map { ( ref $_ ) ? $self->refs([$_]) : $_ } @$_ );
  92         283  
897 1         4 } @{ $self->_data };
  1         5  
898              
899             return
900 1 50 33     17 ( @text > 1 and wantarray ) ? @text :
    50 33        
901             ( @text > 1 and not wantarray ) ? \@text : join( ' ', @text );
902             }
903              
904 4     4 1 6176 sub set_bible_data ( $self, $bible = undef, $book_data = undef, $verse_data = undef ) {
  4         8  
  4         7  
  4         9  
  4         6  
  4         7  
905 4 50 66     227 croak 'First argument to set_bible_data() must be a Bible name string'
      66        
906             unless ( $bible and not ref $bible and length $bible > 0 );
907 3 100 66     104 croak 'Second argument to set_bible_data() must be an arrayref of arrayrefs'
908             unless ( $book_data and ref $book_data eq 'ARRAY' );
909              
910 2         6 for (@$book_data) {
911 41 50 66     373 croak 'Second argument to set_bible_data() does not appear valid' unless (
      66        
      66        
      33        
912             ref $_ eq 'ARRAY' and
913             not ref $_->[0] and length $_->[0] > 0 and
914             not ref $_->[1] and length $_->[1] > 0
915             );
916             }
917              
918 1 50       6 unless ($verse_data) {
919 1         7 _build_bible_template( 'Orthodox' => $bible, $self->_bibles );
920 1         6 $self->_bibles->{$bible}[0] = $book_data;
921             }
922             else {
923 0         0 $self->_bibles->{$bible}[0] = $book_data;
924 0         0 $self->_bibles->{$bible}[1] = $verse_data;
925             }
926              
927 1         45 $self->bible($bible);
928 1         9 return $self;
929             }
930              
931 1     1 1 2541 sub get_bible_structure ( $self, $bible = undef ) {
  1         3  
  1         3  
  1         2  
932 1 50       8 $self->bible($bible) if ($bible);
933 1         5 return [ map { [ $_, $self->_bible_data->{lengths}{$_} ] } @{ $self->_bible_data->{books} } ];
  84         776  
  1         6  
934             }
935              
936 2     2 1 3588 sub identify_bible ( $self, @books ) {
  2         5  
  2         6  
  2         3  
937 2 100       217 croak('No books supplied; must supply at least 1 input') unless (@books);
938              
939 1         7 my $obj = $self->new( minimum_book_length => $self->minimum_book_length );
940             my $bibles = [
941 12         27 sort { $b->{count} <=> $a->{count} }
942             map {
943 7         53 $obj->bible($_);
944 7         62 my $books = scalar( $obj->clear->in(@books)->as_books );
945             {
946 7         64 name => $_,
947             books => $books,
948             count => scalar(@$books),
949             };
950             }
951 1         4 keys %{ $obj->_bibles }
  1         5  
952             ];
953              
954 7         26 $bibles = [ grep { $bibles->[0]{count} == $_->{count} } @$bibles ]
955 1 50       8 if ( $bibles->[0]{count} != $bibles->[-1]{count} );
956              
957 1         3694 return $bibles;
958             }
959              
960             1;
961              
962             __END__