changeset 225:a1e868b0fba9

Bindings concept in progress
author sergey
date Fri, 31 Aug 2012 16:41:18 +0400
parents e6c050db7d98
children b6cde007a175
files Lib/IMPL/Code/Binding.pm _test/Resources/sample.xml _test/test_binding.pl
diffstat 3 files changed, 201 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Lib/IMPL/Code/Binding.pm	Fri Aug 31 16:41:18 2012 +0400
@@ -0,0 +1,83 @@
+package IMPL::Code::Binding;
+use strict;
+
+use IMPL::require {
+	Exception => 'IMPL::Exception',
+	ArgumentException => '-IMPL::ArgumentException'
+};
+
+sub new {
+	my ($self,$expr,$vars) = @_;
+	
+	$vars ||= [];
+	
+	die ArgumentException( vars => 'A reference to an array is required')
+	   unless ref $vars eq 'ARRAY';
+	
+	m/^\w+$/ or die ArgumentException->new( vars => 'A valid variable name is required', $_ )
+	   foreach @$vars;    
+	
+	my $varnames = join (',', map { "\$$_" } @$vars);   
+    
+    my $code = <<CODE;
+    sub {
+        my ($varnames) = \@_;
+        $text
+    }
+CODE
+    my $body = eval $code; #$compiler_env->reval($code,'strict');
+    
+    
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+C<IMPL::Code::Binding> - превращает выражения в связыватель
+
+=head1 SYNOPSIS
+
+=begin code
+
+use IMPL::require {
+	Binding => 'IMPL::Code::Binding'
+}
+
+my $person = DB->SearchPerson({name => 'Peter'})->First;
+
+my $bind = Binding->new(
+    [qw(obj)] => q{ $obj->addresses->[0]->country->code }
+);
+
+print $bind->($person);
+
+=end
+
+=head1 DESCRIPTION
+
+Позвоялет преобразовать выражение в функцию, которую можно будет многократно
+использовать для получения значения выражения.
+
+Выражение параметризуется произвольным количеством именованных параметров,
+которые будут доступны внутри выражения как переменные. При создании связывателя
+в конструктор передается выражение связывания, ссылка насписок из параметров
+и могут быть переданы связи для копозиции.
+
+При создания связывателя будет проверен синтаксис, и если в выражении допущена
+ошибка, возникнет исключение.
+
+Данный класс не является безопасным при создании связывателей из ненадежных
+источников, поскольку внутри будет выполнен C<eval>.
+
+=head1 MEMBERS
+
+=head2 C<new($expression,\@vars,\%bindings)>
+
+Возвращает ссылку на процедуру.
+
+=cut
\ No newline at end of file
--- a/_test/Resources/sample.xml	Wed Aug 29 17:28:13 2012 +0400
+++ b/_test/Resources/sample.xml	Fri Aug 31 16:41:18 2012 +0400
@@ -3,14 +3,14 @@
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://implab.org/schemas/resources resources.xsd ">
 	<root>
-		<get expr="model" />
+		<get expr="$model" />
 
 		<resource>
 			<name>projects</name>
-			<model expr="model" />
-			<get expr="model.projects" />
+			<model expr="$model" />
+			<get expr="$model->projects" />
 
-			<post expr="model.CreateProject(project)">
+			<post expr="$model->CreateProject($project)">
 				<var name="project">
 					<transform class="IMPL::Web::Transform::BindModel" />
 				</var>
@@ -23,29 +23,31 @@
 
 			<resource>
 				<match>(\w+)</match>
-				<model expr="model.GetProject(resourceId)" />
+				<model expr="$model->GetProject($resourceId)" />
 
-				<get expr="model" />
-				<put expr="model.update(data)">
+				<get expr="$model" />
+				<put expr="$model->update(data)">
+				    <var name="data">
+				        <transform class="IMPL::Web::Transform::BindModel" />
+				    </var>
 				</put>
 
 				<resource>
 					<name>library</name>
-					<model expr="model" />
-					<get expr="model" />
+					<model expr="$model" />
+					<get expr="$model" />
 				</resource>
 				<resource>
 					<name>sources</name>
-					<model expr="model" />
-					<get expr="model" />
+					<model expr="$model" />
+					<get expr="$model" />
 				</resource>
 			</resource>
 		</resource>
 	</root>
 	<contracts>
-		<contract id="project-contract">
-			<modelType>Benzin::Model::Project</modelType>
-			<get expr="model"/>
+		<contract id="project-contract" modelType="IMPL::Web::Model::Project">
+			<get expr="$model"/>
 		</contract>
 	</contracts>
 </resources>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_test/test_binding.pl	Fri Aug 31 16:41:18 2012 +0400
@@ -0,0 +1,102 @@
+use strict;
+
+package Person;
+use IMPL::lang qw(:declare);
+use IMPL::declare {
+	base => [
+	   'IMPL::Object' => undef,
+	   'IMPL::Object::Autofill' => '@_'
+	]
+};
+
+BEGIN {
+	public property name => PROP_ALL;
+	public property age => PROP_ALL;
+	public property address => PROP_ALL|PROP_LIST, {type => 'Address'};
+}
+
+package Address;
+use IMPL::lang qw(:declare);
+use IMPL::declare {
+	base => [
+	   'IMPL::Object' => undef,
+	   'IMPL::Object::Autofill' => '@_'
+	]
+};
+
+BEGIN {
+	public property street => PROP_ALL;
+	public property city => PROP_ALL;
+	public property country => PROP_ALL;
+}
+
+package main;
+
+my $target = Person->new(
+    name => 'Peter',
+    age => '43',
+    address => [
+        Address->new(
+            country => 'US',
+            city => 'Dallas',
+            street => '6 Avenue'
+        ),
+        Address->new(
+            country => 'US',
+            city => 'Magnolia',
+            street => 'Heaven line'
+        )
+    ]
+);
+
+my $expr = q{
+	$person->address->Count
+};
+
+use Safe;
+my $compiler_env = new Safe("IMPL::Bindings::Sandbox");
+
+sub compile {
+	my ($text,$target,$vars) = @_;
+	
+	$vars ||= {};
+	$target ||= 'target';
+	my @keys = keys %$vars;
+	my $varnames = join (',', map { "\$$_" } $target, @keys);	
+	
+	my $code = <<CODE;
+	sub {
+		my ($varnames) = \@_;
+		$text
+	}
+CODE
+	my $body = eval $code; #$compiler_env->reval($code,'strict');
+	
+	return sub {
+		my $target = shift;
+		my @args = ($target);
+		push @args, $vars->{$_} foreach @keys;
+		
+		return $body->(@args);
+	}
+}
+
+my $binding = compile($expr,'person');
+
+use Time::HiRes qw(gettimeofday tv_interval);
+    
+my $t = [gettimeofday];
+
+for(my $i = 0; $i < 100000; $i++) {
+    $binding->($target);
+}
+
+print "Binding: ",tv_interval($t,[gettimeofday]),"\n";
+
+$t = [gettimeofday];
+
+for(my $i = 0; $i < 100000; $i++) {
+    $target->address->Count;
+}
+
+print "Direct: ",tv_interval($t,[gettimeofday]),"\n";
\ No newline at end of file