File Coverage

lib/XML/Schema/Attribute.pm
Criterion Covered Total %
statement 69 70 98.5
branch 43 50 86.0
condition 9 13 69.2
subroutine 13 13 100.0
pod 1 7 14.2
total 135 153 88.2


line stmt bran cond sub pod time code
1             #============================================================= -*-perl-*-
2             #
3             # XML::Schema::Attribute.pm
4             #
5             # DESCRIPTION
6             # Module implementing a base class for XML Schema attributes.
7             #
8             # AUTHOR
9             # Andy Wardley
10             #
11             # COPYRIGHT
12             # Copyright (C) 2001 Canon Research Centre Europe Ltd.
13             # All Rights Reserved.
14             #
15             # This module is free software; you can redistribute it and/or
16             # modify it under the same terms as Perl itself.
17             #
18             # REVISION
19             # $Id: Attribute.pm,v 1.3 2001/12/20 13:26:27 abw Exp $
20             #
21             #========================================================================
22              
23             package XML::Schema::Attribute;
24              
25 11     11   603 use strict;
  11         24  
  11         372  
26              
27 11     11   61 use XML::Schema::Scoped;
  11         18  
  11         301  
28 11     11   244 use XML::Schema::Scheduler;
  11         18  
  11         300  
29 11     11   4840 use XML::Schema::Constants qw( :attribs );
  11         29  
  11         2118  
30              
31 11     11   71 use base qw( XML::Schema::Scoped XML::Schema::Scheduler );
  11         20  
  11         1245  
32 11     11   60 use vars qw( $VERSION $DEBUG $ERROR @MANDATORY @OPTIONAL @SCHEDULES );
  11         209  
  11         11885  
33              
34             $VERSION = sprintf("%d.%02d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/);
35             $DEBUG = 0 unless defined $DEBUG;
36             $ERROR = '';
37              
38             # mandatory 'type' implied by XML::Schema::Scoped base class
39             @MANDATORY = qw( name );
40             # optional 'scope' implied by XML::Schema::Scoped base class
41             @OPTIONAL = qw( namespace annotation );
42             @SCHEDULES = qw( instance );
43              
44              
45             #------------------------------------------------------------------------
46             # build regexen to match valid constraints values
47             #------------------------------------------------------------------------
48              
49             my @constraints = ( FIXED, DEFAULT );
50             my $constraints_regex = join('|', @constraints);
51             $constraints_regex = qr/^$constraints_regex$/;
52              
53              
54              
55             #------------------------------------------------------------------------
56             # init()
57             #
58             # Initiliasation method called by base class new() constructor.
59             #------------------------------------------------------------------------
60              
61             sub init {
62 92     92 1 134 my ($self, $config) = @_;
63 92         89 my ($value);
64              
65             # call base class (XML::Schema::Scoped) initialiser
66 92 100       1604 $self->SUPER::init($config)
67             || return;
68              
69             # call XML::Schema::Scheduler initialiser
70 87 50       277 $self->init_scheduler($config)
71             || return;
72              
73             # set value constraint specified as any of the config
74             # options: fixed, default or constraint
75 87         267 $self->{ constraint } = [ ];
76              
77             # it easy to forget if it's 'constrain' or 'constraint'
78 87   33     219 $self->{ constraint } ||= $self->{ constrain };
79              
80 87 100       364 if (defined ($value = $config->{ fixed })) {
    100          
    100          
81 2 50       7 $self->fixed($value) || return;
82             }
83             elsif (defined ($value = $config->{ default })) {
84 3 50       10 $self->default($value) || return;
85             }
86             elsif (defined ($value = $config->{ constraint })) {
87 3 100       14 return $self->error('constraint value must be an array ref')
88             unless UNIVERSAL::isa($value, 'ARRAY');
89 2 100       6 $self->constraint(@$value) || return;
90             }
91              
92 85         515 return $self;
93             }
94              
95              
96             #------------------------------------------------------------------------
97             # name()
98             #
99             # Simple accessor method to return name value.
100             #------------------------------------------------------------------------
101              
102             sub name {
103 21     21 0 39 my $self = shift;
104 21         78 return $self->{ name };
105             }
106              
107              
108             #------------------------------------------------------------------------
109             # namespace( $namespace )
110             #
111             # Simple accessor method to return existing namespace value or set new
112             # namespace when called with an argument.
113             #------------------------------------------------------------------------
114              
115             sub namespace {
116 3     3 0 3 my $self = shift;
117 3 100       13 return @_ ? ($self->{ namespace } = shift) : $self->{ namespace };
118             }
119              
120              
121             #------------------------------------------------------------------------
122             # constrain( default => 'some_value' ) # set default constraint
123             # constrain('default') # fetch default constraint
124             # constrain( fixed => 'other_value' ) # set fixed value constraint
125             # constrain('fixed') # fetch fixed value constraint
126             # ($type, $value) = constraint() # fetch current type/value
127             #
128             # Fetch or store a value constraint as a pair of ($type, $value) where
129             # type must be one of 'fixed' or 'default'.
130             #------------------------------------------------------------------------
131              
132             *constraint = \&constrain; # use typos; :-)
133              
134             sub constrain {
135 17     17 0 23 my $self = shift;
136              
137 17 100       25 if (@_) {
138 14         24 my $type = lc shift;
139 14 100       75 return $self->error_value('constraint type', $type, @constraints)
140             unless $type =~ $constraints_regex;
141 12         27 $self->$type(@_);
142             }
143             else {
144 3         2 return @{ $self->{ constraint } };
  3         10  
145             }
146             }
147              
148              
149             #------------------------------------------------------------------------
150             # default()
151             # default($value)
152             #
153             # Get/set default value constraint.
154             #------------------------------------------------------------------------
155              
156             sub default {
157 14     14 0 23 my $self = shift;
158              
159 14 100       35 if (@_) {
    100          
160 5         6 my $value = shift;
161 5 50       13 return $self->error('no default value specified')
162             unless defined $value;
163 5         23 $self->{ constraint } = [ default => $value ];
164             }
165             elsif ($self->{ constraint }->[0] eq DEFAULT) {
166 6         21 return $self->{ constraint }->[1];
167             }
168             else {
169 3         9 return $self->error('attribute does not define a default value');
170             }
171             }
172              
173              
174             #------------------------------------------------------------------------
175             # fixed()
176             # fixed($value)
177             #
178             # Get/set fixed value constraint.
179             #------------------------------------------------------------------------
180              
181             sub fixed {
182 28     28 0 34 my $self = shift;
183              
184 28 100       60 if (@_) {
    100          
185 10         10 my $value = shift;
186 10 50       20 return $self->error('no fixed value specified')
187             unless defined $value;
188 10         45 $self->{ constraint } = [ fixed => $value ];
189             }
190             elsif ($self->{ constraint }->[0] eq FIXED) {
191 16         53 return $self->{ constraint }->[1];
192             }
193             else {
194 2         6 return $self->error('attribute does not define a fixed value');
195             }
196             }
197              
198              
199              
200             #------------------------------------------------------------------------
201             # instance($value)
202             #------------------------------------------------------------------------
203              
204             sub instance {
205 107     107 0 207 my ($self, $value, $xml_instance) = @_;
206 107         188 my $constraint = $self->{ constraint };
207 107         91 my $result;
208              
209             # fetch type object via local scope
210 107   100     276 my $type = $self->type()
211             || return;
212              
213             # accept DEFAULT or FIXED value if none was provided
214 106 100       248 unless (defined $value) {
215 18 100       39 if ($constraint->[0]) {
216 6         12 $value = $constraint->[1];
217             }
218             else {
219             # NOTE: it's important not to change this error message
220             # as the parent attribute group calling it looks for it
221 12         40 return $self->error('no value provided');
222             }
223             }
224              
225             # instantiate the type
226 94   100     292 my $infoset = $type->instance($value, $xml_instance)
227             || return $self->error( $type->error() );
228              
229             # check any FIXED constraint against post-validation (but pre-activation) result
230 90 100 100     278 if (@$constraint && $constraint->[0] eq FIXED) {
231             return $self->error("value does not match FIXED value of ", $constraint->[1])
232 2 100       13 unless $infoset->{ value } eq $constraint->[1];
233             }
234              
235             # TODO: what about ID and IDREF?
236 0         0 $self->DEBUG("attribute magic: @{ $infoset->{ magic } }\n")
237 89 50 33     193 if $DEBUG && $infoset->{ magic };
238              
239 89 50       227 $self->activate_instance($infoset)
240             || return;
241             # || return if @{ $self->{ _SCHEDULE_instance } };
242              
243              
244             return wantarray ? @$infoset{ qw( result magic ) }
245 89 100       846 : $infoset->{ result };
246            
247             }
248              
249              
250              
251             1;
252              
253             __END__