Ravenel
view release on metacpan or search on metacpan
lib/Ravenel/Document.pm view on Meta::CPAN
use Ravenel::Tag::Replace;
use Ravenel::SubScraper;
use fields qw(
document name prefix content_type docroot
tags tags_by_depth static_content
packages arguments
dynamic document_is_totally_dynamic
functions
default_post default_put default_delete
caller
lib_path
);
sub new {
my Ravenel::Document $self = shift;
my $option = shift;
unless ( ref($self) ) {
$self = fields::new($self);
$self->{'docroot'} = $option->{'docroot'} if ( $option->{'docroot'} );
if ( $self->{'docroot'} and $self->{'docroot'} !~ /\/$/ ) {
$self->{'docroot'} = "$self->{'docroot'}/";
}
if ( $option->{'data'} ) {
$self->{'document'} = $option->{'data'};
$self->{'content_type'} = $option->{'content_type'} || 'html'; # XXX Might change my mind :-(
$self->{'name'} = $option->{'name'};
} elsif ( $option->{'file'} ) {
if ( $option->{'content_type'} ) {
$self->{'content_type'} = $option->{'content_type'};
} else {
( $self->{'content_type'} ) = $option->{'file'} =~ ( /\.(.+)$/ );
}
if ( $option->{'name'} ) {
$self->{'name'} = $option->{'name'};
} else {
( $self->{'name'} ) = $option->{'file'} =~ ( /\/?([^\/\.]+)\..+$/ );
}
my $filename = ( $self->{'docroot'} ? $self->{'docroot'} . $option->{'file'} : $option->{'file'} );
confess("File not found: $filename, $!") if ( not -f $filename );
open(F, $filename);
$self->{'document'} = do { local $/; <F> };
close F;
}
$self->{'prefix'} ||= 'r:';
$self->{'dynamic'} = $option->{'dynamic'};
confess("'arguments' is invalid when generating a package (dynamic=$self->{'dynamic'})") if ( $self->{'arguments'} and $self->{'dynamic'} == 0 );
$self->{'document_is_totally_dynamic'} = $option->{'document_is_totally_dynamic'};
$self->{'arguments'} = $option->{'arguments'};
$self->{'tags'} = [];
$self->{'functions'} = $option->{'functions'};
$self->{'caller'} = $option->{'caller'} || (caller)[1];
if ( not $self->{'dynamic'} ) { # if static
confess("'name' required if not dynamically generated (dynamic=$self->{'dynamic'}, name=$self->{'name'})") if ( not $self->{'name'} );
# get the libraries
$self->{'lib_path'} = &get_libraries();
}
# replace wrap!
$self->{'document'} = "<r:replace>$self->{'document'}</r:replace>" if ( $option->{'replace_wrap'} );
}
return $self;
}
#########################################
#########################################
# Built in tag handling below
sub _look_for_tag {
my Ravenel::Document $self = shift;
my $tag = shift || '';
my $pos = shift || 0;
my $get_close_tag = shift;
my $expect_singleton = shift;
$get_close_tag = ( $get_close_tag ? '/' : '' );
my $start_pos = index($self->{'document'}, '<' . $get_close_tag . $self->{'prefix'} . $tag, $pos);
return if ( $start_pos == -1 );
my $end_pos = index($self->{'document'}, '>', $start_pos);
my $beginning_of_tag_content = $start_pos + length("<$self->{'prefix'}");
my $end_of_tag_content = $end_pos - $start_pos - length($self->{'prefix'});
if ( $get_close_tag) { # account for "</" closing tag
$beginning_of_tag_content++;
$end_of_tag_content -= 2;
}
my $inner = substr( $self->{'document'}, $beginning_of_tag_content, $end_of_tag_content );
if ( $get_close_tag ) {
return { 'close_start_pos' => $start_pos, 'close_end_pos' => $end_pos };
} else {
if ( $inner =~ /\/>$/ ) {
$inner =~ s|/?>||;
my ( $action, $option ) = $inner =~ /^([^\s]+)[\s\=]*([^\/]+)?$/;
#print "inner=$inner, start_pos=$start_pos, end_pos=$end_pos, action=$action, option=$option\n";
return { 'start_pos' => $start_pos, 'end_pos' => $end_pos, 'inner' => $inner, 'action' => $action, 'option' => $option, 'pos' => $end_pos };
} elsif ( $expect_singleton ) {
confess("Expected a singleton for tag '$tag'");
} else {
$inner = substr( $self->{'document'}, $beginning_of_tag_content, $end_of_tag_content -1 );
my ( $action, $option ) = $inner =~ /^([^\s]+)[\s\=]*([^\/]+)?>$/;
#print "look for end tag, action=$action, option=$option\n";
my $et = $self->_look_for_tag($action, $end_pos, 'close_tag');
#print Dumper($et);
lib/Ravenel/Document.pm view on Meta::CPAN
if ( $block->isa("Ravenel::Redirect") ) {
# XXX handle redirect
} else {
confess("Invalid return type: " . ref($block));
}
} else {
if ( index($block, "<$prefix") >= 0 ) {
my Ravenel::Document $doc = new Ravenel::Document( {
'data' => $block,
'prefix' => $prefix,
'content_type' => $content_type,
'dynamic' => 1,
'functions' => $functions,
'name' => $name,
'arguments' => $arguments,
} );
return $doc->parse('dynamic');
} else {
return $block;
}
}
return;
}
sub get_libraries {
my $VAR1;
my $reg_lib = `perl -MData::Dumper -e "print Dumper(\\\@INC);"`;
eval $reg_lib;
my %seen;
my @unique = grep { $seen{$_} == 1 } map { $seen{$_}++; $_ } @{$VAR1}, @INC;
return \@unique;
}
sub parse {
my Ravenel::Document $self = shift;
$self->look_for_actions();
if ( $self->{'dynamic'} ) {
while ( $self->get_all_tags() ) {
$self->expand_tags();
$self->replace_tags_with_content();
$self->look_for_actions();
}
return $self->{'document'};
} else {
$self->get_all_tags();
return $self->build_document();
}
return;
}
sub render {
my $class = shift;
my $option = shift;
confess("Option hash required") if ( not $option or not ref($option) );
$option->{'dynamic'} = ( defined($option->{'dynamic'}) ? $option->{'dynamic'} : 1 );
$option->{'caller'} = (caller)[1];
my Ravenel::Document $document = new Ravenel::Document($option);
$document->{'document_is_totally_dynamic'} = $option->{'dynamic'};
return $document->parse();
}
1;
( run in 4.518 seconds using v1.01-cache-2.11-cpan-364913b4093 )