File Coverage

blib/lib/Treex/Core/Bundle.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Treex::Core::Bundle;
2             $Treex::Core::Bundle::VERSION = '2.20150928';
3 24     24   34352 use namespace::autoclean;
  24         185448  
  24         124  
4              
5 24     24   2308 use Moose;
  24         435092  
  24         237  
6 24     24   152846 use Treex::Core::Common;
  24         63  
  24         276  
7 24     24   124107 use MooseX::NonMoose;
  24         788  
  24         266  
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   187916 use Treex::Core::Node;
  0            
  0            
22             use Treex::Core::Node::A;
23             use Treex::Core::Node::T;
24             use Treex::Core::Node::N;
25             use Treex::Core::Node::P;
26             use Treex::Core::BundleZone;
27              
28             use Treex::Core::Log;
29              
30             # --------- ACCESS TO ZONES ------------
31              
32             sub BUILD {
33             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             my $self = shift;
40             my ( $language, $selector ) = pos_validated_list(
41             \@_,
42             { isa => 'Treex::Type::LangCode' },
43             { isa => 'Treex::Type::Selector', default => '' },
44             );
45             if ( defined $self->{zones} ) {
46             foreach my $element ( $self->{zones}->elements ) {
47             my ( undef, $value ) = @$element; # $name is not needed
48             if (( $value->{language} eq $language or $language eq 'mul' )
49             and ( $value->{selector} || '' ) eq $selector
50             )
51             {
52             return $value;
53             }
54             }
55             }
56             return;
57             }
58              
59             sub create_zone {
60             my $self = shift;
61             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             if ( $self->get_zone( $language, $selector ) ) {
69             if (defined $params_rf and $params_rf->{overwrite}) {
70              
71             }
72             else {
73             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             my $new_zone = Treex::Core::BundleZone->new(
81             {
82             'language' => $language,
83             'selector' => $selector,
84             }
85             );
86              
87             my $new_element = Treex::PML::Seq::Element->new( 'zone', $new_zone );
88              
89             $new_zone->_set_bundle($self);
90              
91             # $new_subbundle->set_type_by_name( $self->get_document->metaData('schema'), 'zone' );
92              
93             if ( defined $self->{zones} ) {
94             $self->{zones}->unshift_element_obj($new_element);
95             }
96             else {
97             $self->{zones} = Treex::PML::Seq->new( [$new_element] );
98             }
99              
100             return $new_zone;
101             }
102              
103             sub get_or_create_zone {
104             my $self = shift;
105             my ( $language, $selector ) = pos_validated_list(
106             \@_,
107             { isa => 'Treex::Type::LangCode' },
108             { isa => 'Treex::Type::Selector', default => '' },
109             );
110             my $zone = $self->get_zone( $language, $selector );
111             if ( !defined $zone ) {
112             $zone = $self->create_zone( $language, $selector );
113             }
114             return $zone;
115             }
116              
117             sub get_all_zones {
118             my $self = shift;
119             if ( $self->{zones} ) {
120             return map { $_->value() } $self->{zones}->elements;
121             }
122             else {
123             return ();
124             }
125             }
126              
127             sub remove_zone {
128             my ( $self, $language, $selector ) = @_;
129              
130             my $zone = $self->get_zone( $language, $selector );
131             if ( !$zone ) {
132             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             foreach my $tree ( $zone->get_all_trees ) {
137             $zone->remove_tree( $tree->get_layer );
138             }
139              
140             $self->{zones}->delete_value($zone)
141             or log_fatal "Zone to be deleted was not found. This should never happen";
142             return;
143             }
144              
145             sub remove {
146             my ( $self ) = @_;
147              
148             # clean the bundle's content first (to ensure de-indexing)
149             foreach my $zone ( $self->get_all_zones ) {
150             $self->remove_zone( $zone->language, $zone->selector );
151             }
152              
153             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             foreach my $bundle ( $self->get_document->get_bundles ) {
159             if ( $bundle eq $self ) {
160             last BUNDLE;
161             }
162             else {
163             $position++;
164             }
165             }
166              
167             $self->get_document->delete_tree($position);
168             bless $self, 'Treex::Core::Node::Removed';
169             return;
170             }
171              
172              
173             # --------- ACCESS TO TREES ------------
174              
175             sub get_all_trees {
176             my $self = shift;
177             if ($Treex::Core::Config::params_validate) { ## no critic (ProhibitPackageVars)
178             pos_validated_list( \@_ );
179             }
180              
181             return () if !$self->{zones};
182              
183             my @trees;
184             foreach my $zone ( $self->{zones}->elements ) {
185             my $structure = $zone->value;
186             foreach my $layer (Treex::Core::Types::layers()) {
187             $layer = lc $layer;
188             if ( exists $structure->{trees}->{"${layer}_tree"} ) {
189             push @trees, $structure->{trees}->{"${layer}_tree"};
190             }
191             }
192             }
193             return @trees;
194              
195             }
196              
197             sub create_tree {
198             my $self = shift;
199             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             my $zone = $self->get_or_create_zone( $language, $selector );
207             my $tree_root = $zone->create_tree($layer);
208             return $tree_root;
209             }
210              
211             sub get_tree {
212             my $self = shift;
213             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             my $zone = $self->get_zone( $language, $selector );
221             log_fatal "Unavailable zone for selector=$selector language=$language\n" if !$zone;
222             return $zone->get_tree($layer);
223             }
224              
225             sub has_tree {
226             my $self = shift;
227             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             my $zone = $self->get_zone( $language, $selector );
234             return defined $zone && $zone->has_tree($layer);
235             }
236              
237             sub get_position {
238             my ($self) = @_;
239              
240             # search for position of the bundle
241             # (ineffective, because there's no caching of positions of bundles so far)
242             my $position_of_reference;
243             my $fsfile = $self->get_document->_pmldoc;
244             foreach my $position ( 0 .. $fsfile->lastTreeNo ) {
245             if ( $fsfile->tree($position) eq $self ) {
246             $position_of_reference = $position;
247             last;
248             }
249             }
250              
251             if ( !defined $position_of_reference ) {
252             log_fatal "document structure inconsistency: can't detect position of bundle $self";
253             }
254              
255             return $position_of_reference;
256             }
257              
258             # --------- ACCESS TO ATTRIBUTES ------------
259              
260             sub get_attr {
261             my $self = shift;
262             my ($attr_name) = pos_validated_list(
263             \@_,
264             { isa => 'Str' },
265             );
266             return $self->{$attr_name};
267             }
268              
269             # ------- other -------------
270              
271             sub following {
272             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.20150928
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.