File Coverage

blib/lib/Treex/PML.pm
Criterion Covered Total %
statement 14 16 87.5
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 20 22 90.9


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