File Coverage

blib/lib/Treex/Core/Bundle.pm
Criterion Covered Total %
statement 106 124 85.4
branch 22 32 68.7
condition 11 14 78.5
subroutine 22 25 88.0
pod 11 14 78.5
total 172 209 82.3


line stmt bran cond sub pod time code
1             package Treex::Core::Bundle;
2             $Treex::Core::Bundle::VERSION = '2.20210102';
3 24     24   117872 use namespace::autoclean;
  24         200517  
  24         124  
4              
5 24     24   2287 use Moose;
  24         480377  
  24         224  
6 24     24   174741 use Treex::Core::Common;
  24         69  
  24         270  
7 24     24   141854 use MooseX::NonMoose;
  24         1051  
  24         237  
8              
9             extends 'Treex::PML::Node';
10             with 'Treex::Core::WildAttr';
11              
12             has document => (
13             is => 'ro',
14             writer => '_set_document',
15             reader => 'get_document',
16             weak_ref => 1,
17             );
18              
19             has id => ( is => 'rw' );
20              
21 24     24   210732 use Treex::Core::Node;
  24         130  
  24         1430  
22 24     24   17717 use Treex::Core::Node::A;
  24         188  
  24         1489  
23 24     24   16748 use Treex::Core::Node::T;
  24         108  
  24         1664  
24 24     24   15329 use Treex::Core::Node::N;
  24         96  
  24         1148  
25 24     24   14337 use Treex::Core::Node::P;
  24         104  
  24         1400  
26 24     24   15550 use Treex::Core::BundleZone;
  24         105  
  24         1026  
27              
28 24     24   191 use Treex::Core::Log;
  24         66  
  24         46619  
29              
30             # --------- ACCESS TO ZONES ------------
31              
32             sub BUILD {
33 0     0 0 0 log_fatal 'Because of node indexing, no bundles can be created outside of documents. '
34             . 'You have to use $document->create_bundle() instead of $bundle->new().';
35              
36             }
37              
38             sub get_zone {
39 74     74 1 1695 my $self = shift;
40 74         422 my ( $language, $selector ) = pos_validated_list(
41             \@_,
42             { isa => 'Treex::Type::LangCode' },
43             { isa => 'Treex::Type::Selector', default => '' },
44             );
45 74 100       327 if ( defined $self->{zones} ) {
46 52         280 foreach my $element ( $self->{zones}->elements ) {
47 85         601 my ( undef, $value ) = @$element; # $name is not needed
48 85 100 66     599 if (( $value->{language} eq $language or $language eq 'mul' )
      100        
      100        
49             and ( $value->{selector} || '' ) eq $selector
50             )
51             {
52 37         167 return $value;
53             }
54             }
55             }
56 37         148 return;
57             }
58              
59             sub create_zone {
60 35     35 1 1684 my $self = shift;
61 35         346 my ( $language, $selector, $params_rf ) = pos_validated_list(
62             \@_,
63             { isa => 'Treex::Type::LangCode' },
64             { isa => 'Treex::Type::Selector', default => '' },
65             { isa => 'Ref' },
66             );
67              
68 35 100       194 if ( $self->get_zone( $language, $selector ) ) {
69 3 100 66     16 if (defined $params_rf and $params_rf->{overwrite}) {
70              
71             }
72             else {
73 1         10 log_fatal("Bundle already contains a zone with language='$language' and selector='$selector'. "
74             . "Use create_zone(...,{overwrite=>1}) to remove it first.")
75             }
76             }
77              
78              
79              
80 34         629 my $new_zone = Treex::Core::BundleZone->new(
81             {
82             'language' => $language,
83             'selector' => $selector,
84             }
85             );
86              
87 34         8504 my $new_element = Treex::PML::Seq::Element->new( 'zone', $new_zone );
88              
89 34         391 $new_zone->_set_bundle($self);
90              
91             # $new_subbundle->set_type_by_name( $self->get_document->metaData('schema'), 'zone' );
92              
93 34 100       136 if ( defined $self->{zones} ) {
94 13         59 $self->{zones}->unshift_element_obj($new_element);
95             }
96             else {
97 21         216 $self->{zones} = Treex::PML::Seq->new( [$new_element] );
98             }
99              
100 34         585 return $new_zone;
101             }
102              
103             sub get_or_create_zone {
104 4     4 1 9 my $self = shift;
105 4         21 my ( $language, $selector ) = pos_validated_list(
106             \@_,
107             { isa => 'Treex::Type::LangCode' },
108             { isa => 'Treex::Type::Selector', default => '' },
109             );
110 4         15 my $zone = $self->get_zone( $language, $selector );
111 4 100       12 if ( !defined $zone ) {
112 1         5 $zone = $self->create_zone( $language, $selector );
113             }
114 4         9 return $zone;
115             }
116              
117             sub get_all_zones {
118 154     154 1 290 my $self = shift;
119 154 100       494 if ( $self->{zones} ) {
120 133         532 return map { $_->value() } $self->{zones}->elements;
  441         2433  
121             }
122             else {
123 21         54 return ();
124             }
125             }
126              
127             sub remove_zone {
128 6     6 1 2368 my ( $self, $language, $selector ) = @_;
129              
130 6         22 my $zone = $self->get_zone( $language, $selector );
131 6 50       27 if ( !$zone ) {
132 0         0 log_fatal "Non-existing zone cannot be removed";
133             }
134              
135             # remove all trees first, so that their nodes are correctly removed from the index
136 6         28 foreach my $tree ( $zone->get_all_trees ) {
137 15         94 $zone->remove_tree( $tree->get_layer );
138             }
139              
140 6 50       54 $self->{zones}->delete_value($zone)
141             or log_fatal "Zone to be deleted was not found. This should never happen";
142 6         1064 return;
143             }
144              
145             sub remove {
146 3     3 0 40 my ( $self ) = @_;
147              
148             # clean the bundle's content first (to ensure de-indexing)
149 3         10 foreach my $zone ( $self->get_all_zones ) {
150 2         76 $self->remove_zone( $zone->language, $zone->selector );
151             }
152              
153 3         13 my $position = 0;
154              
155             # find the bundle's position (this is quite inefficient, as the info about
156             # bundle's position is stored nowhere), and delete the bundle using Treex::PML API
157             BUNDLE:
158 3         625 foreach my $bundle ( $self->get_document->get_bundles ) {
159 6 100       72 if ( $bundle eq $self ) {
160 3         10 last BUNDLE;
161             }
162             else {
163 3         5 $position++;
164             }
165             }
166              
167 3         92 $self->get_document->delete_tree($position);
168 3         90 bless $self, 'Treex::Core::Node::Removed';
169 3         10 return;
170             }
171              
172              
173             # --------- ACCESS TO TREES ------------
174              
175             sub get_all_trees {
176 0     0 1 0 my $self = shift;
177 0 0       0 if ($Treex::Core::Config::params_validate) { ## no critic (ProhibitPackageVars)
178 0         0 pos_validated_list( \@_ );
179             }
180              
181 0 0       0 return () if !$self->{zones};
182              
183 0         0 my @trees;
184 0         0 foreach my $zone ( $self->{zones}->elements ) {
185 0         0 my $structure = $zone->value;
186 0         0 foreach my $layer (Treex::Core::Types::layers()) {
187 0         0 $layer = lc $layer;
188 0 0       0 if ( exists $structure->{trees}->{"${layer}_tree"} ) {
189 0         0 push @trees, $structure->{trees}->{"${layer}_tree"};
190             }
191             }
192             }
193 0         0 return @trees;
194              
195             }
196              
197             sub create_tree {
198 4     4 1 1626 my $self = shift;
199 4         33 my ( $language, $layer, $selector ) = pos_validated_list(
200             \@_,
201             { isa => 'Treex::Type::LangCode' },
202             { isa => 'Treex::Type::Layer' },
203             { isa => 'Treex::Type::Selector', default => '' }
204             );
205              
206 4         18 my $zone = $self->get_or_create_zone( $language, $selector );
207 4         15 my $tree_root = $zone->create_tree($layer);
208 4         16 return $tree_root;
209             }
210              
211             sub get_tree {
212 5     5 1 12 my $self = shift;
213 5         39 my ( $language, $layer, $selector ) = pos_validated_list(
214             \@_,
215             { isa => 'Treex::Type::LangCode' },
216             { isa => 'Treex::Type::Layer' },
217             { isa => 'Treex::Type::Selector', default => '' }
218             );
219              
220 5         21 my $zone = $self->get_zone( $language, $selector );
221 5 50       15 log_fatal "Unavailable zone for selector=$selector language=$language\n" if !$zone;
222 5         19 return $zone->get_tree($layer);
223             }
224              
225             sub has_tree {
226 5     5 1 2703 my $self = shift;
227 5         37 my ( $language, $layer, $selector ) = pos_validated_list(
228             \@_,
229             { isa => 'Treex::Type::LangCode' },
230             { isa => 'Treex::Type::Layer' },
231             { isa => 'Treex::Type::Selector', default => '' }
232             );
233 5         24 my $zone = $self->get_zone( $language, $selector );
234 5   66     29 return defined $zone && $zone->has_tree($layer);
235             }
236              
237             sub get_position {
238 2     2 1 3 my ($self) = @_;
239              
240             # search for position of the bundle
241             # (ineffective, because there's no caching of positions of bundles so far)
242 2         3 my $position_of_reference;
243 2         66 my $fsfile = $self->get_document->_pmldoc;
244 2         8 foreach my $position ( 0 .. $fsfile->lastTreeNo ) {
245 3 100       28 if ( $fsfile->tree($position) eq $self ) {
246 2         14 $position_of_reference = $position;
247 2         4 last;
248             }
249             }
250              
251 2 50       6 if ( !defined $position_of_reference ) {
252 0         0 log_fatal "document structure inconsistency: can't detect position of bundle $self";
253             }
254              
255 2         4 return $position_of_reference;
256             }
257              
258             # --------- ACCESS TO ATTRIBUTES ------------
259              
260             sub get_attr {
261 0     0 0 0 my $self = shift;
262 0         0 my ($attr_name) = pos_validated_list(
263             \@_,
264             { isa => 'Str' },
265             );
266 0         0 return $self->{$attr_name};
267             }
268              
269             # ------- other -------------
270              
271             sub following {
272 40     40 1 2507 return Treex::Core::Node::following(@_);
273             }
274              
275             __PACKAGE__->meta->make_immutable;
276              
277             1;
278              
279             __END__
280              
281              
282             =for Pod::Coverage BUILD set_attr get_attr
283              
284             =encoding utf-8
285              
286             =head1 NAME
287              
288             Treex::Core::Bundle - a set of equivalent sentences in the Treex framework
289              
290             =head1 VERSION
291              
292             version 2.20210102
293              
294             =head1 DESCRIPTION
295              
296             A set of equivalent sentences (translations, or variants) and their linguistic representations in the Treex framework
297             A bundle in Treex corresponds to one sentence or more sentences, typically
298             translations or variants of each other, with all their linguistic
299             representations. Each bundle is divided into zones (instances of
300             L<Treex::Core::BundleZone>), each of them containing
301             exactly one sentence and its representations.
302              
303             =head1 ATTRIBUTES
304              
305             Each bundle has two attributes:
306              
307             =over 4
308              
309             =item id
310              
311             identifier accessible by the getter method C<id()> and by the setter method
312             C<set_id($id)>
313              
314             =item document
315              
316             the document (an instance of L<Treex::Core::Document>)
317             which this bundle belongs to; accessible only by the getter method C<document()>
318              
319             =back
320              
321              
322              
323             =head1 METHODS
324              
325             =head2 Construction
326              
327             You cannot create a bundle by a constructor from scratch. You can create a
328             bundle only within an existing documents, using the following methods of
329             L<Treex::Core::Document>:
330              
331             =over 4
332              
333             =item create_bundle
334              
335             =item new_bundle_before
336              
337             =item new_bundle_after
338              
339             =back
340              
341              
342             =head2 Access to zones
343              
344             Bundle zones are instances of
345             L<Treex::Core::BundleZone>, parametrized by language
346             code and possibly also by another free label called selector, whose purpose is
347             to distinguish zones for the same language but from a different source.
348              
349             =over 4
350              
351             =item my $zone = $bundle->create_zone( $langcode, ?$selector, ?$params_rf );
352              
353             If the third argument is {overwrite=>1}, then the newly created empty zone
354             overwrites the previously existing one (if any). Fatal error appears if
355             the zone to be created already exists and this switch is not used.
356              
357             =item my $zone = $bundle->get_zone( $langcode, ?$selector );
358              
359             =item my $zone = $bundle->get_or_create_zone( $langcode, ?$selector );
360              
361             =item my @zones = $bundle->get_all_zones();
362              
363             =back
364              
365              
366             =head2 Access to trees
367              
368             Even if trees are not contained directly in bundle (there is the intermediate
369             zone level), they can be accessed using the following shortcut methods:
370              
371             =over 4
372              
373             =item my $tree_root = $bundle->get_tree( $language, $layer, ?$selector);
374              
375              
376             =item my $tree_root = $bundle->create_tree( $language, $layer, ?$selector );
377              
378              
379             =item $bundle->has_tree( $language, $layer, ?$selector );
380              
381              
382             =item my @tree_roots = $bundle->get_all_trees();
383              
384             =back
385              
386              
387              
388             =head2 Other
389              
390             =over 4
391              
392             =item $bundle->remove_zone( $language, $selector );
393              
394             delete all zone's trees and remove the zone from the bundle
395              
396             =item my $position = $bundle->get_position();
397              
398             position of the bundle within the document (number, starting from 0)
399              
400             =back
401              
402              
403             =head1 AUTHOR
404              
405             Zdeněk Žabokrtský <zabokrtsky@ufal.mff.cuni.cz>
406              
407             =head1 COPYRIGHT AND LICENSE
408              
409             Copyright © 2011 by Institute of Formal and Applied Linguistics, Charles University in Prague
410              
411             This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.