changeset 65:2840c4c85db8

Application configuration improvements Documentation
author wizard
date Tue, 16 Mar 2010 17:36:13 +0300
parents 259cd3df6e53
children f47f93534005
files Lib/IMPL/Web/Application.pm Lib/IMPL/Web/Application/Action.pm Lib/IMPL/Web/Application/Response.pm Lib/IMPL/Web/QueryHandler.pm Lib/IMPL/Web/QueryHandler/PageFormat.pm _doc/make.pl _test/Resources/app.xml
diffstat 7 files changed, 206 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/Lib/IMPL/Web/Application.pm	Mon Mar 15 17:45:13 2010 +0300
+++ b/Lib/IMPL/Web/Application.pm	Tue Mar 16 17:36:13 2010 +0300
@@ -16,6 +16,7 @@
     public property handlerError => prop_all;
     public property factoryAction => prop_all;
     public property handlersQuery => prop_all | prop_list;
+    public property responseCharset => prop_all;
     public property options => prop_all;
 }
 
@@ -30,6 +31,7 @@
 	my ($this) = @_;
 	
 	$this->factoryAction('IMPL::Web::Application::Action') unless $this->factoryAction;
+	$this->responseCharset('utf-8') unless $this->responseCharset;
 }
 
 sub Run {
@@ -37,12 +39,12 @@
     
     while (my $query = $this->FetchRequest()) {
         
-        # todo: move a creation of the response to the ActionClass
         my $action = $this->factoryAction->new(
         	query => $query,
-        	response => new IMPL::Web::Application::Response(query => $query),
         	application => $this, 
-        ); 
+        );
+        
+        $action->response->charset($this->responseCharset);
         
         $action->ChainHandler($_) foreach $this->handlersQuery;
         
--- a/Lib/IMPL/Web/Application/Action.pm	Mon Mar 15 17:45:13 2010 +0300
+++ b/Lib/IMPL/Web/Application/Action.pm	Tue Mar 16 17:36:13 2010 +0300
@@ -11,11 +11,17 @@
 	public property application => prop_get | owner_set;
 	public property query => prop_get | owner_set;
 	public property response => prop_get | owner_set;
+	public property responseFactory => prop_get | owner_set;
 	
 	private property _entryPoint => prop_all;
 }
 
-#todo: make ability to discard old and create new response
+sub CTOR {
+	my ($this) = @_;
+	
+	$this->responseFactory('IMPL::Web::Application::Response') unless $this->responseFactory; 
+	$this->response( $this->responseFactory->new(query => $this->query) );
+}
 
 sub Invoke {
 	my ($this) = @_;
@@ -27,6 +33,15 @@
 	}
 }
 
+sub ReinitResponse {
+	my ($this) = @_;
+	
+	die new IMPL::InvalidOperationException("Response already sent") if $this->response->isHeaderPrinted;
+	
+	$this->response->Discard;
+	$this->response($this->responseFactory->new(query => $this->query));
+}
+
 sub ChainHandler {
 	my ($this,$handler) = @_;
 	
--- a/Lib/IMPL/Web/Application/Response.pm	Mon Mar 15 17:45:13 2010 +0300
+++ b/Lib/IMPL/Web/Application/Response.pm	Tue Mar 16 17:36:13 2010 +0300
@@ -37,7 +37,16 @@
 	
 	$this->query(CGI->new($this->query() | {})) unless $this->query;
 	
-	$this->streamOut(*STDOUT) unless $this->streamOut;
+	if (lc $this->streamOut eq 'memory') {
+		my $dummy = '';
+		open my $hout, '>:encoding(utf8)', \$dummy or die new IMPL::Exception("Failed to create memory stream",$!);
+		$this->streamOut($hout);
+	} elsif (not $this->streamOut) {
+		$this->streamOut(*STDOUT);	
+	} else {
+		die new IMPL::InvalidArgumentException("Invalid parameter value",$this->streamOut);
+	}
+	
 	$this->buffered(1) unless defined $this->buffered;
 	binmode $this->streamOut, ":encoding(".$this->charset.")";
 }
--- a/Lib/IMPL/Web/QueryHandler.pm	Mon Mar 15 17:45:13 2010 +0300
+++ b/Lib/IMPL/Web/QueryHandler.pm	Tue Mar 16 17:36:13 2010 +0300
@@ -1,6 +1,6 @@
 package IMPL::Web::QueryHandler;
 
-use base qw(IMPL::Object IMPL::Object::Autofill);
+use base qw(IMPL::Object IMPL::Object::Autofill IMPL::Object::Serializable);
 use IMPL::Class::Property;
 
 __PACKAGE__->PassThroughArgs;
@@ -10,7 +10,7 @@
 sub Invoke {
 	my ($self,$action,$nextHandler) = @_;
 	
-	if (not ref $self or UNIVERSAL::isa($self,'IMPL::Object::Factory')) {
+	if (not ref $self) {
 		return $self->new( action => $action )->Invoke($action,$nextHandler);
 	} else {
 		return $self->Process($action,$nextHandler);
@@ -27,10 +27,32 @@
 
 =pod
 
-=head1 DESCRIPTION
+=head1 NAME
 
 Базовый класс для обработчиков запросов.
 
+=head1 SYNOPSIS
+
+Простой вариант
+
+=begin code
+
+package MyHandler;
+
+use base qw(IMPL::Web::QueryHandler);
+
+sub CTOR {
+	my ($this,%args) = @_;
+	
+}
+
+sub Process {
+	my ($this,$action,$nextHandler) = @_;
+	
+}
+
+=end code
+
 =head1 MEMBERS
 
 =over 4
@@ -38,16 +60,26 @@
 =item C< Invoke($action,$nextHandler) >
 
 Вызывается механизмом обработки запроса, для передачи управления обработчику. Данная реализация
-проверяет как была вызвана, если как статический метод, то создает экземпляр класса и вызывает
+проверяет контекст вызова, если как статический метод, то создает экземпляр класса и вызывает
 у созданного объекта метод C< Invoke > с параметрами C< $action >, C< $nextHandler >.
 
-Если метод был вызван у объекта, то управление передается методу C< Process >
+При создании нового объекта в конструктор передается именованый параметр C<action>. 
+
+Если метод был вызван у объекта, то управление передается методу C< Process >.
+
+=over
 
-C< $action > Экземпляр запроса
+=item C< $action >
+
+Экземпляр запроса
 
-C< $nextHandler > Делегат для вызова следующего обработчика. Вызывается без параметров, но следующему обработчику
+=item C< $nextHandler >
+
+Делегат для вызова следующего обработчика. Вызывается без параметров, но следующему обработчику
 втоматически будут переданы необходимые параметры.
 
 =back
 
+=back
+
 =cut
\ No newline at end of file
--- a/Lib/IMPL/Web/QueryHandler/PageFormat.pm	Mon Mar 15 17:45:13 2010 +0300
+++ b/Lib/IMPL/Web/QueryHandler/PageFormat.pm	Tue Mar 16 17:36:13 2010 +0300
@@ -5,16 +5,19 @@
 
 use IMPL::Class::Property;
 use IMPL::Web::TDocument;
+use File::Spec;
 use Error qw(:try);
 
 BEGIN {
-	public property charsetTemplates => prop_all;
+	public property templatesCharset => prop_all;
+	public property templatesBase => prop_all;
 }
 
 sub CTOR {
 	my ($this) = @_;
 	
-	$this->charsetTemplates('utf-8') unless $this->charsetTemplates;
+	$this->templatesCharset('utf-8') unless $this->templatesCharset;
+	$this->templatesBase('.') unless $this->templatesBase;
 }
 
 sub Process {
@@ -23,7 +26,9 @@
 	my $doc = new IMPL::Web::TDocument();
 	
 	try {
-		$doc->loadFile ( $ENV{PATH_TRANSLATED}, $this->charsetTemplates );
+		my @path = split /\//, $ENV{PATH_TRANSLATED};
+		
+		$doc->loadFile ( File::Spec->catfile($this->templatesBase,@path), $this->templatesCharset );
 		
 		$action->response->contentType('text/html');
 		my $hOut = $action->response->streamBody;
@@ -34,4 +39,72 @@
 	};
 }
 
-1;
\ No newline at end of file
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+C<IMPL::Web::QueryHandler::PageFormat> - Выдача результатов в виде HTML страницы, построенной из шаблона.
+
+=head1 SYNOPSIS
+
+В файле конфигурации приложения
+
+=begin code xml
+
+<handlersQuery type="IMPL::Object::List">
+	<item type="IMPL::Web::QueryHandler::PageFormat">
+		<charsetTemplates>utf-8</charsetTemplates>
+	</item>
+</handlersQuery>
+
+=end code xml
+
+Программно
+
+=begin code
+
+my $app = new IMPL::Web::Application();
+$app->handlersQuery->Add(
+	new IMPL::Web::QueryHandler::PageFormat( charsetTemplates=> 'utf-8' );
+);
+
+=end
+
+=head1 DESCRIPTION
+
+Обработчик запроса для веб приложения. Загружает шаблон, путь к котрому берется
+из C<ENV{PATH_INFO}> относительно пути из свойства C<templatesBase>.
+
+Наследуется от C<IMPL::Web::QueryHandler> для реализации функционала
+обработчика запроса и переопределяет метод C<Process>.
+
+C<Serializable>
+
+=head1 MEMBERS
+
+=over
+
+=item C<CTOR(%props)>
+
+Создает новый экземпляр и заполняет свойства.
+
+=item C<[get,set] templatesCharset>
+
+Кодировка шаблонов. По умолчанию utf-8.
+
+=item C<[get,set] templatesBase>
+
+Каталог относительно которого ищется шаблон.
+
+=item C<[override] Process($action,$nextHandler)>
+
+Метод, переопределяющий C<IMPL::Web::QueryHandler->Process> и которому передается управление
+для выполнения действий.
+
+=back
+
+=cut
\ No newline at end of file
--- a/_doc/make.pl	Mon Mar 15 17:45:13 2010 +0300
+++ b/_doc/make.pl	Tue Mar 16 17:36:13 2010 +0300
@@ -7,6 +7,7 @@
 
 our $LibDir = '../Lib/IMPL';
 our $OutDir = 'html';
+our $level = 0;
 
 our $index = { name => 'root' };
 
@@ -35,6 +36,8 @@
     
     my $pom = $parser->parse_file($hPod);
     
+    $level = @path;
+    
     print $hOut PodViewHTML->print($pom);
 }
 
@@ -118,13 +121,51 @@
 }
 sub view_begin {
 	my ($self,$begin) = @_;
-	$begin->format =~ /code/i ? return "<pre>\n".join ("",$begin->text())."</pre>\n" : return $self->SUPER::view_begin($begin); 
+	$begin->format =~ /code/i ? return "<pre>\n".escape_html(join ("",$begin->text()))."</pre>\n" : return $self->SUPER::view_begin($begin); 
+}
+
+sub escape_html {
+	my %esc = (
+		'&' => '&amp;',
+		'>' => '&gt;',
+		'<' => '&lt;'
+	);
+	
+	(my $text = shift) =~ s/([&><])/$esc{$1}/gex;
+	
+	return $text;
 }
 
 sub view_seq_link {
 	my ($self,$text) = @_;
 	
-	$text->text =~ /(?:(\w+)\s+)(\w+(?:\:\:\w+)*)/;
+	if ($text =~ /^\s*(?:(\w+)\s+)?(\w+(?:\:\:\w+)+)\s*$/) {
 	
+		my ($keyword, $package) = ($1 || '',$2);
+		
+		my @path = split /::/, $package;
+		
+		pop @path if $keyword;		
+		shift @path if uc $path[0] eq 'IMPL';
+		
+		if (-f File::Spec->catfile($LibDir,@path).".pm") {
+			return '<code><a href="'. '../'x($level-1) . File::Spec->catfile(@path) .'.html">'.$text.'</a></code>';			
+		}
+		
+	} elsif ($text =~ /^\s*(\w+(?:\:\:\w+)+)\s*-&gt;\s*(\w+)\s*$/) {
+		my ($package,$member) = ($1,$2);
+		
+		my @path = split /::/, $package;
+		shift @path;
+		
+		if (-f File::Spec->catfile($LibDir,@path).".pm") {
+			return '<code><a href="'. '../'x($level-1) . File::Spec->catfile(@path) .'.html">'.$text.'</a></code>';			
+		}
+	}
 	
-}
\ No newline at end of file
+	return "<code>$text</code>";
+}
+
+sub view_seq_code {
+	goto &view_seq_link;
+}
--- a/_test/Resources/app.xml	Mon Mar 15 17:45:13 2010 +0300
+++ b/_test/Resources/app.xml	Tue Mar 16 17:36:13 2010 +0300
@@ -17,7 +17,21 @@
 	<options type="HASH">
 		<dataSource refid='ds'/>
 	</options>
+	<responseCharset>utf-8</responseCharset>
+	<factoryAction type="IMPL::Object::Factory">
+		<factory>IMPL::Web::Application::Action</factory>
+		<parameters type='HASH'>
+			<responseFactory type='IMPL::Object::Factory'>
+				<factory>IMPL::Web::Application::Response</factory>
+				<parameters type='HASH'>
+					<streamOut>memory</streamOut>
+				</parameters>
+			</responseFactory>
+		</parameters>
+	</factoryAction>
 	<handlersQuery type="IMPL::Object::List">
-		<item>IMPL::Web::QueryHandler::PageFormat</item>
+		<item type="IMPL::Web::QueryHandler::PageFormat">
+			<templatesCharset>cp1251</templatesCharset>
+		</item>
 	</handlersQuery>
 </Application>
\ No newline at end of file