File Coverage

blib/lib/Religion/Bible/Regex/Reference.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package Religion::Bible::Regex::Reference;
2              
3 1     1   48607 use strict;
  1         4  
  1         53  
4 1     1   5 use warnings;
  1         2  
  1         33  
5              
6             # Input files are assumed to be in the UTF-8 strict character encoding.
7 1     1   1142 use utf8;
  1         17  
  1         5  
8             binmode(STDIN, ":utf8");
9             binmode(STDOUT, ":utf8");
10             binmode(STDERR, ":utf8");
11              
12 1     1   224 use Carp;
  1         2  
  1         108  
13 1     1   1394 use Storable qw(store retrieve freeze thaw dclone);
  1         4861  
  1         231  
14 1     1   1352 use Data::Dumper;
  1         12763  
  1         88  
15              
16 1     1   481 use Religion::Bible::Regex::Config;
  0            
  0            
17             use version; our $VERSION = '0.95';
18              
19             ##################################################################################
20             # Configuration options:
21             # reference.full_book_name: true/false
22             # reference.abbreviation.map: true/false
23             # reference.cvs: Chapitre/Verset Separateur
24             ##################################################################################I
25              
26             # Defaults and Constants
27             # our %configuration_defaults = (
28             # verse_list_separateur => ', ',
29             # chapter_list_separateur => '; ',
30             # book_list_separateur => '; ',
31             # );
32              
33             # These constants are defined in several places and probably should be moved to a common file
34             # Move these to Constants.pm
35             use constant BOOK => 'BOOK';
36             use constant CHAPTER => 'CHAPTER';
37             use constant VERSE => 'VERSE';
38             use constant UNKNOWN => 'UNKNOWN';
39             use constant TRUE => 1;
40             use constant FALSE => 0;
41              
42             sub new {
43             my ($class, $config, $regex) = @_;
44             my ($self) = {};
45             bless $self, $class;
46             $self->{'regex'} = $regex;
47             $self->{'config'} = $config;
48             return $self;
49             }
50              
51             # sub _initialize_default_configuration {
52             # my $self = shift;
53             # my $defaults = shift;
54              
55             # while ( my ($key, $value) = each(%{$defaults}) ) {
56             # $self->set($key, $value) unless defined($self->{mainconfig}{$key});
57             # }
58             # }
59              
60             # Subroutines related to getting information
61             # Returns a reference to a Religion::Bible::Regex::Builder object.
62             sub get_regexes {
63             my $self = shift;
64             confess "regex is not defined\n" unless defined($self->{regex});
65             return $self->{regex};
66             }
67              
68             # Returns a reference to a Religion::Bible::Regex::Config object.
69             sub get_configuration {
70             my $self = shift;
71             confess "config is not defined\n" unless defined($self->{config});
72             return $self->{config};
73             }
74              
75             # Returns the private hash that contains the Bible Reference
76             sub get_reference_hash { return shift->{'reference'}; }
77             sub reference { get_reference_hash(@_); }
78              
79             # Getters
80             sub key { shift->{'reference'}{'data'}{'key'}; }
81             sub c { shift->{'reference'}{'data'}{'c'}; }
82             sub v { shift->{'reference'}{'data'}{'v'}; }
83              
84             sub key2 { shift->{'reference'}{'data'}{'key2'}; }
85             sub c2 { shift->{'reference'}{'data'}{'c2'}; }
86             sub v2 { shift->{'reference'}{'data'}{'v2'}; }
87              
88             sub ob { shift->{'reference'}{'original'}{'b'}; }
89             sub ob2 { shift->{'reference'}{'original'}{'b2'}; }
90             sub oc { shift->{'reference'}{'original'}{'c'}; }
91             sub oc2 { shift->{'reference'}{'original'}{'c2'}; }
92             sub ov { shift->{'reference'}{'original'}{'v'}; }
93             sub ov2 { shift->{'reference'}{'original'}{'v2'}; }
94              
95             # We could simply write these functions as
96             # sub s2 { shift->{'reference'}{'spaces'}{'s2'}; }
97             # However, if there are no spaces defined this code will defined an empty hash, shift->{'reference'}{'spaces'}.
98             # I want these functions to have absolutely no side-effects, so therefore I'm going to write them in a bit longer style
99             sub s2 { my $s = shift; return unless defined($s->{'reference'}{'spaces'}); return $s->{'reference'}{'spaces'}{'s2'}; }
100             sub s3 { my $s = shift; return unless defined($s->{'reference'}{'spaces'}); return $s->{'reference'}{'spaces'}{'s3'}; }
101             sub s4 { my $s = shift; return unless defined($s->{'reference'}{'spaces'}); return $s->{'reference'}{'spaces'}{'s4'}; }
102             sub s5 { my $s = shift; return unless defined($s->{'reference'}{'spaces'}); return $s->{'reference'}{'spaces'}{'s5'}; }
103             sub s6 { my $s = shift; return unless defined($s->{'reference'}{'spaces'}); return $s->{'reference'}{'spaces'}{'s6'}; }
104             sub s7 { my $s = shift; return unless defined($s->{'reference'}{'spaces'}); return $s->{'reference'}{'spaces'}{'s7'}; }
105             sub s8 { my $s = shift; return unless defined($s->{'reference'}{'spaces'}); return $s->{'reference'}{'spaces'}{'s8'}; }
106             sub s9 { my $s = shift; return unless defined($s->{'reference'}{'spaces'}); return $s->{'reference'}{'spaces'}{'s9'}; }
107              
108             sub book {
109             my $self = shift;
110             return $self->get_regexes->book($self->key);
111             }
112             sub book2 {
113             my $self = shift;
114             return $self->get_regexes->book($self->key2);
115             }
116             sub abbreviation {
117             my $self = shift;
118             return $self->get_regexes->abbreviation($self->key);
119             }
120             sub abbreviation2 {
121             my $self = shift;
122             return $self->get_regexes->abbreviation($self->key2);
123             }
124             sub context_words { shift->{'reference'}{'data'}{'context_words'}; }
125             sub cvs { shift->{'reference'}{'info'}{'cvs'}; }
126             sub dash { shift->{'reference'}{'info'}{'dash'}; }
127              
128             # Subroutines for book, abbreviation and key conversions
129             sub abbreviation2book {}
130             sub book2abbreviation {}
131             sub key2book {}
132             sub key2abbreviation {}
133             sub book2key {}
134             sub abbreviation2key {}
135              
136             # Subroutines for setting
137             sub set_key {
138             my $self = shift;
139             my $e = shift;
140             return unless (_non_empty($e));
141             $self->{'reference'}{'data'}{'key'} = $e;
142             }
143             sub set_c {
144             my $self = shift;
145             my $e = shift;
146             return unless (_non_empty($e));
147             $self->{'reference'}{'data'}{'c'} = $e;
148             $self->{'reference'}{'original'}{'c'} = $e;
149             }
150             sub set_v {
151             my $self = shift;
152             my $e = shift;
153              
154             my $r = $self->get_regexes;
155             return unless (_non_empty($e));
156             if ($e =~ m/($r->{'verse_number'})($r->{'verse_letter'})/) {
157             $self->{'reference'}{'data'}{'v'} = $1 if defined($1);
158             $self->{'reference'}{'data'}{'vletter'} = $2 if defined($2);
159             } else {
160             $self->{'reference'}{'data'}{'v'} = $e;
161             }
162             $self->{'reference'}{'original'}{'v'} = $e;
163             }
164              
165             sub set_key2 {
166             my $self = shift;
167             my $e = shift;
168             return unless (_non_empty($e));
169             $self->{'reference'}{'data'}{'key2'} = $e;
170             }
171              
172             sub set_ob {
173             my $self = shift;
174             my $e = shift;
175             return unless (_non_empty($e));
176             $self->{'reference'}{'original'}{'b'} = $e;
177             }
178              
179             sub set_ob2 {
180             my $self = shift;
181             my $e = shift;
182             return unless (_non_empty($e));
183             $self->{'reference'}{'original'}{'b2'} = $e;
184             }
185              
186             sub set_b {
187             my $self = shift;
188             my $e = shift;
189             return unless (_non_empty($e));
190             $self->{'reference'}{'original'}{'b'} = $e;
191              
192             # If there is a key then create the book2key and abbreviation2key associations
193             my $key = $self->get_regexes->key($e);
194             unless (defined($key)) {
195             print Dumper $self->{'regex'}{'book2key'};
196             print Dumper $self->{'regex'}{'abbreviation2key'};
197             croak "Book or Abbreviation must be defined in the configuration file: $e\n";
198             }
199             $self->{'reference'}{'data'}{'key'} = $self->get_regexes->key($e);
200             }
201             sub set_b2 {
202             my $self = shift;
203             my $e = shift;
204             return unless (_non_empty($e));
205              
206             $self->{'reference'}{'original'}{'b2'} = $e;
207             $self->{'reference'}{'data'}{'key2'} = $self->get_regexes->key($e);
208             }
209             sub set_c2 {
210             my $self = shift;
211             my $e = shift;
212             return unless (_non_empty($e));
213             $self->{'reference'}{'data'}{'c2'} = $e;
214             $self->{'reference'}{'original'}{'c2'} = $e;
215             }
216             sub set_v2 {
217             my $self = shift;
218             my $e = shift;
219              
220             my $r = $self->get_regexes;
221             return unless (_non_empty($e));
222             if ($e =~ m/($r->{'verse_number'})($r->{'verse_letter'})/) {
223             $self->{'reference'}{'data'}{'v2'} = $1 if (defined($1));
224             $self->{'reference'}{'data'}{'v2letter'} = $2 if (defined($1));
225             } else {
226             $self->{'reference'}{'data'}{'v2'} = $e;
227             }
228             $self->{'reference'}{'original'}{'v2'} = $e;
229             }
230             sub set_context_words {
231             my $self = shift;
232             my $e = shift;
233             return unless (_non_empty($e));
234             $self->{'reference'}{'data'}{'context_words'} = $e;
235             }
236              
237             # Setors for spaces
238             # Ge 1:1-Ap 21:22
239             # This shows how each of the areas that have the potential
240             # for a space are defined.
241             # Ge(s2)1(s3):(s4)1(s5)-(s6)Ap(s7)21(s8):(s9)22
242             sub set_s2 {
243             my $self = shift;
244             my $e = shift;
245             return unless (_non_empty($e));
246             $self->{'reference'}{'spaces'}{'s2'} = $e;
247             }
248             sub set_s3 {
249             my $self = shift;
250             my $e = shift;
251             return unless (_non_empty($e));
252             $self->{'reference'}{'spaces'}{'s3'} = $e;
253             }
254             sub set_s4 {
255             my $self = shift;
256             my $e = shift;
257             return unless (_non_empty($e));
258             $self->{'reference'}{'spaces'}{'s4'} = $e;
259             }
260             sub set_s5 {
261             my $self = shift;
262             my $e = shift;
263             return unless (_non_empty($e));
264             $self->{'reference'}{'spaces'}{'s5'} = $e;
265             }
266             sub set_s6 {
267             my $self = shift;
268             my $e = shift;
269             return unless (_non_empty($e));
270             $self->{'reference'}{'spaces'}{'s6'} = $e;
271             }
272             sub set_s7 {
273             my $self = shift;
274             my $e = shift;
275             return unless (_non_empty($e));
276             $self->{'reference'}{'spaces'}{'s7'} = $e;
277             }
278             sub set_s8 {
279             my $self = shift;
280             my $e = shift;
281             return unless (_non_empty($e));
282             $self->{'reference'}{'spaces'}{'s8'} = $e;
283             }
284             sub set_s9 {
285             my $self = shift;
286             my $e = shift;
287             return unless (_non_empty($e));
288             $self->{'reference'}{'spaces'}{'s9'} = $e;
289             }
290              
291              
292             sub set_cvs {
293             my $self = shift;
294             my $e = shift;
295             return unless (_non_empty($e));
296             $self->{'reference'}{'info'}{'cvs'} = $e;
297             }
298             sub set_dash {
299             my $self = shift;
300             my $e = shift;
301             return unless (_non_empty($e));
302             $self->{'reference'}{'info'}{'dash'} = $e;
303             }
304              
305             sub book_type {
306             my $self = shift;
307             return 'NONE' unless (_non_empty($self->ob));
308             return 'CANONICAL_NAME' if ($self->ob =~ m/@{[$self->get_regexes->{'livres'}]}/);
309             return 'ABBREVIATION' if ($self->ob =~ m/@{[$self->get_regexes->{'abbreviations'}]}/);
310             return 'UNKNOWN';
311             }
312              
313             sub formatted_book {
314             my $self = shift;
315             my $book_format = shift || 'ORIGINAL';
316             my $ret = '';
317              
318             # Check to be sure that book_format has a proper value, if it doesn't then warn and set it
319             if (!($book_format eq 'ORIGINAL' || $book_format eq 'CANONICAL_NAME' || $book_format eq 'ABBREVIATION')) {
320             confess "book_format should be either 'ORIGINAL', 'CANONICAL_NAME', 'ABBREVIATION'";
321             $book_format = 'ORIGINAL';
322             }
323              
324             if ($book_format eq 'ABBREVIATION' || ($book_format eq 'ORIGINAL' && $self->book_type eq 'ABBREVIATION')) {
325             $ret .= $self->abbreviation || '';
326             } else {
327             $ret .= $self->book || '';
328             }
329              
330             return $ret;
331             }
332              
333             sub formatted_book2 {
334             my $self = shift;
335             my $book_format = shift || 'ORIGINAL';
336             my $ret = '';
337              
338             # Check to be sure that book_format has a proper value, if it doesn't then warn and set it
339             if (!($book_format eq 'ORIGINAL' || $book_format eq 'CANONICAL_NAME' || $book_format eq 'ABBREVIATION')) {
340             confess "book_format should be either 'ORIGINAL', 'CANONICAL_NAME', 'ABBREVIATION'";
341             $book_format = 'ORIGINAL';
342             }
343              
344             if ($book_format eq 'ABBREVIATION' || ($book_format eq 'ORIGINAL' && $self->book_type eq 'ABBREVIATION')) {
345             $ret .= $self->abbreviation2 || '';
346             } else {
347             $ret .= $self->book2 || '';
348             }
349              
350             return $ret;
351             }
352              
353             sub set {
354             my $self = shift;
355             my $r = shift;
356             my $context = shift;
357              
358             $self->{reference} = {};
359             $self->{reference} = dclone($context->{reference}) if defined($context->{reference});
360              
361             # $r must be a defined hash
362             return unless(defined($r) && ref($r) eq 'HASH');
363              
364             # Save the words that provide context
365             $self->set_context_words($r->{context_words});
366              
367             # Set the main part of the reference
368             if (defined($r->{key})) {
369             $self->set_key($r->{key}); # Key
370             } else {
371             $self->set_b($r->{b}); # Match Book
372             }
373              
374             $self->set_ob($r->{ob}); # Original book or abbreviation
375             $self->set_c($r->{c}); # Chapter
376             $self->set_v($r->{v}); # Verse
377              
378             # Set the range part of the reference
379             if (defined($r->{key2})) {
380             $self->set_key2($r->{key2}); # Key
381             } else {
382             $self->set_b2($r->{b2}); # Match Book
383             }
384              
385             $self->set_ob2($r->{ob2}); # Chapter
386             $self->set_c2($r->{c2}); # Chapter
387             $self->set_v2($r->{v2}); # Verse
388              
389             # Set the formatting and informational parts
390             $self->set_cvs($r->{cvs}) if ((defined($r->{c}) && defined($r->{v})) || (defined($r->{c2}) && defined($r->{v2}))); # The Chapter Verse Separtor
391             $self->set_dash($r->{dash}); # The reference range operator
392              
393             # If this is a book with only one chapter then be sure that chapter is set to '1'
394             if(((defined($self->book) && $self->book =~ m/@{[$self->get_regexes->{'livres_avec_un_chapitre'}]}/) ||
395             (defined($self->abbreviation) && $self->abbreviation =~ m/@{[$self->get_regexes->{'livres_avec_un_chapitre'}]}/)) &&
396             !(defined($self->c) && defined($self->c) && $self->c eq '1')) {
397             $self->set_v($self->c);
398             $self->set_c('1');
399             $self->set_cvs(':');
400             }
401              
402             # Set the spaces
403             # Ge(s2)1(s3):(s4)1(s5)-(s6)Ap(s7)21(s8):(s9)22
404              
405             $self->set_s2($r->{s2});
406             $self->set_s3($r->{s3});
407             $self->set_s4($r->{s4});
408             $self->set_s5($r->{s5});
409             $self->set_s6($r->{s6});
410             $self->set_s7($r->{s7});
411             $self->set_s8($r->{s8});
412             $self->set_s9($r->{s9});
413              
414             }
415              
416             ##################################################################################
417             # Reference Parsing
418             ##################################################################################
419             sub parse {
420             my $self = shift;
421             my $token = shift;
422             my $state = shift;
423             my $context_words = '';
424             ($context_words, $state) = $self->parse_context_words($token, $state);
425              
426             my $r = $self->get_regexes;
427             my $spaces = '[\s ]*';
428            
429             # type: LCVLCV
430             if ($token =~ m/($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)($r->{'intervale'})($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)/x) {
431              
432             $self->set({b=>$2, s2=>$3, c=>$4, s3=>$5, cvs=>$6, s4=>$7, v=>$8, s5=>$9, dash=>$10, s6=>$11, b2=>$12, s7=>$13, c2=>$14, s8=>$15, s9=>$17, v2=>$18, context_words=>$context_words});
433             }
434            
435             # Ge(s2)1(s3):(s4)1(s5)-(s6)Ap(s7)21(s8):(s9)22
436             # type: LCVLC
437             elsif ($token =~ m/($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)($r->{'intervale'})($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)/x) {
438            
439             $self->set({ b=>$2, s2=>$3, c=>$4, s3=>$5, cvs=>$6, s4=>$7, v=>$8, s5=>$9, dash=>$10, s6=>$11, b2=>$12, s7=>$13, c2=>$14, s8=>$15, context_words=>$context_words });
440             }
441              
442             # Ge(s2)1(s3):(s4)1(s5)-(s6)Ap(s7)21(s8):(s9)22
443             # type: LCLCV
444             elsif ($token =~ m/($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'intervale'})($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)/x) {
445            
446             $self->set({ b=>$2, s2=>$3, c=>$4, s3=>$5, dash=>$6, s6=>$7, b2=>$8, s7=>$9, c2=>$10, s8=>$11, cvs=>$12, s9=>$13, v2=>$14, context_words=>$context_words });
447             }
448              
449             # type: LCVCV
450             elsif ($token =~ m/($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)($r->{'intervale'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)/x) {
451            
452             $self->set({ b=>$2, s2=>$3, c=>$4, s3=>$5, cvs=>$6, s4=>$7, v=>$8, s5=>$9, dash=>$10, s6=>$11, c2=>$12, s8=>$13, s9=>$15, v2=>$16, context_words=>$context_words});
453             }
454              
455             # Ge(s2)1(s3):(s4)1(s5)-(s6)Ap(s7)21(s8):(s9)22
456             # type: LCLC
457             elsif ($token =~ m/($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'intervale'})($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)/x) {
458            
459             $self->set({ b=>$2, s2=>$3, c=>$4, s3=>$5, dash=>$6, s6=>$7, b2=>$8, s7=>$9, c2=>$10, s8=>$11, context_words=>$context_words });
460             }
461              
462             # type: LCCV
463             elsif ($token =~ m/($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'intervale'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)/x) {
464            
465             $self->set({b=>$2, s2=>$3, c=>$4, s3=>$5, dash=>$6, s6=>$7, c2=>$8, s8=>$9, cvs=>$10, s9=>$11, v2=>$12, context_words=>$context_words});
466             }
467              
468             # type: LCVV
469             elsif ($token =~ m/($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)($r->{'intervale'})($spaces)($r->{'verset'})($spaces)/x) {
470            
471             $self->set({b=>$2, s2=>$3, c=>$4, s3=>$5, cvs=>$6, s4=>$7, v=>$8, s5=>$9, dash=>$10, s6=>$11, v2=>$12, s7=>$13, context_words=>$context_words});
472             }
473              
474             # type: LCV
475             elsif ($token =~ m/($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)/x) {
476            
477             $self->set({b=>$2, s2=>$3, c=>$4, s3=>$5, cvs=>$6, s4=>$7, v=>$8, s5=>$9, context_words=>$context_words});
478             }
479              
480             # type: LCC
481             elsif ($token =~ m/($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)($r->{'intervale'})($spaces)($r->{'chapitre'})($spaces)/x) {
482            
483             $self->set({b=>$2, s2=>$3, c=>$4, s3=>$5, dash=>$6, s6=>$7, c2=>$8, s7=>$9, context_words=>$context_words});
484             }
485              
486             # type: LC
487             elsif ($token =~ m/($spaces)($r->{'livres_et_abbreviations'})($spaces)($r->{'chapitre'})($spaces)/x) {
488             $self->set({b=>$2, s2=>$3, c=>$4, s3=>$5, context_words=>$context_words});
489             } else {
490             $self->parse_chapitre($token, $state, $context_words);
491             }
492             return $self;
493             }
494              
495             sub parse_chapitre {
496             my $self = shift;
497             my $token = shift;
498             my $state = shift;
499             my $context_words = shift;
500             my $r = $self->get_regexes;
501             my $spaces = '[\s ]*';
502              
503             # We are here!
504              
505             # Ge(s2)1(s3):(s4)1(s5)-(s6)Ap(s7)21(s8):(s9)22
506             # type: CVCV
507             if ($token =~ m/($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)($r->{'intervale'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)/x) {
508             $state = 'match';
509             $self->set({ s2=>$1, c=>$2, s3=>$3, cvs=>$4, s4=>$5, v=>$6, s5=>$7, dash=>$8, s6=>$9, c2=>$10, s8=>$11, s9=>$13, v2=>$14, context_words=>$context_words });
510             }
511              
512             # type: CCV
513             elsif ($token =~ m/($spaces)($r->{'chapitre'})($spaces)($r->{'intervale'})($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)/x) {
514             $state = 'match';
515             $self->set({ s2=>$1, c=>$2, s3=>$3, dash=>$4, s6=>$5, c2=>$6, s8=>$7, cvs=>$8, s9=>$9, v2=>$10, context_words=>$context_words });
516             }
517              
518             # type: CVV
519             elsif ($token =~ m/($spaces)($r->{'chapitre'})($spaces)($r->{'cv_separateur'})($spaces)($r->{'verset'})($spaces)($r->{'intervale'})($spaces)($r->{'verset'})($spaces)/x) {
520             $state = 'match';
521             $self->set({ s2=>$1, c=>$2, s3=>$3, cvs=>$4, s4=>$5, v=>$6, s5=>$7, dash=>$8, s6=>$9, v2=>$10, s7=>$11, context_words=>$context_words });
522             }
523              
524             # type: CV
525             elsif ($token =~ m/([\s ]*)($r->{'chapitre'})([\s ]*)($r->{'cv_separateur'})([\s ]*)($r->{'verset'})([\s ]*)/x) {
526             $state = 'match';
527             $self->set({ s2=>$1, c=>$2, s3=>$3, cvs=>$4, s4=>$5, v=>$6, s5=>$7, context_words=>$context_words });
528             }
529              
530             # type: CC
531             elsif ($token =~ m/($spaces)($r->{'chapitre'})($spaces)($r->{'intervale'})($spaces)($r->{'chapitre'})($spaces)/ && $state eq CHAPTER) {
532             $state = 'match';
533             $self->set({ s2=>$1, c=>$2, s3=>$3, dash=>$4, s4=>$5, c2=>$6, s7=>$7, context_words=>$context_words });
534             }
535              
536             # type: C
537             elsif ($token =~ m/([\s ]*)($r->{'chapitre'})([\s ]*)/ && $state eq CHAPTER) {
538             # elsif ($token =~ m/([\s ]*)($r->{'chapitre'})([\s ]*)/) {
539             $state = 'match';
540             $self->set({ s2=>$1, c=>$2, s3=>$3, context_words=>$context_words });
541             }
542              
543             # Cet un Verset
544             else {
545             $self->parse_verset($token, $state, $context_words);
546             }
547             }
548              
549             sub parse_verset {
550             my $self = shift;
551             my $token = shift;
552             my $state = shift;
553             my $context_words = shift;
554             my $r = $self->get_regexes;
555              
556             my $spaces = '[\s ]*';
557              
558             unless (defined($state)) {
559             carp "\n\n$token: " .__LINE__ ."\n\n";
560             }
561             # Ge(s2)1(s3):(s4)1(s5)-(s6)Ap(s7)21(s8):(s9)22
562             # type: VV
563             if ($token =~ m/($spaces)($r->{'verset'})($spaces)($r->{'intervale'})($spaces)($r->{'verset'})($spaces)/ && $state eq VERSE) {
564             $state = 'match';
565             $self->set({s2=>$1, v=>$2, s5=>$3, dash=>$4, s6=>$5, v2=>$6, context_words=>$context_words});
566             }
567            
568             # type: V
569             elsif ($token =~ m/([\s ]*)($r->{'verset'})([\s ]*)/ && $state eq VERSE) {
570             $state = 'match';
571             $self->set({s2=>$1, v=>$2, s5=>$3, context_words=>$context_words});
572             }
573              
574             # Error
575             else {
576             $self->set({type => 'Error'});
577             }
578             }
579              
580             ################################################################################
581             # Format Section
582             # This section provides a default normalize form that is useful for various
583             # operations with references
584             ################################################################################
585             sub parse_context_words {
586             my $self = shift;
587             my $refstr = shift;
588             my $r = $self->get_regexes;
589             my $spaces = '[\s ]*';
590             my $state = shift;
591             my $header = '';
592              
593             if ($refstr =~ m/^($r->{'livres_et_abbreviations'})(?:$spaces)(?:$r->{'cv_list'})/) {
594             # $header = $1; $state = BOOK;
595             $state = BOOK;
596             } elsif ($refstr =~ m/^($r->{'chapitre_mots'})(?:$spaces)(?:$r->{'cv_list'})/) {
597             $header = $1; $state = CHAPTER;
598             } elsif ($refstr =~ m/($r->{'verset_mots'})(?:$spaces)(?:$r->{'cv_list'})/) {
599             $header = $1; $state = VERSE;
600             }
601             return ($header, $state);
602             }
603              
604             sub formatted_context_words {
605             my $self = shift;
606             my $ret = '';
607            
608             # Only print the context words if state is chapter or verse
609             #if ($self->state_is_chapitre || $self->state_is_verset) {
610             $ret .= $self->context_words || '';
611             #}
612              
613             return $ret;
614             }
615              
616             sub formatted_c { shift->c || ''; }
617             sub formatted_v { shift->v || ''; }
618             sub formatted_c2 { shift->c2 || ''; }
619             sub formatted_v2 { shift->v2 || ''; }
620              
621             sub formatted_cvs {
622             my $self = shift;
623             my $state = shift || 'BOOK';
624             my $book_format = shift || 'ORIGINAL';
625            
626             # if C and V exist then return ...
627             # 1. The value given in the configuation file or ...
628             # 2. The value parsed from the original reference
629             # 3. ':'
630             # if C and V do not exist then return ''
631             return (
632             (_non_empty($self->c) && _non_empty($self->v))
633             ?
634             (defined($self->get_configuration->get('reference','cvs'))
635             ?
636             $self->get_configuration->get('reference','cvs')
637             :
638             (defined( $self->cvs ) ? $self->cvs : ':'))
639             :
640             '');
641             }
642              
643             sub formatted_cvs2 {
644             my $self = shift;
645             my $state = shift || 'BOOK';
646             my $book_format = shift || 'ORIGINAL';
647            
648             # if C and V exist then return ...
649             # 1. The value given in the configuation file or ...
650             # 2. The value parsed from the original reference
651             # 3. ':'
652             # if C and V do not exist then return ''
653             return (
654             (_non_empty($self->c2) && _non_empty($self->v2))
655             ?
656             (defined($self->get_configuration->get('reference','cvs'))
657             ?
658             $self->get_configuration->get('reference','cvs')
659             :
660             (defined( $self->cvs ) ? $self->cvs : ':'))
661             :
662             '');
663             }
664              
665             sub formatted_interval {
666             my $self = shift;
667             my $state = shift || 'BOOK';
668             my $book_format = shift || 'ORIGINAL';
669            
670             # if C and V exist then return ...
671             # 1. The value given in the configuation file or ...
672             # 2. The value parsed from the original reference
673             # 3. '-'
674             # if C and V do not exist then return ''
675             return ((_non_empty($self->formatted_book2) || _non_empty($self->c2) || _non_empty($self->v2) )
676             ?
677             (defined($self->get_configuration->get('reference','intervale'))
678             ?
679             $self->get_configuration->get('reference','intervale')
680             :
681             (defined( $self->dash ) ? $self->dash : ':'))
682             :
683             '');
684             }
685              
686             sub formatted_normalize {
687             my $self = shift;
688             my $state = shift || 'BOOK';
689             my $book_format = shift || 'ORIGINAL';
690             my $ret = '';
691            
692             # These variables are used as caches in this function so we don't need to find there values multiple times
693             my ($book, $book2, $c, $c2) = ('','','','');
694              
695             if (defined($self->book) && defined($self->book2) || (!(defined($self->v) || defined($self->v2)) && $state eq 'VERSE') ) {
696             $state = 'BOOK';
697             } elsif (defined($self->c) && defined($self->c2) && $state eq 'VERSE') {
698             $state = 'CHAPTER';
699             }
700              
701             if (_non_empty($self->formatted_context_words)) {
702             $ret .= $self->formatted_context_words;
703             $ret .= ' ' if defined($self->s2);
704             }
705              
706             # Write out the context words and the book or abbreviation
707             if ($state eq 'BOOK') {
708             $ret .= $book = $self->formatted_book($book_format);
709             $ret .= ' ' if defined($self->s2) && _non_empty($self->formatted_book($book_format));
710             }
711              
712             # Write out the chapter and the chapter/verse separator
713             if ($state eq 'BOOK' || $state eq 'CHAPTER') {
714             $ret .= $c = $self->formatted_c;
715             $ret .= $self->formatted_cvs;
716             }
717              
718             # Write out the verse
719             $ret .= $self->formatted_v;
720              
721             # Write out the interval character to connect two references as a range of verses
722             if ($self->has_interval) {
723             $ret .= '-';
724              
725             # Write out the second book or abbreviation
726             $book2 = $self->formatted_book2($book_format);
727             $ret .= $book2 if ($book ne $book2);
728              
729             # If there is a space defined after book2 and we are not printing the same book twice then ' '
730             $ret .= ' ' if (defined($self->s7) && $book ne $book2);
731              
732             # Write out the chapter
733             $c2 = $self->formatted_c2;
734             $ret .= $c2 if ($c ne $c2);
735              
736             # Write out the second chapter/verse separator
737             $ret .= $self->formatted_cvs2 if defined($self->c2) && defined($self->v2) && ($c ne $c2);
738              
739             # Write out the second verse
740             $ret .= $self->formatted_v2;
741             }
742             return $ret;
743             }
744              
745             # When debugging I don't want to type normalize over and over again
746             sub n { return shift->normalize; }
747              
748             sub bol {
749             my $self = shift;
750             my $state = shift || 'BOOK';
751             my $book_format = shift || 'ORIGINAL';
752             my $ret = '';
753            
754             # These variables are used as caches in this function so we don't need to find there values multiple times
755             my ($book, $book2, $c, $c2) = ('','','','');
756              
757             if ((!(defined($self->v) || defined($self->v2)) && $state eq 'VERSE')) {
758             $state = 'BOOK';
759             } elsif (defined($self->c) && defined($self->c2) && $state eq 'VERSE') {
760             $state = 'CHAPTER';
761             }
762              
763             # Write out the context words and the book or abbreviation
764             if ($state eq 'BOOK') {
765             # $ret .= $self->formatted_context_words($state, $book_format);
766             $ret .= $book = $self->formatted_book($book_format);
767             $ret .= ' ' if defined($self->s2);
768             }
769              
770             # Write out the chapter and the chapter/verse separator
771             if ($state eq 'BOOK' || $state eq 'CHAPTER') {
772             $ret .= $c = $self->formatted_c;
773             $ret .= (_non_empty($self->c) && ! _non_empty($self->v)) ? '$' : '';
774             $ret .= $self->formatted_cvs;
775             }
776              
777             # Write out the verse
778             $ret .= $self->formatted_v;
779              
780             # Write out the interval character to connect two references as a range of verses
781             $ret .= $self->formatted_interval;
782              
783             # Get book2 formatted
784             $book2 = $self->formatted_book2($book_format);
785              
786             # Write out the second book or abbreviation
787             if ($state eq 'BOOK' && _non_empty($book2) && $book ne $book2) {
788             $ret .= $book2;
789              
790             # If there is a space defined after book2 and we are not printing the same book twice then ' '
791             $ret .= ' ' if (defined($self->s7));
792             }
793              
794             # Write out the chapter
795             $c2 = $self->formatted_c2;
796             if (_non_empty($c) && $c ne $c2 && ($state eq 'BOOK' || $state eq 'CHAPTER')) {
797             $ret .= $c2;
798             $ret .= (_non_empty($self->c2) && ! _non_empty($self->v2)) ? '$' : '';
799             # Write out the second chapter/verse separator
800             $ret .= $self->formatted_cvs2;
801             }
802              
803             # Write out the second verse
804             $ret .= $self->formatted_v2;
805              
806             return $ret;
807             }
808              
809             sub normalize {
810             my $self = shift;
811             my $ret = '';
812            
813             # These variables are used as caches in this function so we don't need to find there values multiple times
814             my ($book, $book2, $c, $c2) = ('','','','');
815              
816             # Write out the context words and the book or abbreviation
817             $ret .= $self->formatted_context_words;
818             $ret .= $book = $self->formatted_book('CANONICAL_NAME');
819             $ret .= ' ' if defined($self->s2);
820              
821             # Write out the chapter and the chapter/verse separator
822             $ret .= $c = $self->formatted_c;
823             $ret .= ':' if defined($self->c) && defined($self->v);
824              
825             # Write out the verse
826             $ret .= $self->formatted_v;
827              
828             # Write out the interval character to connect two references as a range of verses
829             if ($self->has_interval) {
830             $ret .= '-';
831              
832             # Write out the second book or abbreviation
833             $book2 = $self->formatted_book2('CANONICAL_NAME');
834             $ret .= $book2 if ($book ne $book2);
835              
836             # If there is a space defined after book2 and we are not printing the same book twice then ' '
837             $ret .= ' ' if (defined($self->s7) && $book ne $book2);
838              
839             # Write out the chapter
840             $c2 = $self->formatted_c2;
841             $ret .= $c2 if ($c ne $c2);
842              
843             # Write out the second chapter/verse separator
844             $ret .= ':' if defined($self->c2) && defined($self->v2) && ($c ne $c2);
845            
846             # Write out the second verse
847             $ret .= $self->formatted_v2;
848             }
849             return $ret;
850             }
851              
852              
853             ##################################################################################
854             # State Helpers
855             #
856             # The context of a reference refers to the first part of it defined...
857             # For example: 'Ge 1:1' has its book, chapter and verse parts defined. So its
858             # state is 'explicit' This means it is a full resolvable reference
859             # '10:1' has its chapter and verse parts defined. So its
860             # context is 'chapitre'
861             # 'v. 1' has its verse part defined. So its context is 'verset'
862             #
863             ##################################################################################
864             sub state_is_chapitre {
865             my $self = shift;
866             return _non_empty($self->c) && !$self->is_explicit;
867             }
868              
869             sub state_is_verset {
870             my $self = shift;
871             return _non_empty($self->v) && !_non_empty($self->c) && !$self->is_explicit;
872             }
873              
874             # The state of a reference can have three values BOOK, CHAPTER or VERSE.
875             # To find the state of a reference choose the leftmost value that exists in
876             # that reference
877             #
878             # Examples:
879             # 'Ge 1:2' has a state of 'BOOK'
880             # '1:2' has a state of 'CHAPTER'
881             # '2' has a state of 'VERSE'
882             sub state_is_book {
883             my $self = shift;
884             return $self->is_explicit;
885             }
886              
887             sub state {
888             my $self = shift;
889             return 'BOOK' if $self->state_is_book;
890             return 'CHAPTER' if $self->state_is_chapitre;
891             return 'VERSE' if $self->state_is_verset;
892             return 'UNKNOWN';
893             }
894              
895             # The context of a reference can have three values BOOK, CHAPTER or VERSE.
896             # To find the state of a reference choose the rightmost value that exists in
897             # that reference
898             #
899             # Examples:
900             # 'Ge 1:1' has a state of 'VERSE'
901             # 'Ge 1' has a state of 'CHAPTER'
902             # 'Ge' has a state of 'BOOK' note: a valid reference must be either CHAPTER or VERSE and not simply BOOK
903             # TODO: write tests
904             sub context_is_verset {
905             my $self = shift;
906             return _non_empty($self->v) || _non_empty($self->v2);
907             }
908              
909             sub context_is_chapitre {
910             my $self = shift;
911             return (_non_empty($self->c) || _non_empty($self->c2)) && !$self->context_is_verset;
912             }
913              
914             sub context_is_book {
915             my $self = shift;
916             return (_non_empty($self->formatted_book) || _non_empty($self->formatted_book2)) && !$self->context_is_chapitre;
917             }
918              
919             sub context {
920             my $self = shift;
921             return 'BOOK' if $self->context_is_book;
922             return 'CHAPTER' if $self->context_is_chapitre;
923             return 'VERSE' if $self->context_is_verset;
924             return 'UNKNOWN';
925             }
926              
927             sub is_explicit {
928             my $self = shift;
929             # Explicit reference must have a book and a chapter
930             return (_non_empty($self->key));
931             }
932              
933             sub shared_state {
934             my $r1 = shift;
935             my $r2 = shift;
936              
937             # If this reference has an interval ... don't handle it result may be technically
938             # correct but on a practical note ... they are to difficult to read
939             # return if $r1->has_interval || $r2->has_interval;
940              
941             # Two references can not have shared context if they do not have the same state
942             return unless ($r1->state eq $r2->state);
943              
944             return VERSE if ( ((defined($r1->v) && defined($r2->v)) && ($r1->v ne $r2->v))
945             &&
946             ((defined($r1->c) && defined($r2->c) && ($r1->c eq $r2->c)) || (!(defined($r1->c) && defined($r2->c))))
947             &&
948             ((defined($r1->key) && defined($r2->key) && ($r1->key eq $r2->key)) || (!(defined($r1->key) && defined($r2->key))))
949             );
950              
951             return CHAPTER if ((defined($r1->c) && defined($r2->c)) && (($r1->c ne $r2->c) && (!(defined($r1->key) && defined($r2->key)) || (defined($r1->c) && defined($r2->c) && $r1->key eq $r2->key))) );
952             return BOOK if ((defined($r1->key) && defined($r2->key)) && (($r1->key ne $r2->key)));
953             return;
954             }
955              
956             ########################################################################
957             # Helper Functions
958             #
959              
960             sub has_interval {
961             my $self = shift;
962             return ((defined($self->key) && defined($self->key2) && $self->key ne $self->key2)
963             ||
964             (defined($self->c) && defined($self->c2) && $self->c ne $self->c2)
965             ||
966             (defined($self->v) && defined($self->v2) && $self->v ne $self->v2)
967             );
968             }
969              
970             sub begin_interval_reference {
971             my $self = shift;
972             my $ret = new Religion::Bible::Regex::Reference($self->get_configuration, $self->get_regexes);
973              
974             $ret->set({ key => $self->key,
975             ob => $self->ob,
976             c => $self->oc,
977             v => $self->ov,
978             s2 => $self->s2,
979             s3 => $self->s3, s4 => $self->s4,
980             s5 => $self->s5, cvs => $self->cvs,
981             context_words => $self->context_words});
982              
983             return $ret;
984             }
985             sub end_interval_reference {
986             my $self = shift;
987             my $ret = new Religion::Bible::Regex::Reference($self->get_configuration, $self->get_regexes);
988              
989             my ($b, $c, $s7, $key);
990              
991             if (!defined($self->key2) && (defined($self->oc2) || defined($self->ov2) )) {
992             $b = $self->ob;
993             $key = $self->key;
994             $s7 = $self->s2;
995             } else {
996             $b = $self->ob2;
997             $key = $self->key2;
998             $s7 = $self->s7;
999             }
1000              
1001             if (!defined($self->oc2) && ( defined($self->ov2) )) {
1002             $c = $self->oc;
1003             } else {
1004             $c = $self->oc2;
1005             }
1006            
1007             return unless (_non_empty($b) || _non_empty($c) || _non_empty($self->ov2));
1008              
1009             $ret->set({ key => $key,
1010             ob => $b,
1011             c => $c,
1012             v => $self->ov2,
1013             s2 => $s7,
1014             s3 => $self->s8,
1015             s4 => $self->s9,
1016             cvs => $self->cvs,
1017             context_words => $self->context_words});
1018              
1019             return $ret;
1020             }
1021              
1022             sub interval {
1023             my $r1 = shift;
1024             my $r2 = shift;
1025            
1026             # References must not be empty
1027             return unless (_non_empty($r1));
1028             return unless (_non_empty($r2));
1029              
1030             return $r1 if ($r1->compare($r2) == 0);
1031              
1032             # To be comparable both references must have the same state
1033             # ex. 'Ge 1:1' may not be compared to 'chapter 2' or 'v. 4'
1034             unless ($r1->state eq $r2->state) {
1035             carp "Attempted to compare two reference that do no have the same state: " . $r1->normalize . " and " . $r2->normalize . "\n";
1036             return;
1037             }
1038            
1039             my $min = $r1->begin_interval_reference->min($r1->end_interval_reference, $r2->begin_interval_reference, $r2->end_interval_reference);
1040             my $max = $r1->begin_interval_reference->max($r1->end_interval_reference, $r2->begin_interval_reference, $r2->end_interval_reference);
1041              
1042             my $ret = new Religion::Bible::Regex::Reference($r1->get_configuration, $r1->get_regexes);
1043              
1044             $ret->set({ key => $min->key,
1045             ob => $min->ob,
1046             c => $min->c,
1047             v => $min->v,
1048             key2 => $max->key,
1049             ob2 => $max->ob,
1050             c2 => $max->c,
1051             v2 => $max->v2 || $max->v,
1052             cvs => $min->cvs || $max->cvs,
1053             dash => '-',
1054             s2 => $min->s2,
1055             s3 => $min->s3,
1056             s4 => $min->s4,
1057             s5 => $min->s5,
1058             s7 => $max->s2,
1059             s8 => $max->s3,
1060             s9 => $max->s4,
1061             context_words => $min->context_words
1062             });
1063              
1064             return $ret;
1065             }
1066             sub min {
1067             my $self = shift;
1068             my @refs = @_;
1069             my $ret = $self;
1070              
1071             foreach my $r (@refs) {
1072             # next unless (defined(ref $r));
1073             if ($ret->gt($r)) {
1074             $ret = $r;
1075             }
1076             }
1077             return $ret;
1078             }
1079              
1080             sub max {
1081             my $self = shift;
1082             my @refs = @_;
1083             my $ret = $self;
1084              
1085             foreach my $r (@refs) {
1086             if ($ret->lt($r)) {
1087             $ret = $r;
1088             }
1089             }
1090             return $ret;
1091             }
1092              
1093             # References must be of the forms LCV, CV or V
1094             sub compare {
1095             my $r1 = shift;
1096             my $r2 = shift;
1097            
1098             # References must not be empty
1099             return unless (_non_empty($r1));
1100             return unless (_non_empty($r2));
1101              
1102             # To be comparable both references must have the same state
1103             # ex. 'Ge 1:1' may not be compared to 'chapter 2' or 'v. 4'
1104             unless ($r1->state eq $r2->state) {
1105             carp "Attempted to compare two reference that do no have the same state: " . $r1->normalize . " and " . $r2->normalize . "\n";
1106             return;
1107             }
1108              
1109             # Messy logic that compares two references with a context of 'BOOK'
1110             # ex.
1111             # ('Ge 1:1' and 'Ge 2:1'), ('Ge 1:1' and 'Ge 2'), ('Ge 1' and 'Ge 2:1'), ('Ge 1' and 'Ge 2')
1112             # ('Ge 1:1' and 'Ex 2:1'), ('Ge 1:1' and 'Ex 2'), ('Ge 1' and 'Ex 2:1'), ('Ge 1' and 'Ex 2')
1113             # ('Ex 1:1' and 'Ge 2:1'), ('Ex 1:1' and 'Ge 2'), ('Ex 1' and 'Ge 2:1'), ('Ex 1' and 'Ge 2')
1114             if (defined($r1->key) && defined($r2->key)) {
1115             if (($r1->key + 0 <=> $r2->key + 0) == 0) {
1116             if (defined($r1->c) && defined($r2->c)) {
1117             if (($r1->c + 0 <=> $r2->c + 0) == 0) {
1118             if (defined($r1->v) && defined($r2->v)) {
1119             return ($r1->v + 0 <=> $r2->v + 0);
1120             } else {
1121             return ($r1->c + 0 <=> $r2->c + 0);
1122             }
1123             } else {
1124             return ($r1->c + 0 <=> $r2->c + 0);
1125             }
1126             } else {
1127             return ($r1->key + 0 <=> $r2->key + 0);
1128             }
1129             } else {
1130             return ($r1->key + 0 <=> $r2->key + 0);
1131             }
1132             }
1133             # Messy logic that compares two references with a context of 'CHAPTER'
1134             # ex. ('1:1' and '2:1'), ('1:1' and '2'), ('1' and '2:1'), ('1' and '2')
1135             else {
1136             if (defined($r1->c) && defined($r2->c)) {
1137             if (($r1->c + 0 <=> $r2->c + 0) == 0) {
1138             if (defined($r1->v) && defined($r2->v)) {
1139             return ($r1->v + 0 <=> $r2->v + 0);
1140             } else {
1141             return ($r1->c + 0 <=> $r2->c + 0);
1142             }
1143             } else {
1144             return ($r1->c + 0 <=> $r2->c + 0);
1145             }
1146             } else {
1147             if (defined($r1->v) && defined($r2->v)) {
1148             return ($r1->v + 0 <=> $r2->v + 0);
1149             } else {
1150             return ($r1->c + 0 <=> $r2->c + 0);
1151             }
1152             }
1153             }
1154              
1155             # return 1 if ((defined($r1->key) && defined($r2->key)) && ($r1->key + 0 > $r2->key + 0));
1156             # return 1 if ((defined($r1->c) && defined($r2->c)) && ($r1->c + 0 > $r2->c + 0));
1157             # return 1 if ((defined($r1->v) && defined($r2->v)) && ($r1->v + 0 > $r2->v + 0));
1158             return;
1159             }
1160             sub gt {
1161             my $r1 = shift;
1162             my $r2 = shift;
1163            
1164             # References must not be empty
1165             return unless (_non_empty($r1));
1166             return unless (_non_empty($r2));
1167              
1168             # To be comparable both references must have the same state
1169             # ex. 'Ge 1:1' may not be compared to 'chapter 2' or 'v. 4'
1170             unless ($r1->state eq $r2->state) {
1171             carp "Attempted to compare two reference that do no have the same state: " . $r1->normalize . " and " . $r2->normalize . "\n";
1172             return;
1173             }
1174              
1175             ($r1->compare($r2) == -1) ? return : return 1;
1176              
1177             }
1178             sub lt {
1179             my $r1 = shift;
1180             my $r2 = shift;
1181            
1182             # References must not be empty
1183             return unless (_non_empty($r1));
1184             return unless (_non_empty($r2));
1185              
1186             # To be comparable both references must have the same state
1187             # ex. 'Ge 1:1' may not be compared to 'chapter 2' or 'v. 4'
1188             unless ($r1->state eq $r2->state) {
1189             carp "Attempted to compare two reference that do no have the same state: " . $r1->normalize . " and " . $r2->normalize . "\n";
1190             return;
1191             }
1192              
1193             my $ret = $r1->compare($r2);
1194             ($ret == 1) ? return : return 1;
1195              
1196             }
1197              
1198              
1199             sub combine {
1200             my $r1 = shift;
1201             my $r2 = shift;
1202             my %p;
1203              
1204             # References must not be empty
1205             return unless (_non_empty($r1));
1206             return unless (_non_empty($r2));
1207            
1208             my $ret = new Religion::Bible::Regex::Reference($r1->get_configuration, $r1->get_regexes);
1209              
1210             if ($r2->state eq 'BOOK') {
1211             $p{'context_words'} = ($r2->context_words) if (defined($r2->context_words));
1212             $ret->set( \%p, $r2 );
1213             } elsif ($r2->state eq 'CHAPTER') {
1214             $p{'key'} = ($r1->key2 || $r1->key) if (defined($r1->key2 || $r1->key));
1215             $p{'ob'} = ($r1->ob2 || $r1->ob) if (defined($r1->ob2 || $r1->ob));
1216             $p{'c'} = ($r2->c) if (defined($r2->c));
1217             $p{'v'} = ($r2->v) if (defined($r2->v));
1218             $p{'c2'} = ($r2->c2) if (defined($r2->c2));
1219             $p{'v2'} = ($r2->v2) if (defined($r2->v2));
1220             $p{'cvs'} = ($r2->cvs || $r1->cvs) if (defined($r2->cvs || $r1->cvs));
1221             $p{'dash'} = ($r2->dash || $r1->dash) if (defined($r2->dash || $r1->dash));
1222             $p{'context_words'} = ($r2->context_words) if (defined($r2->context_words));
1223             $p{'s2'} = ($r2->s2 || $r1->s2) if (defined( $r2->s2 || $r1->s2 ));
1224             $p{'s3'} = ($r2->s3 || $r1->s3) if (defined( $r2->s3 || $r1->s3 ));
1225             $p{'s4'} = ($r2->s4 || $r1->s4) if (defined( $r2->s4 || $r1->s4 ));
1226             $p{'s5'} = ($r2->s5 || $r1->s5) if (defined( $r2->s5 || $r1->s5 ));
1227             $p{'s6'} = ($r2->s6 || $r1->s6) if (defined( $r2->s6 || $r1->s6 ));
1228             $p{'s8'} = ($r2->s8 || $r1->s8) if (defined( $r2->s8 || $r1->s8 ));
1229             $p{'s9'} = ($r2->s9 || $r1->s9) if (defined( $r2->s9 || $r1->s9 ));
1230             $ret->set( \%p, $r2);
1231             } else {
1232             $p{'key'} = ($r1->key2 || $r1->key) if (defined($r1->key2 || $r1->key));
1233             $p{'ob'} = ($r1->ob2 || $r1->ob) if (defined($r1->ob2 || $r1->ob));
1234             $p{'c'} = ($r2->c2 || $r2->c || $r1->c2 || $r1->c,) if (defined($r2->c2 || $r2->c || $r1->c2 || $r1->c,));
1235             $p{'v'} = ($r2->v) if (defined($r2->v));
1236             $p{'v2'} = ($r2->v2) if (defined($r2->v2));
1237             $p{'cvs'} = ($r2->cvs || $r1->cvs) if (defined($r2->cvs || $r1->cvs));
1238             $p{'dash'} = ($r2->dash || $r1->dash) if (defined($r2->dash || $r1->dash));
1239             $p{'context_words'} = ($r2->context_words) if (defined($r2->context_words));
1240             $p{'s2'} = ($r2->s2 || $r1->s2) if (defined( $r2->s2 || $r1->s2 ));
1241             $p{'s3'} = ($r2->s3 || $r1->s3) if (defined( $r2->s3 || $r1->s3 ));
1242             $p{'s4'} = ($r2->s4 || $r1->s4) if (defined( $r2->s4 || $r1->s4 ));
1243             $p{'s5'} = ($r2->s5 || $r1->s5) if (defined( $r2->s5 || $r1->s5 ));
1244             $p{'s6'} = ($r2->s6 || $r1->s6) if (defined( $r2->s6 || $r1->s6 ));
1245             $p{'s8'} = ($r2->s8 || $r1->s8) if (defined( $r2->s8 || $r1->s8 ));
1246             $p{'s9'} = ($r2->s9 || $r1->s9) if (defined( $r2->s9 || $r1->s9 ));
1247             $ret->set( \%p, $r2);
1248             }
1249            
1250             return $ret;
1251              
1252             }
1253             sub _non_empty {
1254             my $value = shift;
1255             return (defined($value) && $value ne '');
1256             }
1257              
1258             # Returns the first _non_empty value or ''
1259             sub _setor {
1260             foreach my $v (@_) {
1261             return $v if _non_empty($v);
1262             }
1263            
1264             # if no value is given the default should be a empty string
1265             return '';
1266             }
1267              
1268             1; # Magic true value required at end of module
1269             __END__