File Coverage

blib/lib/Treex/PML/Schema/Container.pm
Criterion Covered Total %
statement 28 112 25.0
branch 0 46 0.0
condition 0 9 0.0
subroutine 10 26 38.4
pod 14 16 87.5
total 52 209 24.8


line stmt bran cond sub pod time code
1             package Treex::PML::Schema::Container;
2              
3 1     1   3 use strict;
  1         1  
  1         22  
4 1     1   3 use warnings;
  1         1  
  1         20  
5              
6 1     1   3 use vars qw($VERSION);
  1         1  
  1         32  
7             BEGIN {
8 1     1   11 $VERSION='2.21'; # version template
9             }
10 1     1   2 no warnings 'uninitialized';
  1         1  
  1         27  
11 1     1   3 use Carp;
  1         1  
  1         43  
12              
13 1     1   4 use Treex::PML::Schema::Constants;
  1         1  
  1         68  
14 1     1   3 use base qw( Treex::PML::Schema::Decl );
  1         1  
  1         76  
15 1     1   4 use UNIVERSAL::DOES;
  1         1  
  1         23  
16 1     1   380 use Treex::PML::Factory;
  1         1  
  1         802  
17              
18             =head1 NAME
19              
20             Treex::PML::Schema::Container - implements declaration of a container.
21              
22             =head1 INHERITANCE
23              
24             This class inherits from L, but provides
25             several methods which make its interface largely compatible with
26             the C class.
27              
28             =head1 METHODS
29              
30             See the super-class for the complete list.
31              
32             =over 3
33              
34             =item $decl->get_decl_type ()
35              
36             Returns the constant PML_CONTAINER_DECL.
37              
38             =item $decl->get_decl_type_str ()
39              
40             Returns the string 'container'.
41              
42             =item $decl->get_content_decl ()
43              
44             Return declaration of the content type.
45              
46             =item $decl->is_atomic ()
47              
48             Returns 0.
49              
50             =cut
51              
52 0     0 1   sub get_decl_type { return PML_CONTAINER_DECL; }
53 0     0 1   sub get_decl_type_str { return 'container'; }
54 0     0 1   sub is_atomic { 0 }
55              
56             sub init {
57 0     0 0   my ($self,$opts)=@_;
58 0           $self->{-parent}{-decl} = 'container';
59             }
60             sub serialize_get_children {
61 0     0 0   my ($self,$opts)=@_;
62 0           my @children = $self->SUPER::serialize_get_children($opts);
63 0           return ((grep { $_->[0] eq 'attribute' } @children),
64 0           (grep { $_->[0] ne 'attribute' } @children));
  0            
65             }
66              
67             =item $decl->get_attributes ()
68              
69             Return a list of the associated attribute declarations
70             (C).
71              
72             =cut
73              
74             sub get_attributes {
75 0     0 1   my $members = $_[0]->{attribute};
76 0 0         return $members ? map { $_->[0] } sort { $a->[1]<=> $b->[1] } map { [ $_, $_->{'-#'} ] } values %$members : ();
  0            
  0            
  0            
77             }
78              
79             =item $decl->has_attributes ()
80              
81             Return true if the container declares attributes.
82              
83             =cut
84              
85             sub has_attributes {
86 0     0 1   my $members = $_[0]->{attribute};
87 0 0         return $members ? scalar(%$members) : 0;
88             }
89              
90              
91             =item $decl->get_attribute_names ()
92              
93             Return a list of names of attributes associated with the container.
94              
95             =cut
96              
97             sub get_attribute_names {
98 0     0 1   my $members = $_[0]->{attribute};
99 0 0         return $members ? map { $_->[0] } sort { $a->[1]<=> $b->[1] } map { [ $_, $members->{$_}->{'-#'} ] } keys %$members : ();
  0            
  0            
  0            
100             }
101              
102             =item $decl->get_attribute_by_name (name)
103              
104             Return the declaration of the attribute with a given name.
105              
106             =cut
107              
108             sub get_attribute_by_name {
109 0     0 1   my ($self, $name) = @_;
110 0           my $members = $_[0]->{attribute};
111 0 0         return $members ? $members->{$name} : undef;
112             }
113              
114             =item $decl->find_attributes_by_content_decl (decl)
115              
116             Lookup and return those attribute declarations whose content
117             declaration is decl.
118              
119             =cut
120              
121             sub find_attributes_by_content_decl {
122 0     0 1   my ($self, $decl) = @_;
123 0           return grep { $decl == $_->get_content_decl } $self->get_attributes;
  0            
124             }
125              
126             =item $decl->find_attributes_by_type_name (name)
127              
128             Lookup and return those attribute declarations whose content is
129             specified via a reference to the named type with a given name.
130              
131             =cut
132              
133             sub find_attributes_by_type_name {
134 0     0 1   my ($self, $type_name) = @_;
135             # using directly $member->{type}
136 0           return grep { $type_name eq $_->{type} } $self->get_attributes;
  0            
137             }
138              
139             =item $decl->find_attributes_by_role (role)
140              
141             Lookup and return declarations of all members with a given role.
142              
143             =cut
144              
145             sub find_attributes_by_role {
146 0     0 1   my ($self, $role) = @_;
147             # using directly $member->{role}
148 0           return grep { $role eq $_->{role} } $self->get_attributes;
  0            
149             }
150              
151             sub validate_object {
152 0     0 1   my ($self, $object, $opts) = @_;
153              
154 0           my ($path,$tag,$flags);
155 0           my $log = [];
156 0 0         if (ref($opts)) {
157 0           $flags = $opts->{flags};
158 0           $path = $opts->{path};
159 0           $tag = $opts->{tag};
160 0 0         $path.="/".$tag if $tag ne q{};
161             }
162              
163 0 0         if (not UNIVERSAL::isa($object,'HASH')) {
164 0           push @$log, "$path: Unexpected container object (should be a HASH): $object";
165             } else {
166 0           my @attributes = $self->get_attributes;
167 0           foreach my $attr (@attributes) {
168 0           my $name = $attr->get_name;
169 0           my $val = $object->{$name};
170 0           my $adecl = $attr->get_content_decl;
171 0 0 0       if ($attr->is_required or $val ne q{}) {
172 0 0         if (ref($val)) {
    0          
173 0           push @$log, "$path/$name: invalid content for attribute: ".ref($val);
174             } elsif ($adecl) {
175 0           $adecl->validate_object($val, {
176             flags => $flags,
177             path => $path,
178             tag => $name,
179             log => $log });
180             }
181             }
182             }
183 0           my $cdecl = $self->get_content_decl;
184 0 0         if ($cdecl) {
185 0           my $content = $object->{'#content'};
186 0           my $skip_content = 0;
187 0 0 0       if ($self->get_role eq '#NODE' and !($flags & PML_VALIDATE_NO_TREES)) {
188 0 0         if (not UNIVERSAL::DOES::does($object,'Treex::PML::Node')) {
189 0           push @$log,"$path: container declared as #NODE should be a Treex::PML::Node object: $object";
190             } else {
191 0           my $cdecl_is = $cdecl->get_decl_type;
192 0 0         if ($cdecl->get_role eq '#CHILDNODES') {
193 0 0         if ($content ne q{}) {
194 0           push @$log, "$path: #NODE container containing a #CHILDNODES should have empty #content: $content";
195             }
196 0 0         if ($flags & PML_VALIDATE_NO_CHILDNODES) {
    0          
    0          
197 0           $skip_content = 1;
198             } elsif ($cdecl_is == PML_SEQUENCE_DECL) {
199 0           $content = Treex::PML::Factory->createSeq([map { Treex::PML::Seq::Element->new($_->{'#name'},$_) } $object->children]);
  0            
200             } elsif ($cdecl_is == PML_LIST_DECL) {
201 0           $content = Treex::PML::Factory->createList([$object->children],1);
202             } else {
203 0           push @$log, "$path: #CHILDNODES should be either a list or sequence";
204             }
205             }
206             }
207             }
208 0 0         unless ($skip_content) {
209 0           $cdecl->validate_object($content,{
210             flags => $flags,
211             path => $path,
212             tag => '#content',
213             log =>$log
214             });
215             }
216             }
217             }
218 0 0 0       if ($opts and ref($opts->{log})) {
219 0           push @{$opts->{log}}, @$log;
  0            
220             }
221 0 0         return @$log ? 0 : 1;
222             }
223              
224             =back
225              
226             =head1 COMPATIBILITY METHODS
227              
228             =over 3
229              
230             =item $decl->get_members ()
231              
232             Return declarations of all associated attributes and of the content
233             type.
234              
235             =cut
236              
237             sub get_members {
238 0     0 1   my $self = shift;
239 0           return ($self->get_attributes, $self->get_content_decl);
240             }
241              
242             =item $decl->get_member_by_name (name)
243              
244             If name is equal to '#content', return the content type declaration,
245             otherwise acts like C.
246              
247             =cut
248              
249             sub get_member_by_name {
250 0     0 1   my ($self, $name) = @_;
251 0 0         if ($name eq '#content') {
252 0           return $self->get_content_decl
253             } else {
254 0           return $self->get_attribute_by_name($name);
255             }
256             }
257              
258             =item $decl->get_member_names ()
259              
260             Return a list of all attribute names plus the string '#content'.
261              
262             =cut
263              
264             sub get_member_names {
265 0     0 1   my $self = shift;
266 0 0         return ($self->get_attribute_names, ($self->get_content_decl ? ('#content') : ()))
267             }
268              
269              
270             =item $decl->find_members_by_content_decl (decl)
271              
272             Lookup and return those member (attribute or content) declarations
273             whose content declaration is decl.
274              
275             =item $decl->find_members_by_type_name (name)
276              
277             Lookup and return those member (attribute or content) declarations
278             whose content is specified via a reference to the named type with a
279             given name.
280              
281             =item $decl->find_members_by_role (role)
282              
283             Lookup and return declarations of all members (attribute or content)
284             with a given role.
285              
286             =cut
287              
288             *find_members_by_content_decl = \&Treex::PML::Schema::Struct::find_members_by_content_decl;
289             *find_members_by_type_name = \&Treex::PML::Schema::Struct::find_members_by_type_name;
290             *find_members_by_role = \&Treex::PML::Schema::Struct::find_members_by_role;
291              
292             =back
293              
294             =cut
295              
296             1;
297             __END__