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 9         950 use vars qw(@EXPORT @EXPORT_OK @ISA $VERSION $API_VERSION %COMPATIBLE_API_VERSION
17 9     9   1080995 $FSError $Debug $resourcePath $resourcePathSplit @BACKENDS);
  9         18  
18             BEGIN {
19 9     9   185 $VERSION = "2.29"; # change when new functions are added etc
20             }
21              
22              
23 9     9   4918 use Data::Dumper;
  9         66792  
  9         758  
24 9     9   65 use Scalar::Util qw(weaken blessed);
  9         11  
  9         403  
25 9     9   3767 use Storable qw(dclone);
  9         25379  
  9         697  
26 9     9   5628 use Treex::PML::Document;
  9         36  
  9         449  
27              
28 9     9   58 use Treex::PML::Factory;
  9         13  
  9         338  
29 9     9   3786 use Treex::PML::StandardFactory;
  9         39  
  9         309  
30 9     9   47 use Treex::PML::Resource::URI;
  9         13  
  9         202  
31 9     9   70 BEGIN { Treex::PML::StandardFactory->make_default() }
32 9     9   45 use Treex::PML::IO;
  9         14  
  9         445  
33 9     9   41 use UNIVERSAL::DOES qw(does);
  9         13  
  9         391  
34              
35 9     9   37 use strict;
  9         23  
  9         207  
36              
37              
38 9     9   35 use Treex::PML::Node;
  9         13  
  9         161  
39              
40 9     9   48 use Exporter;
  9         13  
  9         330  
41 9     9   38 use File::Spec;
  9         14  
  9         203  
42 9     9   36 use Carp;
  9         18  
  9         598  
43 9     9   49 use URI;
  9         17  
  9         199  
44 9     9   34 use URI::file;
  9         47  
  9         1394  
45              
46             BEGIN {
47              
48 9     9   160 @ISA=qw(Exporter);
49              
50 9         30 $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 9         30 %COMPATIBLE_API_VERSION = map { $_ => 1 }
  27         96  
54             (
55             qw( 1.1 1.2 ),
56             $API_VERSION
57             );
58              
59 9         21 @EXPORT = qw/&ImportBackends/;
60 9         79 @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 9   50     69 $Debug=$ENV{TREEX_PML_DEBUG}||0;
63 9         26 *DEBUG = \$Debug;
64              
65 9 50       42 $resourcePathSplit = ($^O eq "MSWin32") ? ',' : ':';
66              
67 9         9195 $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 169 my ($what,$old,$new)=@_;
169 82 50       126 if (ref $what) {
170 82         82 my $val;
171 82 50       126 if (defined $old) {
172 82 50       212 $new = $old unless defined $new;
173             # work around a bug in Data::Dumper:
174 82 50       503 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     360 ->Seen({map { (ref($old->[$_])
  145         3308  
182             and defined($new->[$_]) # bugfix
183             )? (qq{new->[$_]} => $old->[$_]) : () } 0..$#$old})
184             ->Purity(1)->Indent(0)->Dump;
185 82         35497 eval $dump;
186 82 50       524 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         286 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 333 100   333   1592 return ($_[0] =~ m(^\s*[[:alnum:]]+://)) ? 1 : 0;
209             }
210             sub _is_updir {
211 173     173   2668 my $uri = Treex::PML::IO::make_URI($_[0]);
212 173 100       23561 return ($uri->path =~ m{(/|^)\.\.($|/)} ? 1 : 0);
213             }
214             sub _is_absolute {
215 215     215   408 my ($path) = @_;
216 215   100     451 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 9     9   1071 *FindDirInResourcePaths = \&FindDirInResources;
231             }
232              
233             sub FindInResources {
234 92     92 1 191 my ($filename,$opts)=@_;
235 92   100     320 my $all = ref($opts) && $opts->{all};
236 92         127 my @matches;
237 92 100 66     200 unless (_is_absolute($filename) or _is_updir($filename)) {
238 55         1200 for my $dir (ResourcePaths()) {
239 55         626 my $f = File::Spec->catfile($dir,$filename);
240 55 100       1536 if (-f $f) {
241 27 50       203 return $f unless $all;
242 0         0 push @matches,$f;
243             }
244             }
245             }
246 65 100 100     730 return ($all or (ref($opts) && $opts->{strict})) ? @matches : $filename;
247             }
248              
249             BEGIN {
250 9     9   717 *FindInResourcePaths = \&FindInResources;
251             }
252             sub ResourcePaths {
253 64 100   64 1 210 return unless defined $resourcePath;
254 55 50       447 return wantarray ? split(/\Q${resourcePathSplit}\E/, $resourcePath) : $resourcePath;
255             }
256 9     9   12386 BEGIN { *ResourcePath = \&ResourcePaths; } # old name
257              
258             sub AddResourcePath {
259 11 50 66 11 1 333710 if (defined($resourcePath) and length($resourcePath)) {
260 0         0 $resourcePath.=$resourcePathSplit;
261             }
262 11         39 $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 9     9 1 45 $resourcePath=join $resourcePathSplit,@_;
279             }
280              
281             sub _is_local {
282 117     117   224 my ($url) = @_;
283 117 50 33     677 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 123     123 1 3842 my ($base, $href,$use_resources)=@_;
297              
298 123         366 my $rel_uri = Treex::PML::IO::make_URI($href);
299 123         865 my $base_uri = Treex::PML::IO::make_abs_URI($base);
300 123 50       3607 print STDERR "ResolvePath: rel='$rel_uri', base='$base_uri'\n" if $Treex::PML::Debug;
301 123         320 my $abs_uri = $rel_uri->abs($base_uri);
302              
303 123 100       23213 if (_is_absolute($rel_uri)) {
    100          
304 5         69 return $rel_uri;
305             } elsif (_is_updir($rel_uri)) {
306 3 50       35 return _is_url($base) ? $abs_uri : Treex::PML::IO::get_filename($abs_uri);
307             } else {
308 115         1424 my $abs_f = Treex::PML::IO::get_filename($abs_uri);
309 115         12030 my $rel_f = Treex::PML::IO::get_filename($rel_uri);
310 115 50       5772 if (_is_local($base_uri)) {
311 115 100       4816 if (-f $abs_f) {
    50          
312 86 50       382 print STDERR "\t=> (LocalURL-relative) result='$abs_f'\n" if $Treex::PML::Debug;
313 86 100       279 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 29 100       282 if ($use_resources) {
320 27         134 my ($res) = FindInResources($rel_f,{strict=>1});
321 27 50       128 if ($res) {
322 27 50       64 print STDERR "\t=> (resources) result='$res'\n" if $Treex::PML::Debug;
323 27         264 return Treex::PML::Resource::URI->new($res)
324             }
325             }
326 2 50       8 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       5 return _is_local($base) ? $rel_uri : $abs_uri;
332             }
333             }
334              
335             sub ImportBackends {
336 20     20 1 47 my @backends=();
337 20         43 foreach my $backend (@_) {
338 20 50       61 print STDERR "LOADING $backend\n" if $Treex::PML::Debug;
339 20         30 my $b;
340 20         44 for my $try (_BackendCandidates($backend)) {
341 20         34 my $file = $try.'.pm';
342 20         82 $file=~s{::}{/}g;
343 20 50 33     34 if (eval { require $file; } or $::INC{$file}) {
  20         4684  
344 20         37 $b=$backend;
345 20         43 last;
346             }
347             }
348 20 50       74 if ($b) {
349 20         58 push @backends,$b;
350             } else {
351 0 0       0 warn $@ if $@;
352 0         0 warn "FAILED TO LOAD $backend\n";
353             }
354             }
355 20         51 return @backends;
356             }
357              
358             sub UseBackends {
359 11     11 1 368971 @BACKENDS = ImportBackends(@_);
360 11 50       50 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 55     55   112 my ($backend)=@_;
379             return (
380 55 100       474 ($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 66 my ($backend)=@_;
389 24         34 my $b;
390 24         83 for my $try (_BackendCandidates($backend)) {
391 24 50       283 if (UNIVERSAL::can($try,'open_backend')) {
392 24         40 $b = $try;
393 24         46 last;
394             }
395             }
396 24 50 33     284 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 23 my ($backend)=@_;
402 11         13 my $b;
403 11         58 for my $try (_BackendCandidates($backend)) {
404 11 50       121 if (UNIVERSAL::can($try,'open_backend')) {
405 11         17 $b = $try;
406 11         21 last;
407             }
408             }
409 11 50 33     98 return $b if ($b and UNIVERSAL::can($b,'write'));
410 0           return;
411             }
412              
413             1;
414              
415             __END__