File Coverage

blib/lib/Treex/PML/Schema/Derive.pm
Criterion Covered Total %
statement 109 136 80.1
branch 39 62 62.9
condition 18 33 54.5
subroutine 10 12 83.3
pod 3 4 75.0
total 179 247 72.4


line stmt bran cond sub pod time code
1             package Treex::PML::Schema::Derive;
2              
3 6     6   36 use strict;
  6         10  
  6         155  
4 6     6   24 use warnings;
  6         11  
  6         151  
5              
6 6     6   26 use vars qw($VERSION);
  6         10  
  6         229  
7             BEGIN {
8 6     6   111 $VERSION='2.24'; # version template
9             }
10 6     6   26 no warnings 'uninitialized';
  6         12  
  6         194  
11 6     6   30 use Carp;
  6         10  
  6         287  
12 6     6   40 use Treex::PML::Schema::Constants;
  6         24  
  6         507  
13 6     6   34 use base qw(Treex::PML::Schema::XMLNode);
  6         9  
  6         6956  
14              
15 0     0 1 0 sub get_decl_type { return(PML_DERIVE_DECL); }
16 0     0 1 0 sub get_decl_type_str { return('derive'); }
17              
18             sub init {
19 18     18 0 51 my ($derive,$opts)=@_;
20 18 50       69 if (!exists($derive->{type})) {
21 0         0 die " must have a type attribute\n";
22             }
23 18 100       58 if (!exists($derive->{name})) {
24 16         50 $derive->{name}=$derive->{type};
25             }
26             }
27              
28             sub simplify {
29 18     18 1 46 my ($derive,$opts)=@_;
30 18   33     109 $derive->{name} ||= $derive->{-name};
31 18         48 my $schema = $derive->{-parent};
32             return if
33             (($schema->get_decl_type == PML_TEMPLATE_DECL and $opts->{no_template_derive}) or
34 18 50 66     55 ($schema->get_decl_type == PML_SCHEMA_DECL and $opts->{no_derive}));
      66        
      33        
35              
36 18         50 my $name = $derive->{name};
37 18         27 my $type;
38 18         32 my $source = $derive->{type};
39 18 50 33     91 unless (defined($source) and length($source)) {
40 0         0 croak "Derive must specify source type in the attribute 'type' in $schema->{URL}\n";
41             }
42 18 50 33     76 if (defined($name) and length($name)) {
43 18 50 66     96 if (exists ($schema->{type}{$name}) and $source ne $name) {
44 0         0 croak "Refusing to derive already existing type '$name' from '$source' in $schema->{URL}\n";
45             }
46 18         69 $type = $schema->{type}{$name} = $schema->copy_decl($schema->{type}{$source});
47 18         60 $type->{-name} = $name;
48             } else {
49 0         0 $name = $source;
50 0         0 $type = $schema->{type}{$name};
51             }
52              
53             # deriving possible for structures, sequences and choices
54 18 100       91 if ($derive->{structure}) {
    100          
    100          
    50          
55 7 50       25 if ($type->{structure}) {
56 7         17 my $derive_structure = $derive->{structure};
57 7         21 my $target_structure = $type->{structure};
58 7         22 foreach my $attr (qw(role name)) {
59 14 100       53 if (exists $derive_structure->{$attr}) {
60 3         10 $target_structure->{$attr} = $derive_structure->{$attr};
61 0         0 push @{$target_structure->{-attributes}},$attr
62 3 50       6 unless grep { $_ eq $attr } @{$target_structure->{-attributes}};
  3         19  
  3         13  
63             }
64             }
65 7   50     25 $target_structure->{member} ||= {};
66 7         20 my $members = $target_structure->{member};
67 7         16 while (my ($member,$value) = each %{$derive_structure->{member}}) {
  16         86  
68 9         38 $members->{$member} = $target_structure->copy_decl($value); # FIXME: no need if we remove derives in the end
69             }
70 7 50       49 if (ref $derive_structure->{delete}) {
71 0         0 for my $member (@{$derive_structure->{delete}}) {
  0         0  
72 0         0 delete $members->{$member};
73             }
74             }
75             } else {
76              
77 0         0 croak "Cannot derive structure type '$name' from a non-structure '$source'\n";
78             }
79             } elsif ($derive->{sequence}) {
80 2 50       9 if ($type->{sequence}) {
81 2         5 my $derive_sequence = $derive->{sequence};
82 2         6 my $target_sequence = $type->{sequence};
83 2 50       9 if (exists $derive_sequence->{role}) {
84 0         0 $target_sequence->{role} = $derive_sequence->{role};
85 0         0 push @{$target_sequence->{-attributes}},'role'
86 0 0       0 unless grep { $_ eq 'role' } @{$target_sequence->{-attributes}};
  0         0  
  0         0  
87             }
88 2 50       8 if (exists $derive_sequence->{content_pattern}) {
89 2         6 $target_sequence->{content_pattern} = $derive_sequence->{content_pattern};
90 2         8 push @{$target_sequence->{-attributes}},'content_pattern'
91 2 50       5 unless grep { $_ eq 'content_pattern' } @{$target_sequence->{-attributes}};
  2         10  
  2         6  
92             }
93 2   50     9 $target_sequence->{element} ||= {};
94 2         5 my $elements = $target_sequence->{element};
95 2         5 while (my ($element,$value) = each %{$derive_sequence->{element}}) {
  4         22  
96 2         14 $elements->{$element} = $target_sequence->copy_decl($value); # FIXME: no need if we remove derives in the end
97             }
98 2 50       14 if (ref $derive_sequence->{delete}) {
99 0         0 for my $element (@{$derive_sequence->{delete}}) {
  0         0  
100 0         0 delete $elements->{$element};
101             }
102             }
103             } else {
104 0         0 require Data::Dumper;
105             # print STDERR Data::Dumper::Dumper([$type]);
106 0         0 croak "Cannot derive sequence type '$name' from a non-sequence '$source'\n";
107             }
108             } elsif ($derive->{container}) {
109 7 50       23 if ($type->{container}) {
110 7         21 my $derive_container = $derive->{container};
111 7         20 my $target_container = $type->{container};
112 7         18 for my $attr (qw(type role)) {
113 14 100       41 next unless exists $derive_container->{$attr};
114 2 100 66     13 if ($attr eq 'type' and !exists($target_container->{type})) {
115 1         4 foreach my $d (qw(list alt structure container sequence cdata)) {
116 6 100       16 if (exists $target_container->{$d}) {
117 1         4 delete $target_container->{$d};
118 1         2 last;
119             }
120             }
121 1         3 delete $target_container->{-decl};
122 1         3 delete $target_container->{-resolved};
123             }
124 2         5 $target_container->{$attr} = $derive_container->{$attr};
125 1         4 push @{$target_container->{-attributes}},$attr
126 2 100       5 unless grep { $_ eq $attr } @{$target_container->{-attributes}};
  3         11  
  2         5  
127             }
128 7   100     30 $target_container->{attribute} ||= {};
129 7         12 my $attributes = $target_container->{attribute};
130 7         16 while (my ($attribute,$value) = each %{$derive_container->{attribute}}) {
  14         75  
131 7         32 $attributes->{$attribute} = $target_container->copy_decl($value); # FIXME: no need if we remove derives in the end
132             }
133 7 100       46 if (ref $derive_container->{delete}) {
134 1         2 for my $attribute (@{$derive_container->{delete}}) {
  1         4  
135 1         5 delete $attributes->{$attribute};
136             }
137             }
138             } else {
139 0         0 croak "Cannot derive a container '$name' from a different type '$source'\n";
140             }
141             } elsif ($derive->{choice}) {
142 2         7 my $choice = $derive->{choice};
143 2 50       7 if ($type->{choice}) {
144 2         6 my (@add,%delete);
145 2 50       11 if (UNIVERSAL::isa($choice,'HASH')) {
146 2 50       8 @add = @{$choice->{values}} if ref $choice->{values};
  2         9  
147 2 50       11 @delete{ @{$choice->{delete}} }=() if ref $choice->{delete};
  2         10  
148             } else {
149 0         0 @add = @$choice;
150             }
151 2         6 my %seen;
152 2         17 @{$type->{choice}{values}} =
153 2   66     5 grep { !($seen{$_}++) and ! exists $delete{$_} } (@{$type->{choice}{values}},@add);
  16         68  
  2         9  
154             } else {
155 0           croak "Cannot derive a choice type '$name' from a non-choice type '$source'\n";
156             }
157             } else {
158 0 0         unless ($name ne $source) {
159 0           croak " has no effect in $schema->{URL}\n";
160             }
161             }
162             }
163              
164             1;
165             __END__