1 #============================================================= -*-Perl-*-
6 # Base class for a node in a Pod::POM tree.
9 # Andy Wardley <abw@wardley.org>
12 # Copyright (C) 2000-2003 Andy Wardley. All Rights Reserved.
14 # This module is free software; you can redistribute it and/or
15 # modify it under the same terms as Perl itself.
18 # $Id: Node.pm 88 2010-04-02 13:37:41Z ford $
20 #========================================================================
22 package BASIS::Pod::POM::Node;
27 use BASIS::Pod::POM::Nodes;
28 use BASIS::Pod::POM::Constants qw( :all );
29 use vars qw( $VERSION $DEBUG $ERROR $NODES $NAMES $AUTOLOAD );
30 use constant DUMP_LINE_LENGTH => 80;
32 $VERSION = sprintf("%d.%02d", q$Revision: 1.5 $ =~ /(\d+)\.(\d+)/);
33 $DEBUG = 0 unless defined $DEBUG;
35 pod => 'BASIS::Pod::POM::Node::Pod',
36 head1 => 'BASIS::Pod::POM::Node::Head1',
37 head2 => 'BASIS::Pod::POM::Node::Head2',
38 head3 => 'BASIS::Pod::POM::Node::Head3',
39 head4 => 'BASIS::Pod::POM::Node::Head4',
40 over => 'BASIS::Pod::POM::Node::Over',
41 item => 'BASIS::Pod::POM::Node::Item',
42 begin => 'BASIS::Pod::POM::Node::Begin',
43 for => 'BASIS::Pod::POM::Node::For',
44 text => 'BASIS::Pod::POM::Node::Text',
45 code => 'BASIS::Pod::POM::Node::Code',
46 verbatim => 'BASIS::Pod::POM::Node::Verbatim',
49 map { ( $NODES->{ $_ } => $_ ) } keys %$NODES,
52 # overload stringification to present node via a view
58 # alias meta() to metadata()
62 #------------------------------------------------------------------------
65 # Constructor method. Returns a new Pod::POM::Node::* object or undef
66 # on error. First argument is the Pod::POM parser object, remaining
67 # arguments are node attributes as specified in %ATTRIBS in derived class
69 #------------------------------------------------------------------------
74 my ($type, $attribs, $accept, $key, $value, $default);
76 $type = $NAMES->{ $class };
80 $attribs = \%{"$class\::ATTRIBS"} || [ ];
81 $accept = \@{"$class\::ACCEPT"} || [ ];
82 unless (%{"$class\::ACCEPT"}) {
83 %{"$class\::ACCEPT"} = (
84 map { ( $_ => $NODES->{ $_ } ) } @$accept,
89 # create object with slots for each acceptable child and overall content
92 content => bless([ ], 'BASIS::Pod::POM::Node::Content'),
93 map { ($_ => bless([ ], 'BASIS::Pod::POM::Node::Content')) }
97 # set attributes from arguments
98 keys %$attribs; # reset hash iterator
99 while(my ($key, $default) = each %$attribs) {
100 $value = shift || $default;
101 return $class->error("$type expected a $key")
103 $self->{ $key } = $value;
110 #------------------------------------------------------------------------
111 # add($pom, $type, @attr)
113 # Adds a new node as a child element (content) of the current node.
114 # First argument is the Pod::POM parser object. Second argument is the
115 # child node type specified by name (e.g. 'head1') which is mapped via
116 # the $NODES hash to a class name against which new() can be called.
117 # Remaining arguments are attributes passed to the child node constructor.
118 # Returns a reference to the new node (child was accepted) or one of the
119 # constants REDUCE (child terminated node, e.g. '=back' terminates an
120 # '=over' node), REJECT (child rejected, e.g. '=back' expected to terminate
121 # '=over' but something else found instead) or IGNORE (node didn't expect
122 # child and is implicitly terminated).
123 #------------------------------------------------------------------------
129 my $class = ref $self;
130 my ($name, $attribs, $accept, $expect, $nodeclass, $node);
132 $name = $NAMES->{ $class }
133 || return $self->error("no name for $class");
135 no strict qw( refs );
136 $accept = \%{"$class\::ACCEPT"};
137 $expect = ${"$class\::EXPECT"};
140 # SHIFT: accept indicates child nodes that can be accepted; a
141 # new node is created, added it to content list and node specific
142 # list, then returned by reference.
144 if ($nodeclass = $accept->{ $type }) {
145 defined($node = $nodeclass->new($pom, @_))
146 || return $self->error($nodeclass->error())
147 unless defined $node;
148 push(@{ $self->{ $type } }, $node);
149 push(@{ $self->{ content } }, $node);
150 $pom->{in_begin} = 1 if $nodeclass eq 'BASIS::Pod::POM::Node::Begin';
154 # REDUCE: expect indicates the token that should terminate this node
155 if (defined $expect && ($type eq $expect)) {
156 DEBUG("$name terminated by expected $type\n");
157 $pom->{in_begin} = 0 if $name eq 'begin';
161 # REJECT: expected terminating node was not found
162 if (defined $expect) {
163 DEBUG("$name rejecting $type, expecting a terminating $expect\n");
164 $self->error("$name expected a terminating $expect");
168 # IGNORE: don't know anything about this node
169 DEBUG("$name ignoring $type\n");
174 #------------------------------------------------------------------------
177 # Present the node by making a callback on the appropriate method against
178 # the view object passed as an argument. $Pod::POM::DEFAULT_VIEW is used
179 # if $view is unspecified.
180 #------------------------------------------------------------------------
183 my ($self, $view, @args) = @_;
184 $view ||= $BASIS::Pod::POM::DEFAULT_VIEW;
185 my $type = $self->{ type };
186 my $method = "view_$type";
187 DEBUG("presenting method $method to $view\n");
188 my $txt = $view->$method($self, @args);
189 if ($view->can("encode")){
190 return $view->encode($txt);
197 #------------------------------------------------------------------------
200 # metadata($key, $value)
202 # Returns the metadata hash when called without any arguments. Returns
203 # the value of a metadata item when called with a single argument.
204 # Sets a metadata item to a value when called with two arguments.
205 #------------------------------------------------------------------------
208 my ($self, $key, $value) = @_;
209 my $metadata = $self->{ METADATA } ||= { };
211 return $metadata unless defined $key;
213 if (defined $value) {
214 $metadata->{ $key } = $value;
217 $value = $self->{ METADATA }->{ $key };
218 return defined $value ? $value
219 : $self->error("no such metadata item: $key");
224 #------------------------------------------------------------------------
228 # May be called as a class or object method to set or retrieve the
229 # package variable $ERROR (class method) or internal member
230 # $self->{ _ERROR } (object method). The presence of parameters indicates
231 # that the error value should be set. Undef is then returned. In the
232 # abscence of parameters, the current error value is returned.
233 #------------------------------------------------------------------------
241 no strict qw( refs );
243 # my ($pkg, $file, $line) = caller();
244 # print STDERR "called from $file line $line\n";
245 # croak "cannot get/set error in non-hash: $self\n"
246 # unless UNIVERSAL::isa($self, 'HASH');
247 $errvar = \$self->{ ERROR };
250 $errvar = \${"$self\::ERROR"};
254 $$errvar = ref($_[0]) ? shift : join('', @_);
263 #------------------------------------------------------------------------
266 # Returns a representation of the element and all its children in a
267 # format useful only for debugging. The structure of the document is
268 # shown by indentation (inspired by HTML::Element).
269 #------------------------------------------------------------------------
272 my($self, $depth) = @_;
274 $depth = 0 unless defined $depth;
275 my $nodepkg = ref $self;
276 if ($self->isa('REF')) {
278 my $cmd = $self->[CMD];
279 my @content = @{ $self->[CONTENT] };
281 $output .= (" " x $depth) . $cmd . $self->[LPAREN] . "\n";
283 foreach my $item (@content) {
285 $output .= $item->dump($depth+1); # recurse
288 $output .= _dump_text($item, $depth+1);
292 $output .= (" " x $depth) . $self->[RPAREN] . "\n", ;
297 my @attrs = sort keys %{"*${nodepkg}::ATTRIBS"};
298 $output .= (" " x $depth) . $self->type . "\n";
299 foreach my $attr (@attrs) {
300 if (my $value = $self->{$attr}) {
301 $output .= (" " x ($depth+1)) . "\@$attr\n";
304 $output .= $value->dump($depth+1);
307 $output .= _dump_text($value, $depth+2);
311 foreach my $item (@{$self->{content}}) {
312 if (ref $item) { # element
313 $output .= $item->dump($depth+1); # recurse
316 $output .= _dump_text($item, $depth+1);
325 my ($text, $depth) = @_;
328 my $padding = " " x $depth;
329 my $max_text_len = DUMP_LINE_LENGTH - length($depth) - 2;
331 foreach my $line (split(/\n/, $text)) {
333 if (length($line) > $max_text_len or $line =~ m<[\x00-\x1F]>) {
334 # it needs prettyin' up somehow or other
335 my $x = (length($line) <= $max_text_len) ? $_ : (substr($line, 0, $max_text_len) . '...');
336 $x =~ s<([\x00-\x1F])>
337 <'\\x'.(unpack("H2",$1))>eg;
338 $output .= qq{"$x"\n};
340 $output .= qq{"$line"\n};
347 #------------------------------------------------------------------------
349 #------------------------------------------------------------------------
353 my $name = $AUTOLOAD;
357 return if $name eq 'DESTROY';
359 # my ($pkg, $file, $line) = caller();
360 # print STDERR "called from $file line $line to return ", ref($item), "\n";
362 return $self->error("can't manipulate \$self")
363 unless UNIVERSAL::isa($self, 'HASH');
364 return $self->error("no such member: $name")
365 unless defined ($item = $self->{ $name });
367 return wantarray ? ( UNIVERSAL::isa($item, 'ARRAY') ? @$item : $item )
372 #------------------------------------------------------------------------
374 #------------------------------------------------------------------------
377 print STDERR "DEBUG: ", @_ if $DEBUG;
386 Pod::POM::Node - base class for a POM node
390 package Pod::POM::Node::Over;
391 use base qw( Pod::POM::Node );
392 use vars qw( %ATTRIBS @ACCEPT $EXPECT $ERROR );
394 %ATTRIBS = ( indent => 4 );
395 @ACCEPT = qw( over item begin for text verbatim );
399 my $list = Pod::POM::Node::Over->new(8);
400 $list->add('item', 'First Item');
401 $list->add('item', 'Second Item');
406 This documentation describes the inner workings of the Pod::POM::Node
407 module and gives a brief overview of the relationship between it and
408 its derived classes. It is intended more as a guide to the internals
409 for interested hackers than as general user documentation. See
410 L<Pod::POM> for information on using the modules.
412 This module implements a base class node which is subclassed to
413 represent different elements within a Pod Object Model.
415 package Pod::POM::Node::Over;
416 use base qw( Pod::POM::Node );
418 The base class implements the new() constructor method to instantiate
421 my $list = Pod::POM::Node::Over->new();
423 The characteristics of a node can be specified by defining certain
424 variables in the derived class package. The C<%ATTRIBS> hash can be
425 used to denote attributes that the node should accept. In the case of
426 an C<=over> node, for example, an C<indent> attribute can be specified
427 which otherwise defaults to 4.
429 package Pod::POM::Node::Over;
430 use base qw( Pod::POM::Node );
431 use vars qw( %ATTRIBS $ERROR );
433 %ATTRIBS = ( indent => 4 );
435 The new() method will now expect an argument to set the indent value,
436 or will use 4 as the default if no argument is provided.
438 my $list = Pod::POM::Node::Over->new(8); # indent: 8
439 my $list = Pod::POM::Node::Over->new( ); # indent: 4
441 If the default value is undefined then the argument is mandatory.
443 package Pod::POM::Node::Head1;
444 use base qw( Pod::POM::Node );
445 use vars qw( %ATTRIBS $ERROR );
447 %ATTRIBS = ( title => undef );
450 my $head = Pod::POM::Node::Head1->new('My Title');
452 If a mandatory argument isn't provided then the constructor will
453 return undef to indicate failure. The $ERROR variable in the derived
454 class package is set to contain a string of the form "$type expected a
457 # dies with error: "head1 expected a title"
458 my $head = Pod::POM::Node::Head1->new()
459 || die $Pod::POM::Node::Head1::ERROR;
461 For convenience, the error() subroutine can be called as a class
462 method to retrieve this value.
464 my $type = 'Pod::POM::Node::Head1';
465 my $head = $type->new()
466 || die $type->error();
468 The C<@ACCEPT> package variable can be used to indicate the node types
469 that are permitted as children of a node.
471 package Pod::POM::Node::Head1;
472 use base qw( Pod::POM::Node );
473 use vars qw( %ATTRIBS @ACCEPT $ERROR );
475 %ATTRIBS = ( title => undef );
476 @ACCEPT = qw( head2 over begin for text verbatim );
478 The add() method can then be called against a node to add a new child
479 node as part of its content.
481 $head->add('over', 8);
483 The first argument indicates the node type. The C<@ACCEPT> list is
484 examined to ensure that the child node type is acceptable for the
485 parent node. If valid, the constructor for the relevant child node
486 class is called passing any remaining arguments as attributes. The
487 new node is then returned.
489 my $list = $head->add('over', 8);
491 The error() method can be called against the I<parent> node to retrieve
492 any constructor error generated by the I<child> node.
494 my $list = $head->add('over', 8);
495 die $head->error() unless defined $list;
497 If the child node is not acceptable to the parent then the add()
498 method returns one of the constants IGNORE, REDUCE or REJECT, as
499 defined in Pod::POM::Constants. These return values are used by the
500 Pod::POM parser module to implement a simple shift/reduce parser.
502 In the most common case, IGNORE is returned to indicate that the
503 parent node doesn't know anything about the new child node. The
504 parser uses this as an indication that it should back up through the
505 parse stack until it finds a node which I<will> accept this child node.
506 Through this mechanism, the parser is able to implicitly terminate
507 certain POD blocks. For example, a list item initiated by a C<=item>
508 tag will I<not> accept another C<=item> tag, but will instead return IGNORE.
509 The parser will back out until it finds the enclosing C<=over> node
510 which I<will> accept it. Thus, a new C<=item> implicitly terminates any
513 The C<$EXPECT> package variable can be used to indicate a node type
514 which a parent expects to terminate itself. An C<=over> node, for
515 example, should always be terminated by a matching C<=back>. When
516 such a match is made, the add() method returns REDUCE to indicate
517 successful termination.
519 package Pod::POM::Node::Over;
520 use base qw( Pod::POM::Node );
521 use vars qw( %ATTRIBS @ACCEPT $EXPECT $ERROR );
523 %ATTRIBS = ( indent => 4 );
524 @ACCEPT = qw( over item begin for text verbatim );
528 my $list = Pod::POM::Node::Over->new();
529 my $item = $list->add('item');
530 $list->add('back'); # returns REDUCE
532 If a child node isn't specified in the C<@ACCEPT> list or doesn't match
533 any C<$EXPECT> specified then REJECT is returned. The parent node sets
534 an internal error of the form "$type expected a terminating $expect".
535 The parser uses this to detect missing POD tags. In nearly all cases
536 the parser is smart enough to fix the incorrect structure and downgrades
537 any errors to warnings.
539 # dies with error 'over expected terminating back'
540 ref $list->add('head1', 'My Title') # returns REJECT
541 || die $list->error();
543 Each node contains a 'type' field which contains a simple string
544 indicating the node type, e.g. 'head1', 'over', etc. The $NODES and
545 $NAMES package variables (in the base class) reference hash arrays
546 which map these names to and from package names (e.g. head1 E<lt>=E<gt>
547 Pod::POM::Node::Head1).
549 print $list->{ type }; # 'over'
551 An AUTOLOAD method is provided to access to such internal items for
552 those who don't like violating an object's encapsulation.
556 Nodes also contain a 'content' list, blessed into the
557 Pod::POM::Node::Content class, which contains the content (child
558 elements) for the node. The AUTOLOAD method returns this as a list
559 reference or as a list of items depending on the context in which it
562 my $items = $list->content();
563 my @items = $list->content();
565 Each node also contains a content list for each individual child node
566 type that it may accept.
568 my @items = $list->item();
569 my @text = $list->text();
570 my @vtext = $list->verbatim();
572 The present() method is used to present a node through a particular view.
573 This simply maps the node type to a method which is then called against the
574 view object. This is known as 'double dispatch'.
576 my $view = 'Pod::POM::View::HTML';
577 print $list->present($view);
579 The method name is constructed from the node type prefixed by 'view_'.
580 Thus the following are roughly equivalent.
582 $list->present($view);
584 $view->view_list($list);
586 The benefit of the former over the latter is, of course, that the
587 caller doesn't need to know or determine the type of the node. The
588 node itself is in the best position to determine what type it is.
592 Andy Wardley E<lt>abw@kfs.orgE<gt>
596 Copyright (C) 2000, 2001 Andy Wardley. All Rights Reserved.
598 This module is free software; you can redistribute it and/or
599 modify it under the same terms as Perl itself.
603 Consult L<Pod::POM> for a general overview and examples of use.