File Coverage

blib/lib/Religion/Bible/Regex/Lexer.pm
Criterion Covered Total %
statement 22 24 91.6
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 30 32 93.7


line stmt bran cond sub pod time code
1             package Religion::Bible::Regex::Lexer;
2              
3 1     1   32339 use strict;
  1         4  
  1         46  
4 1     1   5 use warnings;
  1         2  
  1         30  
5 1     1   6 use Carp;
  1         7  
  1         321  
6              
7             # Input/Output files are assumed to be in the UTF-8 strict character encoding.
8 1     1   1326 use utf8;
  1         12  
  1         4  
9             binmode(STDIN, ":utf8");
10             binmode(STDOUT, ":utf8");
11             binmode(STDERR, ":utf8");
12              
13 1     1   70 use Carp;
  1         2  
  1         58  
14 1     1   1193 use Storable qw(store retrieve freeze thaw dclone);
  1         8032  
  1         113  
15 1     1   1136 use Data::Dumper;
  1         11673  
  1         75  
16              
17 1     1   455 use Religion::Bible::Regex::Config;
  0            
  0            
18             use Religion::Bible::Regex::Reference;
19              
20             use version; our $VERSION = '0.85';
21              
22             # These constants are defined in several places and probably should be moved to a common file
23             # Move these to Constants.pm
24             use constant BOOK => 'BOOK';
25             use constant CHAPTER => 'CHAPTER';
26             use constant VERSE => 'VERSE';
27             use constant UNKNOWN => 'UNKNOWN';
28             use constant TRUE => 1;
29             use constant FALSE => 0;
30              
31             sub new {
32             my ($class, $config, $regex, $versification) = @_;
33             my ($self) = {};
34             $self->{'config'} = $config;
35             $self->{'regex'} = $regex;
36             $self->{'versification'} = $versification;
37             bless $self, $class;
38             return $self;
39             }
40              
41             # Subroutines related to getting information
42             sub get_regexes {
43             my $self = shift;
44             confess "regex is not defined\n" unless defined($self->{regex});
45             $self->{regex};
46             }
47              
48             # Returns a reference to a Religion::Bible::Regex::Config object.
49             sub get_configuration {
50             my $self = shift;
51             confess "config is not defined\n" unless defined($self->{config});
52             return $self->{config};
53             }
54              
55             # Returns a reference to a Religion::Bible::Regex::Versification object.
56             sub get_versification {
57             my $self = shift;
58             return $self->{versification};
59             }
60              
61             sub references {
62             shift->{reference_list};
63             }
64              
65             sub parse {
66             my ($self, $refstr, $con) = @_;
67             my $state = "";
68             my @result;
69             my $r = $self->get_regexes;
70             my $previous_reference = (defined($con)) ? $$con : undef;
71              
72             # Split the references apart by the separators, which are by default ';' and ','
73             my @refs = split/([\s ]*(?:$r->{'cl_ou_vl_separateurs'})[\s ]*)/, $refstr;
74              
75             foreach my $token (@refs) {
76             # The separator gives a clue as to the state of the next reference
77             # If there is a ';' the next reference should have a state of BOOK or CHAPTER
78             # If there is a ',' the next reference should have a state of VERSE
79             # Of course, you can change these separator values in the configuration file
80             if ($token =~ m/$r->{'cl_separateur'}/) {
81             $state = CHAPTER; next;
82             } elsif (($token =~ m/$r->{'vl_separateur'}/)) {
83             $state = VERSE; next;
84             } elsif (($token =~ m/$r->{'separateur'}/)) {
85             $state = $previous_reference->context;
86             if (!_non_empty($state)) {
87             $state = '';
88             }
89             next;
90             }
91              
92             # Initialize the reference
93             my $ref = new Religion::Bible::Regex::Reference($self->get_configuration, $self->get_regexes);
94              
95             # Parse the reference
96             $ref->parse($token, $state);
97              
98             # Combine the context of this reference with the previous reference
99             $ref = $previous_reference->combine($ref) if defined($previous_reference);
100              
101             # Save the current reference as the previous reference
102             $previous_reference = $ref;
103              
104             # Save the current reference's state
105             $state = $ref->state;
106              
107             # This should be rethought
108             $$con = $previous_reference;
109              
110             # Do the versification
111             $ref = $self->get_versification->decalage($ref) if (defined($self->get_versification) && ref($self->get_versification) eq 'Religion::Bible::Regex::Versification');
112              
113             # Push the reference onto an array
114             push @result, $ref;
115             }
116            
117             $previous_reference = undef;
118             $self->{reference_list} = \@result;
119             return $self;
120             }
121              
122             sub normalize {
123             my $self = shift;
124             my $ret = "";
125             my $count = 0;
126             my $next_state = undef;
127              
128             foreach my $ref (@{$self->{reference_list}}) {
129             my $next = $self->{reference_list}->[++($count)];
130              
131             # Print the formatted reference
132             $ret .= $ref->formatted_normalize;
133              
134             # If no more refs then exit the loop
135             last unless defined($next);
136              
137             $next_state = $next->state;
138            
139             if (defined($next) and $next_state eq VERSE) {
140             # $ret .= $refconfig->get('verse_list_separateur');
141             $ret .= ', ';
142             } elsif (defined($next) and $next_state eq CHAPTER) {
143             # $ret .= $refconfig->get('chapter_list_separateur');
144             $ret .= '; ';
145             } elsif (defined($next) and $next_state eq BOOK) {
146             # $ret .= $refconfig->get('book_list_separateur');
147             $ret .= ', ';
148             } else {
149             carp "Reference has an UNKNOWN next_statearsion " . $ref->normalize . " and " . $next->normalize . "\n";
150             # $ret .= $refconfig->get('book_list_separateur');
151             }
152             }
153             return $ret;
154             }
155              
156              
157             # Dynamically call a formatter
158             sub format {
159             my $self = shift;
160             my $func = shift || 'normalize';
161              
162             {
163             no strict ;
164             return &{$func}($self);
165             }
166             }
167              
168             ###################################################################################################################
169             # grouping: for the Bible Online (BOL) this can have the following values: BOOK, CHAPTER, VERSE, NONE
170             # For example when giving a reference these transformations take place:
171             # BOOK Grouping : Mt 1:1, 2, 3; 4:5; Jn 3:16 ==> \\Mt 1:1, 2, 3; 4:5; Jn 3:16\\
172             # CHAPTER Grouping : Mt 1:1, 2, 3; 4:5; Jn 3:16 ==> \\Mt 1:1, 2, 3; 4:5\\; \\Jn 3:16\\
173             # VERSE Grouping : Mt 1:1, 2, 3; 4:5; Jn 3:16 ==> \\Mt 1:1, 2, 3\\; \\Mt 4:5\\; \\Jn 3:16\\
174             # NONE Grouping : Mt 1:1, 2, 3; 4:5; Jn 3:16 ==> \\Mt 1:1\\, \\Mt 1:2\\, \\Mt 1:3\\; \\Mt 4:5\\; \\Jn 3:16\\
175             ###################################################################################################################
176              
177             sub bol {
178             my $self = shift;
179             my $ret = "";
180             my $count = 0;
181             my $state = undef;
182             my $inside = FALSE;
183            
184             foreach my $ref (@{$self->{reference_list}}) {
185             my $next = $self->{reference_list}->[++($count)];
186              
187             if (defined($ref->context_words) && !($ref->context_words =~ m/(?:@{[$self->get_regexes->{'livres_et_abbreviations'}]})/) ) {
188             $ret .= $ref->context_words || '';
189             $ret .= ' ' if defined($ref->s2);
190             }
191            
192             unless ($inside) {
193             $ret .= '\\\\#';
194             $inside = TRUE;
195             }
196            
197             my $tmp = $ref->bol($state);
198             ($tmp = $tmp) =~ s/^(?:@{[$self->get_regexes->{'chapitre_mots'}]}|@{[$self->get_regexes->{'verset_mots'}]})//g;
199              
200             $tmp =~ s/^[\s ]*//g;
201             $tmp =~ s/[\s ]*$//g;
202              
203             $ret .= $tmp;
204              
205             if (!defined($next)) {
206             $ret .= '\\\\';
207             last;
208             }
209              
210             # If no more refs then exit the loop
211             # last unless defined($next);
212              
213             # if (_non_empty($next->context_words)) {
214             if (_non_empty($next->context_words) && !($next->context_words =~ m/(?:@{[$self->get_regexes->{'livres_et_abbreviations'}]})/)) {
215             $ret .= '\\\\';
216             $inside = FALSE;
217             $state = BOOK;
218             } else {
219             $state = $ref->shared_state($next) || $next->state;
220             }
221              
222             if (defined($next) and $state eq VERSE) {
223             # $ret .= $refconfig->get('verse_list_separateur');
224             $ret .= ', ';
225             } elsif (defined($next) and $state eq CHAPTER) {
226             # $ret .= $refconfig->get('chapter_list_separateur');
227             $ret .= '; ';
228             } elsif (defined($next) and $state eq BOOK) {
229             # $ret .= $refconfig->get('book_list_separateur');
230             $ret .= '; ';
231             } else {
232             carp "Reference has an UNKNOWN comparsion " . $ref->normalize . " and " . $next->normalize . "\n";
233             # $ret .= $refconfig->get('book_list_separateur');
234             }
235             }
236             return $ret;
237             }
238              
239              
240             sub _non_empty {
241             my $value = shift;
242             return (defined($value) && $value ne '');
243             }
244              
245             1; # Magic true value required at end of module
246             __END__