File Coverage

blib/lib/Treex/PML.pm
Criterion Covered Total %
statement 151 229 65.9
branch 59 110 53.6
condition 21 74 28.3
subroutine 38 63 60.3
pod 15 33 45.4
total 284 509 55.8


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