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 9     9   65 use strict;
  9         15  
  9         271  
4 9     9   54 use warnings;
  9         12  
  9         413  
5              
6 9     9   36 use vars qw($VERSION);
  9         12  
  9         412  
7             BEGIN {
8 9     9   171 $VERSION='2.29'; # version template
9             }
10 9     9   39 no warnings 'uninitialized';
  9         13  
  9         332  
11 9     9   39 use Carp;
  9         9  
  9         498  
12 9     9   44 use Treex::PML::Schema::Constants;
  9         12  
  9         859  
13 9     9   61 use base qw(Treex::PML::Schema::XMLNode);
  9         35  
  9         11687  
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 34 my ($derive,$opts)=@_;
20 18 50       46 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         47 $derive->{name}=$derive->{type};
25             }
26             }
27              
28             sub simplify {
29 18     18 1 42 my ($derive,$opts)=@_;
30 18   33     116 $derive->{name} ||= $derive->{-name};
31 18         38 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     81 ($schema->get_decl_type == PML_SCHEMA_DECL and $opts->{no_derive}));
      66        
      33        
35              
36 18         36 my $name = $derive->{name};
37 18         28 my $type;
38 18         37 my $source = $derive->{type};
39 18 50 33     81 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     64 if (defined($name) and length($name)) {
43 18 50 66     116 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         57 $type = $schema->{type}{$name} = $schema->copy_decl($schema->{type}{$source});
47 18         44 $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       84 if ($derive->{structure}) {
    100          
    100          
    50          
55 7 50       28 if ($type->{structure}) {
56 7         16 my $derive_structure = $derive->{structure};
57 7         20 my $target_structure = $type->{structure};
58 7         14 foreach my $attr (qw(role name)) {
59 14 100       38 if (exists $derive_structure->{$attr}) {
60 3         7 $target_structure->{$attr} = $derive_structure->{$attr};
61 0         0 push @{$target_structure->{-attributes}},$attr
62 3 50       4 unless grep { $_ eq $attr } @{$target_structure->{-attributes}};
  3         14  
  3         12  
63             }
64             }
65 7   50     22 $target_structure->{member} ||= {};
66 7         16 my $members = $target_structure->{member};
67 7         13 while (my ($member,$value) = each %{$derive_structure->{member}}) {
  16         79  
68 9         34 $members->{$member} = $target_structure->copy_decl($value); # FIXME: no need if we remove derives in the end
69             }
70 7 50       40 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       6 if ($type->{sequence}) {
81 2         6 my $derive_sequence = $derive->{sequence};
82 2         5 my $target_sequence = $type->{sequence};
83 2 50       6 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       6 if (exists $derive_sequence->{content_pattern}) {
89 2         6 $target_sequence->{content_pattern} = $derive_sequence->{content_pattern};
90 2         6 push @{$target_sequence->{-attributes}},'content_pattern'
91 2 50       3 unless grep { $_ eq 'content_pattern' } @{$target_sequence->{-attributes}};
  2         8  
  2         7  
92             }
93 2   50     8 $target_sequence->{element} ||= {};
94 2         4 my $elements = $target_sequence->{element};
95 2         4 while (my ($element,$value) = each %{$derive_sequence->{element}}) {
  4         19  
96 2         16 $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       19 if ($type->{container}) {
110 7         14 my $derive_container = $derive->{container};
111 7         13 my $target_container = $type->{container};
112 7         15 for my $attr (qw(type role)) {
113 14 100       36 next unless exists $derive_container->{$attr};
114 2 100 66     30 if ($attr eq 'type' and !exists($target_container->{type})) {
115 1         3 foreach my $d (qw(list alt structure container sequence cdata)) {
116 6 100       15 if (exists $target_container->{$d}) {
117 1         5 delete $target_container->{$d};
118 1         4 last;
119             }
120             }
121 1         3 delete $target_container->{-decl};
122 1         3 delete $target_container->{-resolved};
123             }
124 2         6 $target_container->{$attr} = $derive_container->{$attr};
125 1         5 push @{$target_container->{-attributes}},$attr
126 2 100       4 unless grep { $_ eq $attr } @{$target_container->{-attributes}};
  3         11  
  2         7  
127             }
128 7   100     22 $target_container->{attribute} ||= {};
129 7         17 my $attributes = $target_container->{attribute};
130 7         14 while (my ($attribute,$value) = each %{$derive_container->{attribute}}) {
  14         70  
131 7         29 $attributes->{$attribute} = $target_container->copy_decl($value); # FIXME: no need if we remove derives in the end
132             }
133 7 100       35 if (ref $derive_container->{delete}) {
134 1         3 for my $attribute (@{$derive_container->{delete}}) {
  1         31  
135 1         10 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         4 my $choice = $derive->{choice};
143 2 50       5 if ($type->{choice}) {
144 2         6 my (@add,%delete);
145 2 50       5 if (UNIVERSAL::isa($choice,'HASH')) {
146 2 50       7 @add = @{$choice->{values}} if ref $choice->{values};
  2         6  
147 2 50       10 @delete{ @{$choice->{delete}} }=() if ref $choice->{delete};
  2         6  
148             } else {
149 0         0 @add = @$choice;
150             }
151 2         5 my %seen;
152 2         15 @{$type->{choice}{values}} =
153 2   66     4 grep { !($seen{$_}++) and ! exists $delete{$_} } (@{$type->{choice}{values}},@add);
  16         47  
  2         6  
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__