Upload
reegan
View
29
Download
2
Embed Size (px)
DESCRIPTION
Code Generation. SuperSet Code Generation. Template Definition. A pattern or gauge, such as a thin metal plate with a cut pattern, used as a guide in making something accurately, as in woodworking or the carving of architectural profiles (the free Online Dictionary). Text Template. - PowerPoint PPT Presentation
Citation preview
Code Generation
SuperSet Code Generation
A pattern or gauge, such as a thin metal plate with a cut pattern, used as a guide in making something accurately, as in woodworking or the carving of architectural profiles (the free Online Dictionary).
Template Definition
A textual pattern used as a guide the generation of text.
Text Template
A textual pattern used as a guide the generation of text.
Text Template
<#foreach(System.Data.DataRow row in schema.Rows){ #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { }<#} #>
public class A1 { } public class A2 { } public class A3 { }
Template EvolutionLevel 0: no template mechanism
A function or group of functions generatecode through a set of print statements basedon configurative information.
- Hard to change both text structure and meta-data
Output.print_line(~~~~~~~~~~~~~~~~~~~~);Output.print_line(~~~~~~~~~~~~~~~~~~~~);Output.print_line(~~~~~~~~~~~~~~~~~~~~);If (~~~~) then { Output.print_line(~~~~~~~~~~~~~~~~~~~~); Output.print_line(~~~~~~~~~~~~~~~~~~~~);}
Template EvolutionLevel 1: accidental templates
A function or group of functions generatecode by applying substitution to stringtemplate fragmented throughout theprogram
- Still hard to change the model or the template.
- Inferring the target code’s structure requires understanding of the program’s logic.
String s = “~~~~~~~~%name%~~~~~~~~~”Output.print_line(s1.Replace(“%name%”,name);
Template EvolutionLevel 2: Place Holder Templates
The textual annotative code is organized astemplates in files external to the generationengine that substitute variables for contentin a generator specific way
+ Template can be changed without changing the generator
- Proprietary template syntax - Proprietary substitution mechanism- Model extensions may require generator changes.
<html>!!Header_Content!!!!Body!!</html>
Template EvolutionLevel 3: Scripted Templates
code generators support templates thatinclude scripting for accessing andsubstituting template variables.
class <%=xo.GetName()%> {<% foreach x in xo.getList()%> <%=x.GetDataType()%> v<%=x.GetName()%>; <%=x.GetDataType()%> get<%=x.GetName()%>{ return v<%=x.GetName()%>; } void set<%=x.GetName(<%=x.GetDataType()%> p<%=x.GetName()%>) { v<%=x.GetName()%>=p<%=x.GetName()%>; } <%}%>
Scripted TemplatesBenefits:
• Both model and template can be changed without affecting the generator.
• Standardized substitution mechanism.
Scripted TemplatesHowever, the template and the model access code are stillintermixed:
• Miscoding pitfalls due to the superposition of the codes .
• Incomprehensible and incoherent code.
• Cumbersome development, test and debug process.
• Restricted flexibility of the generated text’s structure.
• Limited textual expressive power.
• Unnecessary dependency on model access code changes.
• Replicated code that burdens the development process.
Scripted TemplatesMiscoding pitfalls due to the superposition of the code.
using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); … SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } } } }
Scripted Templates
using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); … SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } } does not belong to the code but rather to the model access code. } }
Miscoding pitfalls due to the superposition of the code.
Scripted Templates
using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); … SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } }
Miscoding pitfalls due to the superposition of the code.
Scripted TemplatesIncomprehensible and incoherent code.
<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #> <#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}
C# code that belongs to the mode access code
Sql code in the data model code
Textual code
Formatting code
Scripted TemplatesCumbersome development and debug process.
<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #> <#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}
C# debugging goes here
Sql query debugging here
Text issues addressed here
Wrong format in here
Scripted TemplatesRestricted flexibility of the generated text’s structure.
Function <%=X%> (
<%foreach …prm….%>
<%=prm.datatype%> <%=prm.name%>
<% if ….. %> , <%endif%>
<%endif%>
)
{
…
}
Function Fnc1 (string prm1 , string prm2 , integer prm3 )
{
..
}
Function Fnc1 (
string prm1 ,
string prm2 ,
int prm3
)
{
..
}
Scripted TemplatesLimited textual expressive power.
Create procedure getT1RowValues(
@Key1 int in, @Key2 varhcar in,
@val1 int out, @val2 varchar(20) out = ‘world’, @val3 varchar(20) out )
as
Select @val1=val1, @val2=val2, @val3=val3
From T1
Where key1=@key1 and key2=@key2
Scripted TemplatesUnnecessary dependency on model access code changes
Function <%=X%> (
<%foreach …prm…in (select …from A) .%>
<%=prm.datatype%> <%=prm.name%>
<% if ….. %> , <%endif%>
<%endif%>
)
{
…
}
Function <%=X%> (
<%foreach …prm…in (select … from b) .%>
<%=prm.datatype%> <%=prm.name%>
<% if ….. %> , <%endif%>
<%endif%>
)
{
…
}
Scripted TemplatesReplicated code that burdens the development process.
private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(),dc.ColumnName[0].ToString().ToLower()) #>;public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; }}
- Replicated code in the same template as well as code replication that is caused by copying data access code into several templates.
- Designing, testing, debugging and correcting anything but very trivial model access code becomes a prohibitively costly effort.
Separation of ConcernsAnnotative information and model accesscode are separated aspects of codegeneration. Mixing them makes it difficult tomaintain both.
Separation of Concerns• Makes it possible to view a description as a set of
coherent and focused concerns.
• Different concerns may require different approaches.
• Different concerns may require different skill sets.
Separation of Concerns• Makes it possible to view a description as a set of
coherent and focused concerns.
• Different concerns may require different approaches.
• Different concerns may require different skill sets.
<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}
Template Separation of Concerns
<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}
Template Separation of Concerns
Template Separation of Concerns<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}
=>Model access code block
=>Model access code block
=>Model access code block
Template Separation of Concerns<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>
using System;namespace MyProject.Entities{
<# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #>
public class <#= row["TABLE_NAME"].ToString().Trim('s') #> {
<# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #>
private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return xxx ;} _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set ={ value = xxx ; } _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> }
<# } #>
}
Encapsulationusing System;namespace MyProject.Entities{ public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } } }
<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>
The expression is replaced with $ColName$.
Encapsulationusing System;namespace MyProject.Entities{ public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { private <#= dc.DataType.Name #> _$ColName$; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _$ColName$; } set { _$ColName$ = value; } } } }
<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>
$ColName$ encapsulates the substitution expression that belongs to the transformation layer rather than the template.
Encapsulationusing System;namespace MyProject.Entities{ public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { private <#= dc.DataType.Name #> _$ColName$; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _$ColName$; } set { _$ColName$ = value; } } } }
Replace $TableName$ for <#= row["TABLE_NAME"].ToString().Trim('s') #> $DataType$ for <#= dc.DataType.Name #> $CSharpAttributeName$ for <#= dc.ColumnName #>
Abstract Templateusing System;namespace MyProject.Entities{ public class $TableName$ {[ private $DataType$ _$ColName$; ^\n][ public $DataType$ $CSharpAttributeName$ { get { return _$ColName$; } set { _$ColName$ = value; } } ^\n] } }
Abstract Template
• Structural Clarity• Abstraction of Text• Readability• Model Access Code Reuse• Transformational Error Reduction • Textual Expressive Power• Traceability• Analyzability
Abstract Template<#@ template language="C#" debug="True" hostspecific="True" #><#@ output extension=".cs" #><#@ assembly name="System.Data" #><#@ assembly name="System.xml" #><#@ import namespace="System.Collections.Generic" #><#@ import namespace="System.Data.SqlClient" #><#@ import namespace="System.Data" #>using System;namespace MyProject.Entities{ <# string connectionString = "Server=localhost;Database=GridViewGuy;Trusted_Connection=true"; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); System.Data.DataTable schema = conn.GetSchema("TABLES"); string selectQuery = "select * from @tableName"; SqlCommand command = new SqlCommand(selectQuery,conn); SqlDataAdapter ad = new SqlDataAdapter(command); System.Data.DataSet ds = new DataSet(); foreach(System.Data.DataRow row in schema.Rows) { #> public class <#= row["TABLE_NAME"].ToString().Trim('s') #> { <# command.CommandText = selectQuery.Replace("@tableName",row["TABLE_NAME"].ToString()); ad.FillSchema(ds, SchemaType.Mapped, row["TABLE_NAME"].ToString()); foreach (DataColumn dc in ds.Tables[0].Columns) { #> private <#= dc.DataType.Name #> _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; public <#= dc.DataType.Name #> <#= dc.ColumnName #> { get { return _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #>; } set { _<#= dc.ColumnName.Replace(dc.ColumnName[0].ToString(), dc.ColumnName[0].ToString().ToLower()) #> = value; } } <# } #> } <# } #>}
using System;namespace MyProject.Entities{ public class $TableName$ { private $DataType$ _$ColName$ public $DataType$ $CSharpAttributeName$ { get { return _$ColName$; } set { _$ColName$ = value; } } } }
model content provided as a relational set.
Abstract TemplateLevel 4: Abstract Templates
abstract, coherent, template centric representation of text.
• Annotated Models: models with annotative information. • Text centric: do not include model access code.• Abstract: represents a meta-description of the text.
Template Structure
Hidden Assumptions: • DataType, ColName and CSharpAttributeName are in
the context of TableName.• The annotative text is at a line boundary • There are no separators such as “and” or “,”.
using System;namespace MyProject.Entities{ public class $TableName$ { private $DataType$ _$ColName$ public $DataType$ $CSharpAttributeName$ { get { return _$ColName$; } set { _$ColName$ = value; } } } }
Template Structure
The partition of the text to blocks clarifies the containment relationship between the attribute sets
using System;namespace MyProject.Entities{[ public class $TableName$ {[ private $DataType$ _$ColName$ public $DataType$ $CSharpAttributeName$ { get { return _$ColName$; } set { _$ColName$ = value; } } ] } ] }
Attributes and Blocks
• A block is instantiated for every unique set of its attributes values.
• An attribute is required by default. • A block is a multi-segment, multi-instance
attribute of its container block. • A block is optional by default.
using System;namespace MyProject.Entities{[ public class $TableName$ {[ private $DataType$ _$ColName$ public $DataType$ $CSharpAttributeName$] } ] }
Template Structure[ create table $TableName$ ([ $ColName$ $DataType$ ^,\n] ) ]
Instance separator
Template Structure[ create table $TableName$ ([ $ColName$ $DataType$ [ = $Default$ ] $*Comment$ ^,\n] ) ]
Instance separator
Optional variable
Optional block
Template Structure
[ select [ $AttName$ ^,] from $TableName$[ where ![ $KeyAttName$= @$KeyAttName$ ^ and ] ]]
Instance separatorRequired block
The block containing “where” requires at least one instance in its internal block in order to be generated.
Template as Textual ProjectorA template is a projector of a hierarchical model portion or modelon
[ create table $TableName$ ([ $ColName$ $DataType$ [ = $Default$ ] $*Comment$ ^,\n] ) ]
Template as Textual Projector
…{ColName,DataType,*Comment}
{TableName}
1 2 3
*{Default}
T(TableName,+C(ColName,DataType,*Comment,*D(Default))
A template is a projector of a hierarchical model portion or modelon
[ create table $TableName$ ([ $ColName$ $DataType$ [ = $Default$ ] $*Comment$ ^,\n] ) ]
Template as Textual Projector{TableName}
{ColName,DataType,*Comment}
*{Default}21 3
[ create table $TableName$ ([ $ColName$ $DataType$ [ = $Default$ ] $*Comment$ ^,\n] ) ]
TableName
ColNameDataTypeDefault
T1C1Varchar(8)
T1C2Int0
T1C3Int
T2C4Varchar(8)
T2C5int
TableName(+C(ColName,DataType,*Comment,*D(Default)))
create table T1(C1 varchar(8) , C2 int = 0 ,C3 int) create table T2(C4 varchar(8),C5 int)
Meta Model
Abstract Model
HierarchicalRelational
Annotated Meta Model = Template
Annotated Model Code
C3C1
T1
C2
{C1,varchar(8)} {C2,int} {C3,int}
0C4 C5
T2
{C4,varchar(8)} {C5,int}
root
Template Structural Aspect
An entity has zero or more attributes. [ xxx $att1$ yyy $att2$ zzz ]
Attributes can be required or optional. $reqAtt$ $*OptAtt$
An entity is a composite attribute.Hence, an it can be required or optionalAn entity is optional by default. ![ xxx $att1$ yyy $att2$ zzz ] – required
A (simple) attribute is required by default. $*OptAtt$ - optional
Template Structural Aspect
An instance of an entity is a unique set of attributes such that all required values are provided, recursively.
The order of the instances is according to the value of the attributes based on the attributes sort level or order of appearance.
Attributes are visible by default $~NonVisible$
Conditional Attribute
A conditional generation implies generating text conditionally or generating text for a subset of instances that meet the condition.
The classify statement derives a subset of attributes from base attributes:
Classify BaseTable isa Table where TableType=‘Base’;
Conditional Attribute
A conditional generation implies generating text conditionally or generating text for a subset of instances that meet the condition.
The classify statement derives a subset of attributes from base attributes:
Classify BaseTable isa Table where TableType=‘Base’;
[ create procedure Insert_$BaseTable$ …… ]
[ create procedure Insert_$Table$[ @$Column$ $DataType$ ^,\n][ insert $Table$ ( [ $Column$ ^,] ) values ( [ @$Column$ ^,] )][ insert LOG ( TableName, Content ) values ( “@$BaseTable$” , [ “$Column$=”+@$Column$ ^+] )]
Generated only for base tables
Distinct Partitioning ChoiceAttributes Di | i=1..n are classification of base attribute B such that an instance that have attribute Dx does not have attribute Dy unless x=y.
Classify LongEntityName isa EntityName where LengthFlag=‘Y’; Classify ShortEntityName isa EntityName where LengthFlag=‘N’;
Distinct Partitioning ChoiceAttributes Di | i=1..n are classification of base attribute B such that an instance that have attribute Dx does not have attribute Dy unless x=y.
Classify LongEntityName isa EntityName where LengthFlag=‘Y’; Classify ShortEntityName isa EntityName where LengthFlag=‘N’;
[$~EntityName$ ….. [ Entity $LongEntityName$ is a long entity and hence has this code ][ Entity $ShortEntityName$ is a short entity only ]]
Only one block is generated. Each instance is separated by the separator of the enclosing block.
Overlapping Partitioning ChoiceAttributes Di | i=1..n are classification of base attribute B such that an instance that have attribute Dx may have attribute Dy where x<>y.
Classify L1EntityName isa EntityName where L<1; Classify L2EntityName isa EntityName where L<2;
Overlapping Partitioning ChoiceAttributes Di | i=1..n are classification of base attribute B such that an instance that have attribute Dx may have attribute Dy where x<>y.
Classify L1EntityName isa EntityName where L<1; Classify L2EntityName isa EntityName where L<2;
[$~EntityName$ ….. [ Entity $L1EntityName$ has level 1 and up associated information ][ Entity $L2EntityName$ has level 2 and up content ]]
Only one block is generated. Each instance is separated by the separator of the enclosing block.
Aonix Text Template Example 1template genDragDropDecls(MClass)//--helper functions for drag&drop-----------------------------------------virtual bool canAcceptDragDrop(int, int, bool = false);virtual bool acceptDragDrop(int, int, bool = false);virtual bool unplugDragDrop();virtual bool aggregationCycleDragDrop(int, int);end templatetemplate genDragDropFunctions(MClass)//--test if drag&drop object could be accepted-----------------------------------------bool [MClass.name]::canAcceptDragDrop(int cid, int oid, bool clone){ [udOut("UDDDT","","Test drag and drop")] if( ! clone && myMetaClass()->isA(cid) && getKey() == oid) return false; // cannot drop on self if( ! clone && aggregationCycleDragDrop(cid, oid)) return false; // avoid cyclic aggregations [loop(Instances->MClass([MClass.id] " " getBaseClassList([MClass])) as Super)] [loop(Super->Role as FromRole->MAssociation->MAssociationEnd as ToRole->MClass as Partner Where [FromRole.id] != [ToRole.id])] [if([FromRole.aggregation] == "Aggregation")] if(DbMetaClass<[Partner.name]>::metaInstance()->isKindOf(cid)) return true; [else] [if([ToRole.aggregation] == "Aggregation")] [insert("include",[Partner.name])] { Ptr<[Partner.name]> owner = to_[ToRole.name].navigate(this).first(); if(owner.valid() && owner->canAcceptDragDrop(cid, oid)) return true; } [end if] [end if] [end loop] [end loop]return false;}... 80 more lines for three more function bodies
Aonix Text Template Example 1 template genDragDropDecls(MClass)//--helper functions for drag&drop-----------------------------------------virtual bool canAcceptDragDrop(int, int, bool = false);virtual bool acceptDragDrop(int, int, bool = false);virtual bool unplugDragDrop();virtual bool aggregationCycleDragDrop(int, int);end templatetemplate genDragDropFunctions(MClass)//--test if drag&drop object could be accepted-----------------------------------------bool [MClass.name]::canAcceptDragDrop(int cid, int oid, bool clone){ [udOut("UDDDT","","Test drag and drop")] if( ! clone && myMetaClass()->isA(cid) && getKey() == oid) return false; // cannot drop on self if( ! clone && aggregationCycleDragDrop(cid, oid)) return false; // avoid cyclic aggregations [loop(Instances->MClass([MClass.id] " " getBaseClassList([MClass])) as Super)] [loop(Super->Role as FromRole->MAssociation->MAssociationEnd as ToRole->MClass as Partner Where [FromRole.id] != [ToRole.id])] [if([FromRole.aggregation] == "Aggregation")] if(DbMetaClass<[Partner.name]>::metaInstance()->isKindOf(cid)) return true; [else] [if([ToRole.aggregation] == "Aggregation")] [insert("include",[Partner.name])] { Ptr<[Partner.name]> owner = to_[ToRole.name].navigate(this).first(); if(owner.valid() && owner->canAcceptDragDrop(cid, oid)) return true; } [end if] [end if] [end loop] [end loop]return false;}... 80 more lines for three more function bodies
Aonix Text Template Example 1[//--helper functions for drag&drop-----------------------------------------virtual bool canAcceptDragDrop(int, int, bool = false);virtual bool acceptDragDrop(int, int, bool = false);virtual bool unplugDragDrop();virtual bool aggregationCycleDragDrop(int, int); ][//--test if drag&drop object could be accepted-----------------------------------------bool [MClass.name]::canAcceptDragDrop(int cid, int oid, bool clone){ if( ! clone && myMetaClass()->isA(cid) && getKey() == oid) return false; // cannot drop on self if( ! clone && aggregationCycleDragDrop(cid, oid)) return false; // avoid cyclic aggregations[$~Partner.name$[ if(DbMetaClass<$Partner.name$>::metaInstance()->isKindOf(cid)) return true; ] [ { Ptr<$Partner.name$> owner = to_$ToRole.name$.navigate(this).first(); if(owner.valid() && owner->canAcceptDragDrop(cid, oid)) return true; } ] ^\n] return false;} ^\n]... 80 more lines for three more function bodies
Aonix Text Template Example 1
L3L4L4/L3
Characters14799050.611
Lines35216
• Total of 115 lines vs. 71 or 3380 characters vs. 2068.
• Clearer code
Aonix Text Template 2a template genAccessMethod(MClass) [loop(MClass->MAttribute)] [MAttribute.access] [getDataType([MAttribute.type])] get[string_capitalize(MAttribute.name)]() { return [MAttribute.name]; } [MAttribute.access] void set[string_capitalize(MAttribute.name)]([getDataType([MAttribute.type])] value) { [MAttribute.name] = value; } [end loop] end template
[$access$ $dataType$ get$capName$() { return $Name$; } $access$ void set$capName$($dataType$ value) { $name$ = value; } ^\n]
L3L4L4/L3
Characters3451240.35
Lines1480.57
Aonix Text Template Example 3template BufferAssoc (MAssociation) [loop (MAssociation->MAssociationEnd As FromRole->MClass As SenderCl )] [loop (MAssociation->MAssociationEnd As ToRole->MClass As ReceiverCl Where [ToRole.id] != [FromRole.id])] import com.aonix.hidoors.tools.ApexBuffer; public class [SenderCl.name][ReceiverCl.name]Buffer { [loop (MAssociation->AssociationClass As MessageCl)] // New buffer queue [loop(MAssociation->TaggedValue As TV Where [TV.tag] == "HIBufferSize")] private ApexBuffer queue = new ApexBuffer([TV.value]); [end loop] // send and receive methods public [MessageCl.name] receive() { return ([MessageCl.name]) queue.get(); } public void send ([MessageCl.name] element) { queue.put(element); } } [end loop end loop end loop] end template
Aonix Text Template Example 3import com.aonix.hidoors.tools.ApexBuffer; [public class $SenderCl.name$$ReceiverCl.name$Buffer { // New buffer queue [private ApexBuffer queue = new ApexBuffer($TV.value$); ^\n]// send and receive methods public $MessageCl.name$ receive() { return ($MessageCl.name$) queue.get(); } public void send ($MessageCl.name$ element) { queue.put(element); } }^\n]
L3L4L4/L3
Characters7393560.481
Lines24120.5
Aonix Text Template Example 3import com.aonix.hidoors.tools.ApexBuffer; [public class $SenderCl$$ReceiverCl$Buffer { // New buffer queue [private ApexBuffer queue = new ApexBuffer($TV$); ]// send and receive methods public $MessageCl$ receive() { return ($MessageCl$) queue.get(); } public void send ($MessageCl$ element) { queue.put(element); } }]
L3L4L4/L3
Characters7393200.433
Lines24120.5
Use aliased names and default line separator.
PHP, Smarty, Comparison
<?php foreach ($items as $item): ?><div><?php echo $item; ?></div><?php endforeach; ?>
{foreach from=$myArray item=foo} <div>{$foo}</div>{/foreach}
PHP
Smarty
[<div>$foo$</div> ^\n] Smarty