changeset 63:76b878ad6596

Added serialization support for the IMPL::Object::List More intelligent Exception message Fixed encoding support in the actions Improoved tests Minor fixes
author wizard
date Mon, 15 Mar 2010 02:38:09 +0300
parents c64bd1bf727d
children 259cd3df6e53
files .settings/org.eclipse.core.resources.prefs Lib/IMPL/Class/Property/Base.pm Lib/IMPL/Config.pm Lib/IMPL/Exception.pm Lib/IMPL/Object/Abstract.pm Lib/IMPL/Object/List.pm Lib/IMPL/Object/Meta.pm Lib/IMPL/Web/Application.pm Lib/IMPL/Web/Application/Action.pm Lib/IMPL/Web/Application/Response.pm Lib/IMPL/Web/QueryHandler/PageFormat.pm _test/Resources/app.xml _test/Test/Web/Application.pm
diffstat 13 files changed, 145 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/.settings/org.eclipse.core.resources.prefs	Fri Mar 12 16:23:46 2010 +0300
+++ b/.settings/org.eclipse.core.resources.prefs	Mon Mar 15 02:38:09 2010 +0300
@@ -1,3 +1,3 @@
-#Fri Feb 26 10:46:20 MSK 2010
+#Sat Mar 13 04:39:05 MSK 2010
 eclipse.preferences.version=1
 encoding/<project>=cp1251
--- a/Lib/IMPL/Class/Property/Base.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/Lib/IMPL/Class/Property/Base.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -161,9 +161,9 @@
     \$accessor = sub {
         my \$this = shift;
         $codeAccessCheck
-        $codeValidator
         if (\@_) {
         	$codeOwnerCheck
+        	$codeValidator
         	$codeSet
         } else {
         	$codeGet
--- a/Lib/IMPL/Config.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/Lib/IMPL/Config.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -76,14 +76,16 @@
 
 sub save {
     my ($this,$ctx) = @_;
-
-    foreach my $info ($this->get_meta('IMPL::Class::PropertyInfo')) {
-        next if $info->Access != IMPL::Class::Member::MOD_PUBLIC; # save only public properties
+    
+    my $val;
 
-        my $name = $info->Name;
-        $ctx->AddVar($name => $this->rawGet($name)) if $this->rawGet($name);
-    }
-    
+    $val = $this->rawGet($_) and $ctx->AddVar($_ => $val) foreach map $_->Name, $this->get_meta(
+    	'IMPL::Class::PropertyInfo',
+    	sub {
+    		$_->Access == IMPL::Class::Member::MOD_PUBLIC and
+    		$_->canGet;
+    	},
+    	1);    
 }
 
 sub spawn {
--- a/Lib/IMPL/Exception.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/Lib/IMPL/Exception.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -81,7 +81,7 @@
 
 sub toString {
     my ($this,$notrace) = @_;
-    $this->Message . join("\n",'',map { my $s = $_; local $_; indent("$s",1) } @{$this->Args} ) . ( $notrace ? '' : "\n" . $this->CallStack);
+    ($this->Message || ref $this) . join("\n",'',map { my $s = $_; local $_; indent("$s",1) } @{$this->Args} ) . ( $notrace ? '' : "\n" . $this->CallStack);
 }
 
 package IMPL::InvalidOperationException;
--- a/Lib/IMPL/Object/Abstract.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/Lib/IMPL/Object/Abstract.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -113,8 +113,12 @@
     $sub = $_->can($methodName) and $sub->(@_) foreach @{caller().'::ISA'};
 }
 
+1;
+
+__END__
+
 =pod
-=h1 SYNOPSIS
+=head1 SYNOPSIS
 
 package MyBaseObject;
 use base qw(IMPL::Object::Abstract);
@@ -127,10 +131,8 @@
     # own implementation of the surrogate operator
 }
 
-=h1 DESCRIPTION
+=head1 DESCRIPTION
 
 Реализация механизма вызова конструкторов и других вспомогательных вещей, кроме операторов
 создания экземпляров.
 =cut
-
-1;
--- a/Lib/IMPL/Object/List.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/Lib/IMPL/Object/List.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -68,5 +68,24 @@
     return $this;
 }
 
+sub save {
+	my ($this,$ctx) = @_;
+	
+	$ctx->AddVar( item => $_ ) foreach @$this;
+}
+
+sub restore {
+	my ($class,$data,$surrogate) = @_;
+	
+	my $i = 0;
+	
+	if ($surrogate) {
+		@$surrogate = grep { ($i++)%2 } @$data;
+	} else {
+		$surrogate = $class->new([grep { ($i++)%2 } @$data]);
+	}
+	
+	return $surrogate;
+}
 
 1;
--- a/Lib/IMPL/Object/Meta.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/Lib/IMPL/Object/Meta.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -7,17 +7,42 @@
 use IMPL::Class::Property::Direct;
 
 BEGIN {
-    public _direct property Container => prop_get;
+    public _direct property Container => prop_get | owner_set;
 }
 
 sub meta {
     my $class = shift;
     my $caller = caller;
     my $meta = $class->surrogate();
-    $meta->{$Container} = $caller;
+    $meta->IMPL::Object::Meta::Container(caller);
     $meta->callCTOR(@_);
     $caller->set_meta($meta);
 }
 
+1;
 
-1;
+__END__
+
+=pod
+
+=head1 SYNOPSIS
+
+package Foo;
+
+meta BarAttribute('Simple bar attribute'); #mark Foo with BarAttribute
+
+=head1 DESCRIPTION
+
+Базовый класс для мета-свойств класса. Определяет оператор C< meta > для создания метаданных в вызвавшем классе.
+
+=head1 MEMBERS
+
+=over
+
+=item C< Container >
+
+Свойство заполняется до вызова конструктора и содержит имя модуля к которому применяется атрибут.
+
+=back
+
+=cut
\ No newline at end of file
--- a/Lib/IMPL/Web/Application.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/Lib/IMPL/Web/Application.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -16,7 +16,7 @@
     public property handlerError => prop_all;
     public property factoryAction => prop_all;
     public property handlersQuery => prop_all | prop_list;
-    public property configuration => prop_all;
+    public property options => prop_all;
 }
 
 # custom factory
@@ -36,17 +36,19 @@
     my ($this) = @_;
     
     while (my $query = $this->FetchRequest()) {
-        my $response = new IMPL::Web::Application::Response(query => $query);
         
+        # todo: move a creation of the response to the ActionClass
         my $action = $this->factoryAction->new(
         	query => $query,
-        	response => $response,
+        	response => new IMPL::Web::Application::Response(query => $query),
         	application => $this, 
         ); 
         
         $action->ChainHandler($_) foreach $this->handlersQuery;
         
         $action->Invoke();
+        
+        $action->response->Complete;
     }
 }
 
--- a/Lib/IMPL/Web/Application/Action.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/Lib/IMPL/Web/Application/Action.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -3,6 +3,8 @@
 
 use base qw(IMPL::Object IMPL::Object::Autofill);
 
+__PACKAGE__->PassThroughArgs;
+
 use IMPL::Class::Property;
 
 BEGIN {
@@ -13,6 +15,8 @@
 	private property _entryPoint => prop_all;
 }
 
+#todo: make ability to discard old and create new response
+
 sub Invoke {
 	my ($this) = @_;
 	
@@ -32,18 +36,32 @@
 		$this->_entryPoint( sub {
 			$handler->($this,$delegateNext);			
 		} );
-	} elsif (UNIVERSAL::isa($handler,'IMPL::Web::Application::QueryHandler')) {
+	} elsif (ref $handler and UNIVERSAL::isa($handler,'IMPL::Web::QueryHandler')) {
 		$this->_entryPoint( sub {
 			$handler->Invoke($this,$delegateNext);
 		} );
 	} elsif ($handler and not ref $handler) {
-		my $method = $this->can($handler) or die new IMPL::InvalidArgumentException("An invalid handler supplied");
 		
-		$this->_entryPoint( sub {
-			$method->($this,$delegateNext);			
-		} );
+		if (my $method = $this->can($handler) ) {
+			$this->_entryPoint( sub {
+				$method->($this,$delegateNext);			
+			} );
+		} else {
+			{
+				no strict 'refs';
+				eval "require $handler; 1;" or die new IMPL::InvalidArgumentException("An invalid handler supplied",$handler,"Failed to load module") unless keys %{"${handler}::"};
+			}
+			
+			if (UNIVERSAL::isa($handler,'IMPL::Web::QueryHandler')) {
+				$this->_entryPoint( sub {
+					$handler->Invoke($this,$delegateNext);
+				} );	
+			} else {
+				die new IMPL::InvalidArgumentException("An invalid handler supplied",$handler);
+			}
+		}
 	} else {
-		die new IMPL::InvalidArgumentException("An invalid handler supplied");
+		die new IMPL::InvalidArgumentException("An invalid handler supplied",$handler);
 	}
 	
 }
--- a/Lib/IMPL/Web/Application/Response.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/Lib/IMPL/Web/Application/Response.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -8,8 +8,11 @@
 require CGI::Cookie;
 
 use Carp;
+use Encode;
 use IMPL::Class::Property;
 
+#todo: add binary method to set a binary encoding, set it automatic when type isn't a text 
+
 BEGIN {
 	public property query => prop_get | owner_set; # cgi query
 	public property status => prop_all, { validator => \&_checkHeaderPrinted };
@@ -33,9 +36,10 @@
 	my ($this,%args) = @_;
 	
 	$this->query(CGI->new($this->query() | {})) unless $this->query;
-	$this->charset($this->query->charset) unless $this->charset;
 	
 	$this->streamOut(*STDOUT) unless $this->streamOut;
+	$this->buffered(1) unless defined $this->buffered;
+	binmode $this->streamOut, ":encoding(".$this->charset.")";
 }
 
 sub _checkHeaderPrinted {
@@ -53,7 +57,18 @@
 sub _charset {
 	my $this = shift;
 	
-	return $this->query->charset(@_);
+	if (@_) {
+		my $charset = $this->query->charset(@_);
+		
+		my $hout = $this->streamOut;
+		
+		binmode $hout;
+		binmode $hout, ":encoding($charset)";
+		
+		return $charset;
+	} else {
+		return $this->query->charset;
+	}
 }
 
 sub _PrintHeader {
@@ -87,9 +102,12 @@
 	unless ($this->_streamBody) {
 		if ($this->buffered) {
 			my $buffer = "";
+			
 			$this->_bufferBody(\$buffer);
 				
-			open my $hBody, ">", \$buffer or die new IMPL::Exception("Failed to create buffer",$!);
+			open my $hBody, ">:encoding(utf-8)", \$buffer or die new IMPL::Exception("Failed to create buffer",$!);
+			
+			Encode::_utf8_on($buffer);
 				
 			$this->_streamBody($hBody);
 		} else {
@@ -110,11 +128,12 @@
 	
 	$this->_PrintHeader();
 	
+	$this->_streamBody(undef);
+	
 	if ($this->buffered) {
 		print $hOut ${$this->_bufferBody};	
-	}
+	}	
 	
-	$this->_streamBody(undef);
 	$this->_bufferBody(undef);
 	$this->streamOut(undef);
 	
--- a/Lib/IMPL/Web/QueryHandler/PageFormat.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/Lib/IMPL/Web/QueryHandler/PageFormat.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -4,12 +4,24 @@
 __PACKAGE__->PassThroughArgs;
 
 use IMPL::Class::Property;
-use URI;
+use IMPL::Web::TDocument;
+use Error qw(:try);
 
 sub Process {
 	my ($this,$action,$nextHandler) = @_;
 	
+	my $doc = new IMPL::Web::TDocument();
 	
+	try {
+		$doc->loadFile ( $ENV{PATH_TRANSLATED}, 'cp1251' );
+		
+		$action->response->contentType('text/html');
+		my $hOut = $action->response->streamBody;
+		
+		print $hOut $doc->Render();
+	} finally {
+		$doc->Dispose;
+	};
 }
 
 1;
\ No newline at end of file
--- a/_test/Resources/app.xml	Fri Mar 12 16:23:46 2010 +0300
+++ b/_test/Resources/app.xml	Mon Mar 15 02:38:09 2010 +0300
@@ -1,21 +1,23 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Application id='app' type="Test::Web::Application::Instance">
-	<name type='SCALAR' id='appName'>Sample application</name>
+	<name>Sample application</name>
 	<dataSource type='IMPL::Config::Activator' id='ds'>
-		<factory>Test::Config::DataSource</factory>
+		<factory>IMPL::Object</factory>
 		<parameters type='HASH'>
 			<db>data</db>
 			<user>nobody</user>
 		</parameters>
 	</dataSource>
 	<securityMod type='IMPL::Config::Activator'>
-		<factory>Test::Config::Security</factory>
+		<factory>IMPL::Object</factory>
 		<parameters type='HASH'>
 			<ds refid='ds'/>
 		</parameters>
 	</securityMod>
 	<options type="HASH">
-		<appName refid='appName'/>
 		<dataSource refid='ds'/>
 	</options>
+	<handlersQuery type="IMPL::Object::List">
+		<item>IMPL::Web::QueryHandler::PageFormat</item>
+	</handlersQuery>
 </Application>
\ No newline at end of file
--- a/_test/Test/Web/Application.pm	Fri Mar 12 16:23:46 2010 +0300
+++ b/_test/Test/Web/Application.pm	Mon Mar 15 02:38:09 2010 +0300
@@ -10,6 +10,8 @@
 
 sub CTOR {
 	# simulate CGI environment
+	
+	$ENV{PATH_TRANSLATED} = "Resources/simple.tt";
 }
 
 test SpawnApp => sub {
@@ -29,7 +31,12 @@
 test SaveXml => sub {
 	my $instance = spawn Test::Web::Application::Instance('Resources/app.xml');
 	
-	warn $instance->xml;	
+	$instance->xml or failed "xml property is invalid";	
+};
+
+test Run => sub {
+	my $instance = spawn Test::Web::Application::Instance('Resources/app.xml');
+	$instance->Run();
 };
 
 package Test::Web::Application::Instance;