File Coverage

blib/lib/Treex/PML/Schema/Container.pm
Criterion Covered Total %
statement 49 112 43.7
branch 4 46 8.7
condition 0 9 0.0
subroutine 17 26 65.3
pod 14 16 87.5
total 84 209 40.1


line stmt bran cond sub pod time code
1             package Treex::PML::Schema::Container;
2              
3 6     6   38 use strict;
  6         13  
  6         162  
4 6     6   27 use warnings;
  6         11  
  6         145  
5              
6 6     6   28 use vars qw($VERSION);
  6         11  
  6         246  
7             BEGIN {
8 6     6   165 $VERSION='2.24'; # version template
9             }
10 6     6   32 no warnings 'uninitialized';
  6         10  
  6         200  
11 6     6   341 use Carp;
  6         20  
  6         317  
12              
13 6     6   52 use Treex::PML::Schema::Constants;
  6         24  
  6         489  
14 6     6   31 use base qw( Treex::PML::Schema::Decl );
  6         16  
  6         531  
15 6     6   41 use UNIVERSAL::DOES;
  6         7  
  6         240  
16 6     6   2296 use Treex::PML::Factory;
  6         16  
  6         6494  
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 474     474 1 840 sub get_decl_type { return PML_CONTAINER_DECL; }
53 0     0 1 0 sub get_decl_type_str { return 'container'; }
54 0     0 1 0 sub is_atomic { 0 }
55              
56             sub init {
57 90     90 0 213 my ($self,$opts)=@_;
58 90         315 $self->{-parent}{-decl} = 'container';
59             }
60             sub serialize_get_children {
61 12     12 0 33 my ($self,$opts)=@_;
62 12         40 my @children = $self->SUPER::serialize_get_children($opts);
63 25         65 return ((grep { $_->[0] eq 'attribute' } @children),
64 12         35 (grep { $_->[0] ne 'attribute' } @children));
  25         68  
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 274     274 1 491 my $members = $_[0]->{attribute};
76 274 100       816 return $members ? map { $_->[0] } sort { $a->[1]<=> $b->[1] } map { [ $_, $_->{'-#'} ] } values %$members : ();
  251         729  
  46         109  
  251         810  
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 0 my $members = $_[0]->{attribute};
87 0 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 0 my $members = $_[0]->{attribute};
99 0 0       0 return $members ? map { $_->[0] } sort { $a->[1]<=> $b->[1] } map { [ $_, $members->{$_}->{'-#'} ] } keys %$members : ();
  0         0  
  0         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 2     2 1 7 my ($self, $name) = @_;
110 2         4 my $members = $_[0]->{attribute};
111 2 50       15 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 0 my ($self, $decl) = @_;
123 0         0 return grep { $decl == $_->get_content_decl } $self->get_attributes;
  0         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 0 my ($self, $type_name) = @_;
135             # using directly $member->{type}
136 0         0 return grep { $type_name eq $_->{type} } $self->get_attributes;
  0         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 0 my ($self, $role) = @_;
147             # using directly $member->{role}
148 0         0 return grep { $role eq $_->{role} } $self->get_attributes;
  0         0  
149             }
150              
151             sub validate_object {
152 0     0 1 0 my ($self, $object, $opts) = @_;
153              
154 0         0 my ($path,$tag,$flags);
155 0         0 my $log = [];
156 0 0       0 if (ref($opts)) {
157 0         0 $flags = $opts->{flags};
158 0         0 $path = $opts->{path};
159 0         0 $tag = $opts->{tag};
160 0 0       0 $path.="/".$tag if $tag ne q{};
161             }
162              
163 0 0       0 if (not UNIVERSAL::isa($object,'HASH')) {
164 0         0 push @$log, "$path: Unexpected container object (should be a HASH): $object";
165             } else {
166 0         0 my @attributes = $self->get_attributes;
167 0         0 foreach my $attr (@attributes) {
168 0         0 my $name = $attr->get_name;
169 0         0 my $val = $object->{$name};
170 0         0 my $adecl = $attr->get_content_decl;
171 0 0 0     0 if ($attr->is_required or $val ne q{}) {
172 0 0       0 if (ref($val)) {
    0          
173 0         0 push @$log, "$path/$name: invalid content for attribute: ".ref($val);
174             } elsif ($adecl) {
175 0         0 $adecl->validate_object($val, {
176             flags => $flags,
177             path => $path,
178             tag => $name,
179             log => $log });
180             }
181             }
182             }
183 0         0 my $cdecl = $self->get_content_decl;
184 0 0       0 if ($cdecl) {
185 0         0 my $content = $object->{'#content'};
186 0         0 my $skip_content = 0;
187 0 0 0     0 if ($self->get_role eq '#NODE' and !($flags & PML_VALIDATE_NO_TREES)) {
188 0 0       0 if (not UNIVERSAL::DOES::does($object,'Treex::PML::Node')) {
189 0         0 push @$log,"$path: container declared as #NODE should be a Treex::PML::Node object: $object";
190             } else {
191 0         0 my $cdecl_is = $cdecl->get_decl_type;
192 0 0       0 if ($cdecl->get_role eq '#CHILDNODES') {
193 0 0       0 if ($content ne q{}) {
194 0         0 push @$log, "$path: #NODE container containing a #CHILDNODES should have empty #content: $content";
195             }
196 0 0       0 if ($flags & PML_VALIDATE_NO_CHILDNODES) {
    0          
    0          
197 0         0 $skip_content = 1;
198             } elsif ($cdecl_is == PML_SEQUENCE_DECL) {
199 0         0 $content = Treex::PML::Factory->createSeq([map { Treex::PML::Seq::Element->new($_->{'#name'},$_) } $object->children]);
  0         0  
200             } elsif ($cdecl_is == PML_LIST_DECL) {
201 0         0 $content = Treex::PML::Factory->createList([$object->children],1);
202             } else {
203 0         0 push @$log, "$path: #CHILDNODES should be either a list or sequence";
204             }
205             }
206             }
207             }
208 0 0       0 unless ($skip_content) {
209 0         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     0 if ($opts and ref($opts->{log})) {
219 0         0 push @{$opts->{log}}, @$log;
  0         0  
220             }
221 0 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 138     138 1 198 my $self = shift;
239 138         279 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 2     2 1 330 my ($self, $name) = @_;
251 2 50       7 if ($name eq '#content') {
252 0         0 return $self->get_content_decl
253             } else {
254 2         6 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__