Apache-XPP

 view release on metacpan or  search on metacpan

lib/Apache/XPP.pm  view on Meta::CPAN

# Apache::XPP
# -------------
# $Revision: 1.32 $
# $Date: 2002/02/15 05:00:01 $
# -----------------------------------------------------------------------------
=head1 NAME

XPP (XPML Page Parser) - An embedded perl language designed to co-exist with HTML

=cut

package Apache::XPP;

=head1 SYNOPSIS

 use Apache::XPP;
 my $xpp = Apache::XPP->new( Apache->request );
 $xpml->run;

=head1 REQUIRES

 Apache
 Apache::Constants
 File::stat
 FileHandle
 HTTP::Request
 LWP::UserAgent

=cut

use Carp;
use strict;
use vars qw( $AUTOLOAD $debug $debuglines );

BEGIN {
    $Apache::XPP::REVISION       = (qw$Revision: 1.32 $)[-1];
    $Apache::XPP::VERSION        = '2.02';
}

use Apache::XPP::Cache;
use Apache::XPP::PreParse;

if ($INC{ 'Apache.pm' }) {
	eval q{
		use Apache();
		use Apache::Constants qw(:response);
	};
}


use Carp;
use File::stat;
use FileHandle;
use HTTP::Request;
use LWP::UserAgent;

=head1 EXPORTS

Nothing

=head1 DESCRIPTION

Apache::XPP is an HTML parser which on run time compiles and runs embedded perl code.

=head1 CLASS VARIABLES

=over

=item C<$Apache::XPP::main_class>

XPP sub-classes must set $Apache::XPP::main_class to the name of the
sub-class. This will allow xinclude/include to work properly.

=cut

$Apache::XPP::main_class = 'Apache::XPP';

=item C<$debug>

Activates debugging output.  All debugging output is sent to STDERR.

At present there are only 4 levels of debugging :
 0 - no debugging (default)
 1 - some debugging
 2 - verbose debugging
 3 - adds some Data::Dumper calls

=item C<$debuglines>

Optionally, you can activate the $debuglines, which will cause all
debugging output to include the line numbers (in this file) of the debugging.

=back

=cut

$debug		= 0;
$debuglines	= 0;

=head1 METHODS

=over

=item C<handler> ( $r )

The Apache handler hook. This is the entry point for the Apache module.  It
takes the Apache request object ($r) as its parameter and builds a new XPP
object to handle the request. In order to support the procedural nature
of include() and xinclude() a global is defined. If you subclass Apache::XPP
replace the value of the global L<"$Apache::XPP::main_class"> with your class name.

=cut

sub handler ($$) {

lib/Apache/XPP.pm  view on Meta::CPAN

		
		
		$self->code->( $self, @_ );
		return 1;
	} else {
		return undef;
	}
} # END method run


=item C<returnrun> ( @arguments )

Calls C<run> with @arguments as specified, catching all output destined for STDOUT, and
returning the results as a string.

=cut
sub returnrun {
	my $self	= shift;
	my $class	= ref($self) || return undef;
	local(*XPP_TIE);
	warn "xpp: tying STDOUT" . ($debuglines ? '' : "\n") if ($debug);
	my $tieobj	= tie(*XPP_TIE, 'XPP::Tie');
	
	my $fh	= select( XPP_TIE );
	$self->run( @_ );
	select( $fh );
	
	my $content	= $tieobj->content();
#	untie(*XPP_TIE);
	return $content;
} # END method returnrun


=item C<load> ( $filename )

Returns the code specified by $filename.  If $filename begins with a url specifier
(e.g. http://), LWP::UserAgent will be used to retrieve the file.  If $filename
begins with a '/', it will be treated as a rooted filename.  Otherwise the filename
will be as a file relative to XPPIncludeDir

=cut
sub load {
	my $self		= shift;
	my $filename	= shift;
	my $counter		= shift;	# don't recurse
	warn "xpp: loading source ($filename)" . ($debuglines ? '' : "\n") if ($debug);
	
	if ((substr($filename,0,1) eq '/') or ((substr($filename,0,2) eq './') and ($counter))) {
		my $fh = new FileHandle;
		warn "xpp:\tattempting to load $filename" . ($debuglines ? '' : "\n") if ($debug);
#		if (($filename =~ m{^(/[/\-\w\.]+)$}) && ($fh->open($1))) {
		if ($fh->open($filename)) {
			local($/)	= undef;
			return <$fh>;
		} else {
			warn "xpp:\tfailed to load file $filename ($!)" . ($debuglines ? '' : "\n");
			return undef;
		}
	} elsif ($filename =~ m{^(?:.+)?://(?:.+)$}) {
		my $ua	= LWP::UserAgent->new;
		my $req	= HTTP::Request->new( 'GET', $filename );
		my $res	= $ua->request( $req );
		warn "xpp:\tattempting to load $filename from LWP::UserAgent" . ($debuglines ? '' : "\n") if ($debug);
		if ($res->is_success) {
			return $res->content;
		} else {
			warn "xpp:\tfailed to load file $filename ($!)" . ($debuglines ? '' : "\n");
			return undef;
		}
	} else {
		my $qualified	= $self->qualify( $filename );
		warn "xpp:\tqualifying filename, and attempting to load '${qualified}'" . ($debuglines ? '' : "\n") if ($debug);
		return $self->load( $qualified, 1 ) unless ($counter);
		return undef;
	}
} # END method load


sub mtime {
	my $self		= shift;
	my $filename	= ref($self) ? $self->filename : shift;
	my $counter		= shift;
	warn "xpp: checking mtime of file ($filename)" . ($debuglines ? '' : "\n") if ($debug);
	
	if (substr($filename,0,1) eq '/') {
		my $mtime = undef;
		unless (-f $filename) {
			return undef;
		}
		
		my $st = stat($filename);	# using File::stat
		if (ref($st) && $st->can('mtime')) {
			return $st->mtime;
		} else {
			warn "xpp:\tcannot stat file ($filename): $!" . ($debuglines ? '' : "\n") if ($debug);
			return undef;
		}
	} elsif ($filename =~ m{^((?:.+)?://(?:.+))$}) { 
		my $ua	= LWP::UserAgent->new;
		my $req	= HTTP::Request->new( 'GET', $filename );
		my $res	= $ua->request( $req );
		if (my $headers = $res->headers) {
			return $headers->last_modified;
		} else {
			warn "xpp:\tfailed to get mtime for url ($!)" . ($debuglines ? '' : "\n") if ($debug);
			return undef;
		}
	} else {
		warn "xpp:\tattempting to qualify filename, and mtime again '${filename}'" . ($debuglines ? '' : "\n") if ($debug);
		return $self->mtime( $self->qualify( $filename ), 1 ) unless ($counter);
		return undef;
	}
} # END method mtime


=item C<qualify> ( $filename )

Qualifies the passed name to a fully rooted filename by using either C<incdir> or C<docroot>.

=cut
sub qualify {
	my $self		= shift;
	my $filename	= shift;
	carp "xpp: qualifying filename ($filename)" . ($debuglines ? '' : "\n") if ($debug);
	
	if (substr($filename,0,1) eq '/') {
		warn "xpp:\tqualifying document rooted file" . ($debuglines ? '' : "\n") if ($debug >= 2);
		if ($filename =~ m{^(/[/\-\w\.]+)$}) {
			return join('', $self->docroot, $1);
		}
	} elsif ($filename =~ m{^((?:.+)?://(?:.+))$}) {
		warn "xpp:\tassuming URL is already qualified" . ($debuglines ? '' : "\n") if ($debug >= 2);
		return $1;
	} else {
		warn "xpp:\tqualifying include rooted file" . ($debuglines ? '' : "\n") if ($debug >= 2);
		warn "xpp:\tfilename: $filename" . ($debuglines ? '' : "\n") if ($debug >= 2);;
		if ($filename =~ m{^([/\-\w\.]+)$}) {
			my $r = $self->r();
			my $incdir = $self->incdir($r);
			return ($incdir) ? join('/', $incdir, $1) : $1;
		}
	}
	
	warn "xpp: qualify failed on filename '$filename'!" . ($debuglines ? '' : "\n") if ($debug);
	return undef;
} # END method qualify


=item C<incdir> (  )

Returns the include directory from which C<include> and C<xinclude> will retrieve source
from by default.  See C<include>, C<xinclude>, and C<load> for more documentation on this
process.

=cut
sub incdir {
	my $self	= shift;
	my $r		= (ref $self) ? $self->r : shift;
	#Not cleaning up for now, why not cache for the life of a process.
	#$r->register_cleanup(sub {undef $Apache::XPP::_cache::incdir}) unless (defined $Apache::XPP::_cache::incdir);



( run in 1.024 second using v1.01-cache-2.11-cpan-acf6aa7dc9e )