File Coverage

blib/lib/Locale/Maketext/Utils/Phrase/Norm.pm
Criterion Covered Total %
statement 114 132 86.3
branch 51 64 79.6
condition 8 15 53.3
subroutine 34 41 82.9
pod 10 10 100.0
total 217 262 82.8


line stmt bran cond sub pod time code
1             package Locale::Maketext::Utils::Phrase::Norm;
2              
3 4     4   53734 use strict;
  4         5  
  4         91  
4 4     4   13 use warnings;
  4         3  
  4         110  
5              
6             $Locale::Maketext::Utils::Phrase::Norm::VERSION = '0.2';
7              
8 4     4   1549 use Module::Want ();
  4         3105  
  4         68  
9 4     4   18 use Carp ();
  4         5  
  4         6591  
10              
11             # IF YOU CHANGE THIS CHANGE THE “DEFAULT FILTERS” POD SECTION ALSO
12             my @default_filters = qw(NonBytesStr WhiteSpace Grapheme Ampersand Markup Ellipsis BeginUpper EndPunc Consider Escapes Compiles); # IF YOU CHANGE THIS CHANGE THE “DEFAULT FILTERS” POD SECTION ALSO
13              
14             # IF YOU CHANGE THIS CHANGE THE “DEFAULT FILTERS” POD SECTION ALSO
15              
16             # TODO ?: Acronym, IntroComma, Parens (needs CLDR char/pattern in Locales.pm) [output,chr,(not|in|the|markup|list|or any if amp() etc happen )???
17              
18             sub new_target {
19 9 100   9 1 2839 my $conf = ref( $_[-1] ) eq 'HASH' ? pop(@_) : {};
20              
21             # IF YOU CHANGE THIS CHANGE THE “new_target()” POD SECTION ALSO
22 9         12 $conf->{'exclude_filters'}{'BeginUpper'} = 1; # IF YOU CHANGE THIS CHANGE THE “new_target()” POD SECTION ALSO
23 9         9 $conf->{'exclude_filters'}{'EndPunc'} = 1; # IF YOU CHANGE THIS CHANGE THE “new_target()” POD SECTION ALSO
24              
25             # IF YOU CHANGE THIS CHANGE THE “new_target()” POD SECTION ALSO
26              
27 9         11 push @_, $conf;
28 9         17 goto &new_source;
29             }
30              
31             sub new {
32 2     2 1 1198 Carp::carp('new() is deprecated, use new_source() instead');
33 2         661 goto &new_source;
34             }
35              
36             sub new_source {
37 75     75 1 7033 my $ns = shift;
38 75 50       179 $ns = ref($ns) if ref($ns); # just the class ma'am
39              
40 75 100       189 my $conf = ref( $_[-1] ) eq 'HASH' ? pop(@_) : {};
41              
42 75         80 my @filters;
43             my %cr2ns;
44 0         0 my $n; # buffer
45 0         0 my @filternames;
46              
47 75 50       216 for $n ( $conf->{'skip_defaults_when_given_filters'} ? ( @_ ? @_ : @default_filters ) : ( @default_filters, @_ ) ) {
    100          
48 375 50       850 my $name = $n =~ m/[:']/ ? $n : __PACKAGE__ . "::$n";
49              
50 375 50 66     1176 next if ( exists $conf->{'exclude_filters'}{$n} && $conf->{'exclude_filters'}{$n} ) || ( exists $conf->{'exclude_filters'}{$name} && $conf->{'exclude_filters'}{$name} );
      33        
      66        
51              
52 341 50       521 if ( Module::Want::have_mod($name) ) {
53 341 50       5300 if ( my $cr = $name->can('normalize_maketext_string') ) {
54 341         363 push @filters, $cr;
55 341         569 $cr2ns{"$cr"} = $name;
56 341         515 push @filternames, $name;
57             }
58             else {
59 0         0 Carp::carp("$name does not implement normalize_maketext_string()");
60 0         0 return;
61             }
62             }
63             else {
64 0         0 Carp::carp($@);
65 0         0 return;
66             }
67             }
68              
69 75 50       149 if ( !@filters ) {
70 0         0 Carp::carp("Filter list is empty!");
71 0         0 return;
72             }
73              
74 75 50       175 my $run_extra_filters = exists $conf->{'run_extra_filters'} ? ( $conf->{'run_extra_filters'} ? 1 : 0 ) : 0;
    100          
75              
76 75         280 my $new_obj = bless {
77             'filters' => \@filters,
78             'cache' => {},
79             'filter_namespace' => \%cr2ns,
80             'filternames' => \@filternames,
81             'run_extra_filters' => $run_extra_filters,
82             'maketext_object' => undef,
83             }, $ns;
84              
85 75 100       139 if ( exists $conf->{'maketext_object'} ) {
86 3 100       5 $new_obj->set_maketext_object( $conf->{'maketext_object'} ) || return;
87             }
88              
89 73         199 return $new_obj;
90             }
91              
92             sub set_maketext_object {
93 4     4 1 6 my ( $self, $mt_obj ) = @_;
94 4 100       7 if ( ref($mt_obj) ) {
95 3 100       22 if ( $mt_obj->can('makethis') ) {
96 2         4 $self->delete_cache();
97 2         3 $self->{'maketext_object'} = $mt_obj;
98             }
99             else {
100 1         4 Carp::carp('Given maketext object does not have a makethis() method.');
101 1         538 return;
102             }
103             }
104             else {
105 1         4 Carp::carp('Given maketext object is not a reference.');
106 1         297 return;
107             }
108              
109 2         7 return $self->{'maketext_object'};
110             }
111              
112             sub get_maketext_object {
113 92 100   92 1 239 return $_[0]->{'maketext_object'} if defined $_[0]->{'maketext_object'};
114              
115             # Do not delete cache since filters clas call this mid stream
116              
117 15         1101 require Locale::Maketext::Utils::Mock;
118 15         69 $_[0]->{'maketext_object'} = Locale::Maketext::Utils::Mock->get_handle(); # We can't do a class or else we get this sort of thing: Can't use string ("Locale::Maketext::Utils") as a HASH ref while "strict refs" in use at …/Locale/Maketext.pm line N.
119              
120 15         29 return $_[0]->{'maketext_object'};
121             }
122              
123             sub enable_extra_filters {
124 0     0 1 0 $_[0]->delete_cache();
125 0         0 $_[0]->{'run_extra_filters'} = 1;
126             }
127              
128             sub disable_extra_filters {
129 0     0 1 0 $_[0]->delete_cache();
130 0         0 $_[0]->{'run_extra_filters'} = 0;
131             }
132              
133             sub run_extra_filters {
134 0 0   0 1 0 return 1 if $_[0]->{'run_extra_filters'};
135 0         0 return;
136             }
137              
138             sub delete_cache {
139 34     34 1 11637 delete $_[0]->{'cache'};
140             }
141              
142             sub normalize {
143 126     126 1 23353 my ( $self, $string ) = @_;
144              
145 126 100       233 if ( !defined $string ) {
146 4         26 Carp::carp('You must pass a value to normalize()');
147 4         1293 return;
148             }
149              
150 122 50       230 return $self->{'cache'}{$string} if exists $self->{'cache'}{$string};
151              
152 122         579 $self->{'cache'}{$string} = bless {
153             'status' => 1,
154             'warning_count' => 0,
155             'violation_count' => 0,
156             'filter_results' => [],
157             'orig_str' => $string,
158             'aggregate_result' => $string,
159             },
160             'Locale::Maketext::Utils::Phrase::Norm::_Res';
161              
162 122         102 my $cr; # buffer
163 122         91 foreach $cr ( @{ $self->{'filters'} } ) {
  122         216  
164 778         5356 push @{ $self->{'cache'}{$string}{'filter_results'} }, bless {
165             'status' => 1,
166             'package' => $self->{'filter_namespace'}{"$cr"},
167             'orig_str' => $string,
168             'new_str' => $string,
169             'violations' => [], # status 0
170             'warnings' => [], # status -1 (true but not 1)
171             '_get_mt' => sub {
172 76     76   117 return $self->get_maketext_object();
173             },
174             '_run_extra' => sub {
175 0     0   0 return $self->run_extra_filters();
176             },
177             },
178 778         483 'Locale::Maketext::Utils::Phrase::Norm::_Res::Filter';
179              
180 778         2083 my ( $filter_rc, $violation_count, $warning_count, $filter_modifies_string ) = $cr->( $self->{'cache'}{$string}{'filter_results'}[-1] );
181              
182             # Update string's overall aggregate modifcation
183 778 100       1052 if ($filter_modifies_string) {
184              
185             # Run aggregate value through filter, not perfect since it isn't operating on the same value as above
186             my $agg_filt = bless {
187             'status' => 1,
188             'package' => $self->{'filter_namespace'}{"$cr"},
189             'orig_str' => $self->{'cache'}{$string}{'aggregate_result'},
190             'new_str' => $self->{'cache'}{$string}{'aggregate_result'},
191             'violations' => [], # status 0
192             'warnings' => [], # status -1 (true but not 1)
193             '_get_mt' => sub {
194 13     13   25 return $self->get_maketext_object();
195             },
196             '_run_extra' => sub {
197 0     0   0 return $self->run_extra_filters();
198             },
199             },
200 79         688 'Locale::Maketext::Utils::Phrase::Norm::_Res::Filter';
201              
202 79         161 $cr->($agg_filt);
203 79         105 $self->{'cache'}{$string}{'aggregate_result'} = $agg_filt->get_new_str();
204             }
205              
206             # Update string's overall result
207 778         877 $self->{'cache'}{$string}{'violation_count'} += $violation_count;
208 778         713 $self->{'cache'}{$string}{'warning_count'} += $warning_count;
209 778 100       1079 if ( $self->{'cache'}{$string}->{'status'} ) {
210 694 100       1328 if ( !$filter_rc ) {
    100          
211 39         44 $self->{'cache'}{$string}{'status'} = $filter_rc;
212             }
213             elsif ( $self->{'cache'}{$string}->{'status'} != -1 ) {
214 589         547 $self->{'cache'}{$string}{'status'} = $filter_rc;
215             }
216             }
217              
218 778 50 66     1450 last if !$filter_rc && $self->{'stop_filter_on_error'}; # TODO: document, add POD, methods, new_source(), tests etc.
219             }
220              
221 122         300 return $self->{'cache'}{$string};
222             }
223              
224             package Locale::Maketext::Utils::Phrase::Norm::_Res;
225              
226             sub get_status {
227 114     114   974 return $_[0]->{'status'};
228             }
229              
230             sub get_warning_count {
231 112     112   419 return $_[0]->{'warning_count'};
232             }
233              
234             sub get_violation_count {
235 112     112   445 return $_[0]->{'violation_count'};
236             }
237              
238             sub get_filter_results {
239 64     64   129 return $_[0]->{'filter_results'};
240             }
241              
242             sub get_orig_str {
243 64     64   286 return $_[0]->{'orig_str'};
244             }
245              
246             sub get_aggregate_result {
247 68   33 68   377 return $_[0]->{'aggregate_result'} || $_[0]->{'orig_str'};
248             }
249              
250             sub filters_modify_string {
251 112 100   112   474 return 1 if $_[0]->{'aggregate_result'} ne $_[0]->{'orig_str'};
252 44         147 return;
253             }
254              
255             package Locale::Maketext::Utils::Phrase::Norm::_Res::Filter;
256              
257             sub run_extra_filters {
258 0     0   0 return $_[0]->{'_run_extra'}->();
259             }
260              
261             sub get_maketext_object {
262 89     89   113 return $_[0]->{'_get_mt'}->();
263             }
264              
265             sub add_violation {
266 188     188   176 my ( $self, $error ) = @_;
267 188         150 $self->{'status'} = 0;
268 188         107 push @{ $self->{'violations'} }, $error;
  188         390  
269             }
270              
271             sub add_warning {
272 144     144   135 my ( $self, $warning ) = @_;
273 144 50       163 $self->{'status'} = -1 if !$self->get_violations();
274 144         100 push @{ $self->{'warnings'} }, $warning;
  144         300  
275             }
276              
277             sub get_status {
278 64     64   280 return $_[0]->{'status'};
279             }
280              
281             sub get_package {
282 64     64   643 return $_[0]->{'package'};
283             }
284              
285             sub get_orig_str {
286 231     231   685 return $_[0]->{'orig_str'};
287             }
288              
289             sub get_new_str {
290 143     143   701 return $_[0]->{'new_str'};
291             }
292              
293             sub get_violations {
294 1385 100   1385   895 return if !@{ $_[0]->{'violations'} };
  1385         3330  
295 384         776 return $_[0]->{'violations'};
296             }
297              
298             sub get_warnings {
299 1239 100   1239   744 return if !@{ $_[0]->{'warnings'} };
  1239         2564  
300 380         715 return $_[0]->{'warnings'};
301             }
302              
303             sub get_string_sr {
304 730     730   1162 return \$_[0]->{'new_str'};
305             }
306              
307             sub get_warning_count {
308 985 100   985   990 return $_[0]->get_warnings() ? scalar( @{ $_[0]->get_warnings() } ) : 0;
  158         173  
309             }
310              
311             sub get_violation_count {
312 985 100   985   1121 return $_[0]->get_violations() ? scalar( @{ $_[0]->get_violations() } ) : 0;
  156         175  
313             }
314              
315             sub return_value {
316 921     921   725 my ($self) = @_;
317 921         1112 return ( $self->{'status'}, $self->get_violation_count(), $self->get_warning_count(), $self->filter_modifies_string() );
318             }
319              
320             sub return_value_noop {
321 0     0   0 return ( 2, 0, 0, 0 );
322             }
323              
324             sub filter_modifies_string {
325 985 100   985   2206 return 1 if $_[0]->{'orig_str'} ne $_[0]->{'new_str'};
326 717         1358 return;
327             }
328              
329             1;
330              
331             __END__