changeset 223:edf011437be8

updated resources schema
author sergey
date Tue, 28 Aug 2012 17:29:42 +0400
parents 84a6382b49c8
children e6c050db7d98
files _test/Resources/resources.xsd _test/Resources/sample.xml _test/temp.pl _test/test_transform.pl
diffstat 4 files changed, 245 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/_test/Resources/resources.xsd	Mon Aug 27 17:28:32 2012 +0400
+++ b/_test/Resources/resources.xsd	Tue Aug 28 17:29:42 2012 +0400
@@ -5,17 +5,18 @@
 	<element name="resources">
 		<complexType>
 			<sequence>
-				<element name="root" type="tns:resourceContract" />
-				<element name="typeMap" minOccurs="0">
+				<element name="root" type="tns:ResourceContract" />
+				<element name="contracts" minOccurs="0">
 					<complexType>
 						<sequence>
 							<element name="contract" maxOccurs="unbounded">
 								<complexType>
 									<complexContent>
-										<extension base="tns:resourceContract">
-											<sequence></sequence>
-											<attribute name="type" type="string" use="required">
-											</attribute>
+										<extension base="tns:ResourceContract">
+											<all>
+												<element name="modelType" type="tns:ClassName" />
+											</all>
+											<attribute name="id" type="string" />
 										</extension>
 									</complexContent>
 								</complexType>
@@ -29,7 +30,7 @@
 							<element name="locator" maxOccurs="unbounded">
 								<complexType>
 									<complexContent>
-										<extension base="tns:resourceLocator">
+										<extension base="tns:ResourceLocator">
 											<attribute name="name" type="string" />
 										</extension>
 									</complexContent>
@@ -51,54 +52,74 @@
 	</element>
 
 	<!-- abstract types -->
-	<complexType name="abstractBinding" abstract="true" />
-	<complexType name="abstractTransformation" abstract="true" />
-	<complexType name="abstractResult" abstract="true" />
+	<complexType name="AbstractBinding" abstract="true" />
+	<complexType name="AbstractTransformation" abstract="true" />
+	<complexType name="AbstractResult" abstract="true" />
 
-	<complexType name="resourceContract">
+	<complexType name="ResourceContract">
 		<sequence>
-			<group ref="tns:restOperations"></group>
-			<element name="resource" maxOccurs="unbounded" minOccurs="0">
-				<complexType>
-					<sequence>
-						<element name="contract" type="tns:resourceContract" />
-					</sequence>
-					<attribute name="name" type="string" />
-				</complexType>
-			</element>
+			<group ref="tns:RestOperations" />
+			<element name="resource" maxOccurs="unbounded" minOccurs="0"
+				type="tns:ChildResourceContract" />
 		</sequence>
 	</complexType>
 
-	<group name="restOperations">
+	<complexType name="ChildResourceContract">
 		<sequence>
-			<element name="get" type="tns:operationContract" minOccurs="0" />
-			<element name="post" type="tns:operationContract" minOccurs="0" />
-			<element name="put" type="tns:operationContract" minOccurs="0" />
-			<element name="delete" type="tns:operationContract"
+			<choice>
+				<element name="name" type="string" />
+				<element name="match" type="string" />
+			</choice>
+			<element name="model" minOccurs="0" type="tns:MethodBinding" />
+			<choice>
+				<element name="contract">
+					<complexType>
+						<attribute name="ref" type="string" use="required" />
+					</complexType>
+				</element>
+				<sequence>
+					<group ref="tns:RestOperations" />
+					<element name="resource" type="tns:ChildResourceContract"
+						minOccurs="0" maxOccurs="unbounded" />
+				</sequence>
+			</choice>
+		</sequence>
+
+	</complexType>
+
+	<group name="RestOperations">
+		<sequence>
+			<element name="get" type="tns:OperationContract" minOccurs="0" />
+			<element name="post" type="tns:OperationContract" minOccurs="0" />
+			<element name="put" type="tns:OperationContract" minOccurs="0" />
+			<element name="delete" type="tns:OperationContract"
 				minOccurs="0" />
 		</sequence>
 	</group>
 
-	<complexType name="operationContract">
-		<sequence>
-			<element name="bind" type="tns:methodBinding" />
-			<element name="parameters" type="tns:transformation"
-				minOccurs="0" />
-			<element name="response" type="tns:abstractResult" minOccurs="0" />
-		</sequence>
+	<complexType name="OperationContract">
+		<complexContent>
+			<extension base="tns:MethodBinding">
+				<sequence>
+					<element name="response" type="tns:AbstractResult"
+						minOccurs="0" />
+				</sequence>
+			</extension>
+		</complexContent>
 	</complexType>
 
-	<complexType name="methodBinding">
+	<complexType name="MethodBinding">
 		<sequence>
-			<element name="var" type="tns:bindingVariable" minOccurs="0"
+			<element name="var" type="tns:BindingVariable" minOccurs="0"
 				maxOccurs="unbounded" />
 		</sequence>
-		<attribute name="bind" type="string" use="required" />
+		<attribute name="expr" type="string" use="required" />
+		<attribute name="handler" type="string" />
 	</complexType>
 
-	<complexType name="bindingVariable">
+	<complexType name="BindingVariable">
 		<complexContent>
-			<extension base="tns:methodBinding">
+			<extension base="tns:MethodBinding">
 				<attribute name="name" type="string" />
 			</extension>
 		</complexContent>
@@ -109,15 +130,15 @@
 		<attribute name="class" type="string" />
 	</complexType>
 
-	<complexType name="resourceLocator">
+	<complexType name="ResourceLocator">
 		<sequence>
-			<element name="var" type="tns:bindingVariable" minOccurs="0"
+			<element name="var" type="tns:BindingVariable" minOccurs="0"
 				maxOccurs="unbounded" />
 			<element name="template" type="string" />
 		</sequence>
 	</complexType>
 
-	<simpleType name="redirectCodes">
+	<simpleType name="RedirectCodes">
 		<restriction base="string">
 			<enumeration value="moved-permanently" />
 			<enumeration value="temporary-redirect" />
@@ -125,20 +146,26 @@
 		</restriction>
 	</simpleType>
 
-	<complexType name="redirectResponse">
+	<complexType name="RedirectResponse">
 		<complexContent>
-			<extension base="tns:abstractResult">
+			<extension base="tns:AbstractResult">
 				<choice>
-					<element name="locator" type="tns:resourceLocator" />
+					<element name="locator" type="tns:ResourceLocator" />
 					<element name="locatorRef">
 						<complexType>
 							<attribute name="ref" type="string" />
 						</complexType>
 					</element>
-					<element name="status" type="tns:redirectCodes" minOccurs="0" />
+					<element name="status" type="tns:RedirectCodes" minOccurs="0" />
 				</choice>
 			</extension>
 		</complexContent>
 	</complexType>
 
+	<simpleType name="ClassName">
+		<restriction base="string">
+			<pattern value="\w+(::\w+)*" />
+		</restriction>
+	</simpleType>
+
 </schema>
\ No newline at end of file
--- a/_test/Resources/sample.xml	Mon Aug 27 17:28:32 2012 +0400
+++ b/_test/Resources/sample.xml	Tue Aug 28 17:29:42 2012 +0400
@@ -3,41 +3,56 @@
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://implab.org/schemas/resources resources.xsd ">
 	<root>
-		<get>
-			<bind bind="model" />
-		</get>
+		<get expr="model" />
+
+		<resource>
+			<name>projects</name>
+			<model expr="model"/>
+			<get expr="model.projects" />
+
+			<post expr="model.CreateProject(project)">
+				<var name="project" expr="BindModel()"/>
+				<response xsi:type="RedirectResponse">
+					<locatorRef ref="projects-locator" />
+				</response>
+			</post>
 
-		<resource name="projects">
-		    <contract>
-		      <get>
-		          <bind bind="parent.model.projects" />
-		      </get>
-		      <post>
-		          <bind bind="parent.model.CreateProject($form)">
-		              <var name="form" bind="request"/>
-		          </bind>
-		          <response xsi:type="redirectResponse">
-		              <locatorRef ref="relative-locator"/>
-		          </response>
-		      </post>
-		    </contract>
-		    
-		    <resource match="(\w+)">
-		    
-		    </resource>
+			<resource>
+				<match>(\w+)</match>
+				<model expr="model.GetProject(resourceId)"/>
+				
+				<get expr="model"/>
+				<put expr="model.update(data)">
+				</put>
+				
+				<resource>
+				    <name>library</name>
+				    <model expr="model"/>
+				    <get expr="model"/>
+				</resource>
+				<resource>
+				    <name>sources</name>
+				    <model expr="model"/>
+				    <get expr="model"/>
+				</resource>
+			</resource>
 		</resource>
 	</root>
-	<typeMap>
-	</typeMap>
+	<contracts>
+	   <contract id="project-contract">
+	       <modelType>Benzin::Model::Project</modelType>
+	       <get/>
+	   </contract>
+	</contracts>
 	<locators>
 		<locator name="relative-locator">
-			<var name="id" bind="model.id" />
-			<var name="parent" bind="parent.location" />
+			<var name="id" expr="model.id" />
+			<var name="parent" expr="parent.location" />
 			<template>$parent/$id</template>
 		</locator>
 		<locator name="projects-locator">
-			<var name="id" bind="model.id" />
-			<var name="projects" bind="application.locate('projects')" />
+			<var name="id" expr="model.id" />
+			<var name="projects" expr="application.locate('projects')" />
 			<template>$projects/$id</template>
 		</locator>
 	</locators>
--- a/_test/temp.pl	Mon Aug 27 17:28:32 2012 +0400
+++ b/_test/temp.pl	Tue Aug 28 17:29:42 2012 +0400
@@ -14,7 +14,7 @@
 my $reader = $schema->compile(
     READER => $type,
     xsi_type => {
-    	pack_type('http://implab.org/schemas/resources','abstractResult') => 'AUTO'
+    	pack_type('http://implab.org/schemas/resources','AbstractResult') => 'AUTO'
     }
 );
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_test/test_transform.pl	Tue Aug 28 17:29:42 2012 +0400
@@ -0,0 +1,131 @@
+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 addresses => PROP_ALL | PROP_LIST;
+}
+
+package Address;
+use IMPL::lang qw(:declare);
+use IMPL::declare {
+	base => [
+		'IMPL::Object'           => undef,
+		'IMPL::Object::Autofill' => '@_'
+	]
+};
+
+BEGIN {
+	public property country => PROP_ALL;
+	public property city    => PROP_ALL;
+}
+
+package main;
+
+my $data = {
+	name      => 'Peter',
+	age       => '99',
+	addresses => {
+		address => [
+			{
+				country => 'Airot',
+				city    => 'Torhiq',
+				street => 'avenu1'
+			},
+			{
+				country => 'Olkson',
+				city    => 'Zoxs',
+				street => 'av2'
+			}
+		]
+	}
+};
+
+use Carp qw(confess);
+
+sub Rule(&) {
+	my ($block) = @_;
+	
+	return sub {
+        local $_ = shift;
+        $block->();
+    }
+}
+
+sub Inspect($$) {
+	my ($path,$block) = @_;
+    my $data = $_;
+    
+    foreach my $name (@$path) {
+    	$data = ref $data ? $data->{$name} : undef;
+    	print "$name = $data\n";
+    }
+    
+    local $_ = $data;
+    $block->($data);
+}
+
+sub Required(@);
+
+sub Required(@) {
+	if(@_) {
+	   Inspect([@_],Rule { Required });
+	} else {
+	   confess "required" unless $_;
+	}
+}
+
+sub Regexp($) {
+	my $rx = shift;
+	die "Regular expression doesn't match" unless m/$rx/; 
+}
+
+my $validate = Rule {
+	Required('name');
+	
+	Inspect ['age'] => Rule {
+		Regexp(qr/^\d+$/);
+		die "invalid person age" unless $_ > 0 && $_ < 200;
+	};
+	
+	Inspect ['addresses', 'address'] => Rule {
+		Required;
+		foreach(@{$_}) {
+            Required('street');
+		}
+	}
+};
+
+$validate->($data);
+
+my ($person) =
+  map {
+	Person->new(
+		name      => $_->{name},
+		age       => $_->{age},
+		addresses => [
+			map {
+				Address->new(
+					country => $_->{country},
+					city    => $_->{city}
+				  )
+			  } as_list( $_->{addresses}{address} )
+		]
+	  )
+  } $data;
+  
+use Data::Dumper;
+print Dumper($person);
+
+sub as_list {
+	return @{ $_[0] } if ref $_[0] eq 'ARRAY';
+	return @_;
+}