GSP
GSP - это генератор текста по шаблонам gsp
.
Генератор по шаблонам gsp
принципиально устроен так же, как и другие общеупотребительные
генераторы: берется текст на некотором входном языке и на его основе генерируется текст.
Входной язык поддерживает подстановку значений переменных, операторы ветвления, циклы и
т.д.
В качестве входного языка шаблонов используется формат GSP (Groovy Server Pages) из
проекта http://grails.org для обеспечения нормального редактирования в IDE,
которые поддерживают gsp
.
Синтаксис шаблонов gsp
Текст шаблона представляет собой тело метода onRender()
класса jandcode.core.web.gsp.BaseGsp
на языке groovy
.
Парзер gsp
преобразует текст шаблона в текст на groovy
по следующим правилам:
ANYTEXT
преобразуется вout('ANYTEXT')
(вывести фрагмент текста)${ANYTEXT}
преобразуется вout(ANYTEXT)
(вывести значение выражения)<%ANYTEXT%>
преобразуется вANYTEXT
(вставить фрагмент groovy-кода)<%=ANYTEXT%>
преобразуется вout(ANYTEXT)
(вывести значение выражения)<%--ANYTEXT--%>
преобразуется в/*ANYTEXT*/
(коментарий)%{--ANYTEXT--}%
преобразуется в/*ANYTEXT*/
(коментарий)<xx:yy/>
преобразуется вoutTag('xx/yy')
(вызов функции outTag)<xx:yy atr="value" atr2="value2"/>
преобразуется вoutTag('xx/yy',atr:value,atr2:value)
(вызов функции outTag)<xx:yy atr="value" atr2="value2"> body </xx:yy>
преобразуется вoutTag('xx/yy',atr:value,atr2:value) { body }
(вызов функции outTag с closure в качестве тела)
Каждая строка шаблона преобразуется в строку метода, что позволяет однозначно
идентифицировать место возникновения ошибки в шаблоне (в отличии от оригинального gsp
,
где нет соответствия между сгенерированным классом и оригинальным шаблоном).
К примеру, из такого шаблона:
<%@ page import="jandcode.commons.datetime.*; jandcode.commons.*; jandcode.commons.groovy.*" %>
<%
def d = XDateTime.create("2011-11-23")
def func1 = { p1 ->
out("P1=${p1}")
}
%>
<div>
Hello! Date: ${d}
</div>
<% for (i in 1..5) { %>
item: ${i}
<% } %>
<jc:tag1 arg1="1" arg2="${d}">
body1
<% func1("one") %>
</jc:tag1>
End
генерируется вот такой класс:
import jandcode.commons.datetime.*; import jandcode.commons.*; import jandcode.commons.groovy.*;
public class G__gsp_syntax1__app1___inc__90b3e070f3b3653b5d4cfc9b2c61e144 extends jandcode.core.web.gsp.BaseGsp {
protected void onRender() {
def d = XDateTime.create("2011-11-23")
def func1 = { p1 ->
out("P1=${p1}")
}
;;out("<div>\n");
;;out(" Hello! Date: ");;;out(d);;;out("\n");
;;out("</div>\n");
;;out("\n");
for (i in 1..5) {
;;out("item: ");;;out(i);;;out("\n");
}
;;out("\n");
outTag('jc/tag1' ,arg1:"1" ,arg2:d) {
;;out(" body1\n");
func1("one")
}
;;out("\n");
;;out("End\n");
}
}
обработка которого приведет к такому результату:
<div>
Hello! Date: 2011-11-23
</div>
item: 1
item: 2
item: 3
item: 4
item: 5
tag1 out with: arg1=1, arg2=2011-11-23
End
В этом примере jc/tag1
- это gsp
с текстом:
tag1 out with: arg1=${args['arg1']}, arg2=${args['arg2']}
Локальные переменные в шаблоне
Т.к. текст шаблона преобразуется в текст метода groovy
, то определение переменной внутри
фрагментов кода, определяет локальную переменную метода:
<%
// локальные переменные метода шаблона
String s = ""
def a = []
%>
Для определения функций внутри шаблона изпользуются groovy closure
(т.к. метод внутри
метода объявить нельзя):
<%
def pw2 = {a->
return a*a
}
%>
5^2 = ${pw2(5)}
Для определения рекурсивной функции внутри шаблона, необходимо сначала определить
переменную для функции, а потом присваивать ей closure
(особенность groovy
):
<%
def recursiveFunc
recursiveFunc = {a->
recursiveFunc(a+1)
}
%>