Web::Chain project: Web/Chain/IO/Common.pm
package Web::Chain::IO::Common;
# doom@kzsu.stanford.edu
# 12 Oct 2004
=head1 NAME
Web::Chain::IO::Common - General methods common to all Web::Chain input/output formats
=head1 SYNOPSIS
See Web::Chain::IO
=head1 DESCRIPTION
As explained in the documentation for Web::Chain::IO, this
project is structured to dynamically load the code necessary
to do input or output from any given format. The different
modules that handle different need a way to to share common code,
hence this module, a base class which they inherit from.
=head1 METHODS
=head2 INPUT METHOD ARGUMENT HANDLING
=over
=cut
use 5.006;
use strict;
use warnings;
use Carp;
use Web::Definitions qw( $DEBUG
$DF_TOPNODE_NAME
$DF_BOTNODE_NAME
$DF_NODE_NAME_PINNED_RULE
$DF_VERSION
);
use Web::Chain;
our $VERSION = $DF_VERSION;
=item B<_handle_input_arguments> - qualify the two arguments
used by the input routines in the modules that use this as a base
(e.g. Web::Chain::IO::Input::Html and so on).
The two arguments:
First, the name of the node (or the file, with '.html' extension)
to begin with, second an argument to specify where in the
browse sequence to terminate the input. If the first argument is
undefined, it will start from the top node name defined in
Definitions.pm ('TOP.html', as of this writing).
The second argument can be one of three things: undefined,
which means to continue to the end of the chain, the final
node (or file) name to be input, or it can be the total
number of nodes (an integer).
This method will error out if given names that don't match the
input location.
This method should return two node names (sans '.html' extension)
that correspond to files that actually exist in the input location.
Example usage:
($begin_node_name, $end_node_name) =
$self->_handle_input_arguments( $begin_name, $termination );
=cut
sub _handle_input_arguments {
my ($self, $begin, $termination) = @_;
my $subname = ( caller(0) )[3];
my $called_from = ( caller(1) )[3];
my ($loc, $browse_ref, $begin_name, $end_name, $file);
$loc = $self->input_location;
if ($self->can("get_browse_sequence_from_input")) {
$browse_ref = $self->get_browse_sequence_from_input;
($DEBUG) && print "Browse sequence of $loc: \n" . join(" ", @{ $browse_ref }) . "\n";
}
$begin =~ s/\.htm(?:l)?$//i if $begin; # strip extension (.html or .htm), if any was given
if (not ($begin) ) { # undefined means start at the beginning.
if ($browse_ref) { # use the first name in browse sequence as the beginning
$begin_name = $browse_ref->[0];
} else { # if browse seq not available, use the standard top node name
$begin_name = $DF_TOPNODE_NAME;
}
} elsif ( $begin =~ /$DF_NODE_NAME_PINNED_RULE/) {
$begin_name = $begin;
} else {
croak "$subname: $begin isn't a well-formed doomfiles node name (e.g. MOSTLY_CAPS_2)";
}
# if $termination is undefined, that means continue to the end of the sequence
if ( not( defined( $termination) ) ) { # undef and only undef ('0' doesn't mean do them all)
if ($browse_ref) { # use the last name in browse sequence as the end
$end_name = $browse_ref->[ $#{ $browse_ref } ];
} else { # if browse seq not available, use the standard bottom node name
$end_name = $DF_BOTNODE_NAME;
}
} elsif ($termination =~ m/^[0-9]*$/) { # the total number of nodes to output
my $count = $termination;
if ($count < 1) { # numeric means "how many nodes", so 1 means "one" and 0 means "don't be silly"
croak("$subname: $count is not an allowed value (if you want zero nodes, don't ask for any in $called_from.");
}
unless ($browse_ref) {
croak("$subname: can't use numeric count to get range of nodes: feature is not implemented for $called_from.");
}
my ($i, $begin_i, $target_i);
for ($i=0; $i <= $#{ $browse_ref } ; $i++) {
if ($browse_ref->[$i] eq $begin_name) {
($DEBUG) && print "$i: $browse_ref->[$i]\n";
$begin_i = $i;
last;
}
}
unless (defined($begin_i)) {
($DEBUG) && print STDERR "WIERD FAILURE: name not found in browse that should be there...\n";
($DEBUG) && print STDERR "$subname was called from: $called_from\n";
($DEBUG) && print STDERR "which was in turn called from: " . ( caller(2) )[3] . "\n";
($DEBUG) && print STDERR "and before that: " . ( caller(3) )[3] . "\n";
($DEBUG) && print STDERR "begin_name: $begin_name\n";
($DEBUG) && print STDERR "browse begins: $browse_ref->[0]\n";
($DEBUG) && print STDERR "browse ends: $browse_ref->[$#{ $browse_ref }]\n";
($DEBUG) && print STDERR "final counter value was $i\n";
croak "$subname: very strange: the name $begin_name not found in browse sequence." ;
}
$target_i = $begin_i + $termination - 1; # reduce by one to use as array indicie
$end_name = $browse_ref->[ $target_i ];
} elsif ($termination =~ /$DF_NODE_NAME_PINNED_RULE/ ) { # then termination must be a node name,
$end_name = $termination;
} else {
croak "$subname: second argument: $termination is not a valid termination param (must be doomfiles node name or a numeric count)";
}
# Make sure begin and end really exist before returning
$file = "$loc/$begin_name.html";
unless (-e $file) { croak "$subname: begin file: $file doesn't exist.";}
$file = "$loc/$end_name.html";
unless (-e $file) { croak "$subname: end file: $file doesn't exist.";}
return ($begin_name, $end_name); # Note, returned node names without .html extension
}
=back
=head2 OUTPUT METHOD ARGUMENT HANDLING
=over
=item B<_handle_output_arguments> - qualify the three arguments
used by the output routines in the modules that use this as a base
(e.g. Web::Chain::IO::Output::Html and so on).
The three ordered arguments:
=over
=item 1. a chain object,
=item 2. the node in the chain to begin from --
as usual, either the node object or the node name
=item 3. the "termination" point, i.e. the location in
the chain to terminate output, which can be:
=over
=item a. undefined, which means to continue to the end
of the chain.
=item b. the final node to be output (node object, or name)
=item c. it can be the total number of nodes (an integer).
=back
=back
=back
=over
=item B<_handle_output_arguments> - returns the beginning and
ending nodes of the segment of the chain to be output.
Example usage:
($begin_node, $end_node) =
$self->_handle_output_arguments( $chain, $begin_node, $termination );
=cut
sub _handle_output_arguments {
my ($self, $chain, $begin, $termination) = @_;
my $subname = ( caller(0) )[3];
my ($begin_node, $end_node, $begin_name, $end_name);
if (not ($begin)) { # if $begin is undef, just dump the whole chain.
$begin_node = $chain->get_beg;
$end_node = $chain->get_end; # or just undef?
} else { # $begin should be node object/name, and $termination must be examined
$begin_node = $chain->_handle_node_argument($begin);
# $termination:
# (a) the final node in the sequence to output or
# (b) the total number of nodes to output or
# (c) an undefined value: go all the way to the end of the chain.
if ( defined( $termination ) ) { # 0 means "none", (without "defined" check, 0 would be "all").
if ($termination =~ m/^[0-9]*$/) { # the total number of nodes to output
my $count = $termination;
my $node;
while ($count) {
$node = $begin_node->next;
$count--;
}
$end_node = $node;
} else { # the final node in the sequence to output
$end_node = $chain->_handle_node_argument($termination);
}
} else {
$end_node = undef;
}
}
return ($begin_node, $end_node);
}
1;
__END__
=back
=head1 SEE ALSO
L<Project Documentation|Web::Project>
=head1 AUTHOR
Joseph Brenner, E<lt>doom@kzsu.stanford.eduE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2004 by Joseph Brenner
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.2 or,
at your option, any later version of Perl 5 you may have available.
=head1 BUGS
None reported... yet.
=cut
Joseph Brenner,
Sat Nov 6 17:04:11 2004