File Coverage

blib/lib/Treex/PML.pm
Criterion Covered Total %
statement 149 226 65.9
branch 59 110 53.6
condition 21 74 28.3
subroutine 37 62 59.6
pod 15 33 45.4
total 281 505 55.6


line stmt bran cond sub pod time code
1             #
2             # Revision: $Id: Treex::PML.pm 3044 2007-06-08 17:47:08Z pajas $
3              
4             # See the bottom of this file for the POD documentation. Search for the
5             # string '=head'.
6              
7             # Authors: Petr Pajas, Jan Stepanek
8             # E-mail: tred@ufal.mff.cuni.cz
9             #
10             # Description:
11             # Several Perl Routines to handle files in treebank FS format
12             # See complete help in POD format at the end of this file
13              
14             package Treex::PML;
15              
16 6         623 use vars qw(@EXPORT @EXPORT_OK @ISA $VERSION $API_VERSION %COMPATIBLE_API_VERSION
17 6     6   913319 $FSError $Debug $resourcePath $resourcePathSplit @BACKENDS);
  6         25  
18             BEGIN {
19 6     6   102 $VERSION = "2.24"; # change when new functions are added etc
20             }
21              
22              
23 6     6   3262 use Data::Dumper;
  6         49825  
  6         405  
24 6     6   46 use Scalar::Util qw(weaken blessed);
  6         12  
  6         276  
25 6     6   3479 use Storable qw(dclone);
  6         17018  
  6         360  
26 6     6   3273 use Treex::PML::Document;
  6         30  
  6         227  
27              
28 6     6   43 use Treex::PML::Factory;
  6         13  
  6         114  
29 6     6   2340 use Treex::PML::StandardFactory;
  6         19  
  6         201  
30 6     6   53 BEGIN { Treex::PML::StandardFactory->make_default() }
31 6     6   40 use Treex::PML::IO;
  6         10  
  6         227  
32 6     6   31 use UNIVERSAL::DOES qw(does);
  6         14  
  6         234  
33              
34 6     6   28 use strict;
  6         15  
  6         128  
35              
36              
37 6     6   29 use Treex::PML::Node;
  6         10  
  6         145  
38              
39 6     6   37 use Exporter;
  6         13  
  6         206  
40 6     6   41 use File::Spec;
  6         18  
  6         164  
41 6     6   27 use Carp;
  6         13  
  6         305  
42 6     6   39 use URI;
  6         12  
  6         105  
43 6     6   33 use URI::file;
  6         18  
  6         889  
44              
45             BEGIN {
46              
47 6     6   121 @ISA=qw(Exporter);
48              
49 6         23 $API_VERSION = "2.0"; # change when internal data structures change,
50             # in a way that may prevent old binary dumps to work properly
51              
52 6         14 %COMPATIBLE_API_VERSION = map { $_ => 1 }
  18         58  
53             (
54             qw( 1.1 1.2 ),
55             $API_VERSION
56             );
57              
58 6         18 @EXPORT = qw/&ImportBackends/;
59 6         33 @EXPORT_OK = qw/&Next &Prev &Cut &DeleteLeaf $FSError &Index &SetParent &SetLBrother &SetRBrother &SetFirstSon &Paste &Parent &LBrother &RBrother &FirstSon ResourcePaths FindInResources FindInResourcePaths FindDirInResources FindDirInResourcePaths ResolvePath &CloneValue AddResourcePath AddResourcePathAsFirst SetResourcePaths RemoveResourcePath UseBackends AddBackends Backends /;
60              
61 6   50     57 $Debug=$ENV{TREEX_PML_DEBUG}||0;
62 6         22 *DEBUG = \$Debug;
63              
64 6 50       48 $resourcePathSplit = ($^O eq "MSWin32") ? ',' : ':';
65              
66 6         6688 $FSError=0;
67              
68             }
69              
70              
71              
72              
73             ImportBackends('FS'); # load FS
74             UseBackends('PML'); # default will be PML
75              
76             sub Root {
77 0     0 0 0 my ($node) = @_;
78 0   0     0 return ref($node) && $node->root;
79             }
80             sub Parent {
81 0     0 0 0 my ($node) = @_;
82 0   0     0 return ref($node) && $node->parent;
83             }
84              
85             sub LBrother ($) {
86 0     0 0 0 my ($node) = @_;
87 0   0     0 return ref($node) && $node->lbrother;
88             }
89              
90             sub RBrother ($) {
91 0     0 0 0 my ($node) = @_;
92 0   0     0 return ref($node) && $node->rbrother;
93             }
94              
95             sub FirstSon ($) {
96 0     0 0 0 my ($node) = @_;
97 0   0     0 return ref($node) && $node->firstson;
98             }
99              
100             sub SetParent ($$) {
101 0     0 0 0 my ($node,$parent) = @_;
102 0   0     0 return ref($node) && $node->set_parent($parent);
103             }
104             sub SetLBrother ($$) {
105 0     0 0 0 my ($node,$brother) = @_;
106 0   0     0 return ref($node) && $node->set_lbrother($brother);
107             }
108             sub SetRBrother ($$) {
109 0     0 0 0 my ($node,$brother) = @_;
110 0   0     0 return ref($node) && $node->set_rbrother($brother);
111             }
112             sub SetFirstSon ($$) {
113 0     0 0 0 my ($node,$son) = @_;
114 0   0     0 return ref($node) && $node->set_firstson($son);
115             }
116              
117             sub Next {
118 0     0 0 0 my ($node,$top) = @_;
119 0   0     0 return ref($node) && $node->following($top);
120             }
121              
122             sub Prev {
123 0     0 0 0 my ($node,$top) = @_;
124 0   0     0 return ref($node) && $node->previous($top);
125             }
126              
127             sub Cut ($) {
128 0     0 0 0 my ($node)=@_;
129 0   0     0 return ref($node) && $node->cut;
130             }
131              
132             sub Paste ($$$) {
133 0     0 0 0 my $node = shift;
134 0         0 return $node->paste_on(@_);
135             }
136              
137             sub PasteAfter ($$) {
138 0     0 0 0 my $node = shift;
139 0         0 return $node->paste_after(@_);
140             }
141              
142             sub PasteBefore ($$) {
143 0     0 0 0 my $node = shift;
144 0         0 return $node->paste_before(@_);
145             }
146              
147             sub _WeakenLinks {
148 0     0   0 my ($node)=@_;
149 0         0 while ($node) {
150 0         0 $node->_weakenLinks();
151 0         0 $node = $node->following();
152             }
153             }
154              
155             sub DeleteTree ($) {
156 0     0 0 0 my ($top)=@_;
157 0         0 return $top->destroy();
158             }
159              
160             sub DeleteLeaf ($) {
161 0     0 0 0 my ($node) = @_;
162 0         0 return $node->destroy_leaf();
163             }
164              
165              
166             sub CloneValue {
167 82     82 1 169 my ($what,$old,$new)=@_;
168 82 50       174 if (ref $what) {
169 82         105 my $val;
170 82 50       149 if (defined $old) {
171 82 50       223 $new = $old unless defined $new;
172             # work around a bug in Data::Dumper:
173 82 50       453 if (UNIVERSAL::can('Data::Dumper','init_refaddr_format')) {
174 82         252 Data::Dumper::init_refaddr_format();
175             }
176             # Sometimes occurs, that $new->[1] is undef. This bug appeared randomly, due to reimplimentation of hash in perl5.18 (http://perldoc.perl.org/perldelta.html#Hash-overhaul.
177             # In previous versions it did not appear, thanks to hash order "new->[1]" < "new->[0]"
178             my $dump=Data::Dumper->new([$what],
179             ['val'])
180 82 100 66     426 ->Seen({map { (ref($old->[$_])
  145         3304  
181             and defined($new->[$_]) # bugfix
182             )? (qq{new->[$_]} => $old->[$_]) : () } 0..$#$old})
183             ->Purity(1)->Indent(0)->Dump;
184 82         33997 eval $dump;
185 82 50       435 die $@ if $@;
186             } else {
187             # return Scalar::Util::Clone::clone($what);
188 0         0 return dclone($what);
189             # eval Data::Dumper->new([$what],['val'])->Indent(0)->Purity(1)->Dump;
190             # die $@ if $@;
191             }
192 82         287 return $val;
193             } else {
194 0         0 return $what;
195             }
196             }
197              
198             sub Index ($$) {
199 0     0 0 0 my ($ar,$i) = @_;
200 0         0 for (my $n=0;$n<=$#$ar;$n++) {
201 0 0       0 return $n if ($ar->[$n] eq $i);
202             }
203 0         0 return;
204             }
205              
206             sub _is_url {
207 304 100   304   1560 return ($_[0] =~ m(^\s*[[:alnum:]]+://)) ? 1 : 0;
208             }
209             sub _is_updir {
210 155     155   2534 my $uri = Treex::PML::IO::make_URI($_[0]);
211 155 100       17503 return ($uri->path =~ m{(/|^)\.\.($|/)} ? 1 : 0);
212             }
213             sub _is_absolute {
214 192     192   390 my ($path) = @_;
215 192   100     608 return (_is_url($path) or File::Spec->file_name_is_absolute($path));
216             }
217              
218             sub FindDirInResources {
219 0     0 1 0 my ($filename)=@_;
220 0 0 0     0 unless (_is_absolute($filename) or _is_updir($filename)) {
221 0         0 for my $dir (ResourcePaths()) {
222 0         0 my $f = File::Spec->catfile($dir,$filename);
223 0 0       0 return $f if -d $f;
224             }
225             }
226 0         0 return $filename;
227             }
228             BEGIN{
229 6     6   835 *FindDirInResourcePaths = \&FindDirInResources;
230             }
231              
232             sub FindInResources {
233 76     76 1 218 my ($filename,$opts)=@_;
234 76   100     304 my $all = ref($opts) && $opts->{all};
235 76         138 my @matches;
236 76 100 66     201 unless (_is_absolute($filename) or _is_updir($filename)) {
237 43         1341 for my $dir (ResourcePaths()) {
238 43         564 my $f = File::Spec->catfile($dir,$filename);
239 43 100       983 if (-f $f) {
240 22 50       171 return $f unless $all;
241 0         0 push @matches,$f;
242             }
243             }
244             }
245 54 100 100     690 return ($all or (ref($opts) && $opts->{strict})) ? @matches : $filename;
246             }
247              
248             BEGIN {
249 6     6   459 *FindInResourcePaths = \&FindInResources;
250             }
251             sub ResourcePaths {
252 49 100   49 1 171 return unless defined $resourcePath;
253 43 50       342 return wantarray ? split(/\Q${resourcePathSplit}\E/, $resourcePath) : $resourcePath;
254             }
255 6     6   6984 BEGIN { *ResourcePath = \&ResourcePaths; } # old name
256              
257             sub AddResourcePath {
258 7 50 66 7 1 214 if (defined($resourcePath) and length($resourcePath)) {
259 0         0 $resourcePath.=$resourcePathSplit;
260             }
261 7         31 $resourcePath .= join $resourcePathSplit,@_;
262             }
263              
264             sub AddResourcePathAsFirst {
265 0 0   0 1 0 $resourcePath = join($resourcePathSplit,@_) . (($resourcePath ne q{}) ? ($resourcePathSplit.$resourcePath) : q{});
266             }
267              
268             sub RemoveResourcePath {
269 0     0 1 0 my %remove;
270 0         0 @remove{@_} = ();
271 0 0       0 return unless defined $resourcePath;
272 0         0 $resourcePath = join $resourcePathSplit, grep { !exists($remove{$_}) }
  0         0  
273             split /\Q$resourcePathSplit\E/, $resourcePath;
274             }
275              
276             sub SetResourcePaths {
277 6     6 1 24 $resourcePath=join $resourcePathSplit,@_;
278             }
279              
280             sub _is_local {
281 112     112   242 my ($url) = @_;
282 112 50 33     955 return (((blessed($url) && $url->isa('URI') && (($url->scheme||'file') eq 'file')) or $url =~ m{^file:/}) ? 1 : 0);
283             }
284             sub _strip_file_prefix {
285 0     0   0 my $url = $_[0]; # ARGUMENT WILL GET MODIFIED
286 0 0       0 if (_is_local($url)) {
287 0         0 $_[0] = Treex::PML::IO::get_filename($url);
288 0         0 return 1;
289             } else {
290 0         0 return 0;
291             }
292             }
293              
294             sub ResolvePath ($$;$) {
295 116     116 1 5716 my ($base, $href,$use_resources)=@_;
296              
297 116         2470 my $rel_uri = Treex::PML::IO::make_URI($href);
298 116         799 my $base_uri = Treex::PML::IO::make_abs_URI($base);
299 116 50       4062 print STDERR "ResolvePath: rel='$rel_uri', base='$base_uri'\n" if $Treex::PML::Debug;
300 116         347 my $abs_uri = $rel_uri->abs($base_uri);
301              
302 116 100       26479 if (_is_absolute($rel_uri)) {
    100          
303 4         67 return $rel_uri;
304             } elsif (_is_updir($rel_uri)) {
305 2 50       34 return _is_url($base) ? $abs_uri : Treex::PML::IO::get_filename($abs_uri);
306             } else {
307 110         1617 my $abs_f = Treex::PML::IO::get_filename($abs_uri);
308 110         14640 my $rel_f = Treex::PML::IO::get_filename($rel_uri);
309 110 50       7414 if (_is_local($base_uri)) {
310 110 100       4850 if (-f $abs_f) {
    50          
311 86 50       389 print STDERR "\t=> (LocalURL-relative) result='$abs_f'\n" if $Treex::PML::Debug;
312 86 100       283 return _is_url($base) ? $abs_uri : $abs_f;
313             } elsif ( not _is_url($base) ) { # base was a filename: try path relative to cwd
314 0 0       0 print STDERR "\t=> (cwd-relative) result='$rel_f'\n" if $Treex::PML::Debug;
315 0 0       0 return $rel_f if -f $rel_f;
316             }
317             }
318 24 100       301 if ($use_resources) {
319 22         124 my ($res) = FindInResources($rel_f,{strict=>1});
320 22 50       90 if ($res) {
321 22 50       75 print STDERR "\t=> (resources) result='$res'\n" if $Treex::PML::Debug;
322 22         136 return $res;
323             }
324             }
325 2 50       11 print STDERR "\t=> (relative) result='$abs_uri'\n" if $Treex::PML::Debug;
326             # The following line has been changed. The resources are handled
327             # lazily, i.e. relative URL is returned on not found files to be
328             # searched in resources later. Original line:
329             # return _is_url($base) ? $abs_uri : $abs_f;
330 2 50       7 return _is_local($base) ? $rel_uri : $abs_uri;
331             }
332             }
333              
334             sub ImportBackends {
335 14     14 1 39 my @backends=();
336 14         32 foreach my $backend (@_) {
337 14 50       40 print STDERR "LOADING $backend\n" if $Treex::PML::Debug;
338 14         24 my $b;
339 14         31 for my $try (_BackendCandidates($backend)) {
340 14         35 my $file = $try.'.pm';
341 14         61 $file=~s{::}{/}g;
342 14 50 33     30 if (eval { require $file; } or $::INC{$file}) {
  14         3143  
343 14         32 $b=$backend;
344 14         35 last;
345             }
346             }
347 14 50       43 if ($b) {
348 14         44 push @backends,$b;
349             } else {
350 0 0       0 warn $@ if $@;
351 0         0 warn "FAILED TO LOAD $backend\n";
352             }
353             }
354 14         49 return @backends;
355             }
356              
357             sub UseBackends {
358 8     8 1 240 @BACKENDS = ImportBackends(@_);
359 8 50       50 return wantarray ? @BACKENDS : ((@_==@BACKENDS) ? 1 : 0);
    50          
360             }
361              
362             sub Backends {
363 0     0 1 0 return @BACKENDS;
364             }
365              
366             sub AddBackends {
367 0     0 1 0 my %have;
368 0         0 @have{ @BACKENDS } = ();
369 0         0 my @new = grep !exists($have{$_}), @_;
370 0         0 my @imported = ImportBackends(@new);
371 0         0 push @BACKENDS, @imported;
372 0         0 $have{ @BACKENDS } = ();
373 0 0       0 return wantarray ? (grep exists($have{$_}), @_) : ((@new==@imported) ? 1 : 0);
    0          
374             }
375              
376             sub _BackendCandidates {
377 49     49   129 my ($backend)=@_;
378             return (
379 49 100       491 ($backend=~/:/ ? ($backend) : ()),
    50          
    100          
    100          
380             ($backend=~/^([^:]+)Backend$/ ? ('Treex::PML::Backend::'.$1) : ()),
381             ($backend=~/^Treex::PML::Backend::/ ? () : 'Treex::PML::Backend::'.$backend),
382             ($backend=~/:/ ? () : ($backend)),
383             );
384             }
385              
386             sub BackendCanRead {
387 24     24 1 69 my ($backend)=@_;
388 24         41 my $b;
389 24         97 for my $try (_BackendCandidates($backend)) {
390 24 50       269 if (UNIVERSAL::can($try,'open_backend')) {
391 24         51 $b = $try;
392 24         49 last;
393             }
394             }
395 24 50 33     345 return $b if ($b and UNIVERSAL::can($b,'test') and UNIVERSAL::can($b,'read'));
      33        
396 0         0 return;
397             }
398              
399             sub BackendCanWrite {
400 11     11 1 34 my ($backend)=@_;
401 11         22 my $b;
402 11         46 for my $try (_BackendCandidates($backend)) {
403 11 50       109 if (UNIVERSAL::can($try,'open_backend')) {
404 11         30 $b = $try;
405 11         27 last;
406             }
407             }
408 11 50 33     126 return $b if ($b and UNIVERSAL::can($b,'write'));
409 0           return;
410             }
411              
412             1;
413              
414             __END__