Kwartz-Ruby Users' Guide
2 Features Detail
2-1 RuleSet and Properties
Format of presentation logic in Kwartz is similar to CSS (Cascading Style Sheet).
- Presentation logic file is a set of Ruleset.
- Ruleset is a pair of selector and declarations.
- Declaration is a pair of property name and value.
The following rules are available in presesntation logic file. These are similar to CSS. If you are familiar with CSS, you'll be so with Kwartz.
- stag: expr;
- Replace start-tag by expression value.
- etag: expr;
- Replace end-tag by expression value.
- elem: expr;
- Replace elemnt by expression value.
- cont: expr;
- Replace content of element by expressin value.
- value: expr;
-
Equivarent to
cont: expr.
- attrs: 'attrname' expr;
-
Replace attribute value by expression.
The following is an example to specify some attributes.
#foo { attrs: 'href' item[:url], 'id' item[:id], 'class' classname; }
- append: expr;
-
Append expression value to tail of tag.
This is used especially to add 'checked="checked"', 'selected="selected"'
into the form control tag.
#checkbox1 { append: member[:age] > 18 ? ' checked="checked"' : ''; } #select_options { append: option[:value] == current_val ? ' selected="selected"' : ''; }
- remove: 'attr1', 'attr2', 'attr3';
- Remove the attributes from the element.
- logic: { ... }
- Logic of the element.
'stag:' and 'elem:' are useful especially for Ruby on Rails. The following is an examle to use Kwartz in Ruby on Rails.
<form id="form">
Name: <input type="text" id="member_name"><br>
Birthday: <select id="member_birth">
<option> - </option>
</select><br>
<input type="submit" id="submit">
</form>
#form {
stag: start_form_tag :action=>'new';
}
#member_name {
elem: text_field 'member', 'name';
}
#member_birth {
elem: date_select 'member', 'birth';
}
#submit {
elem: submit_to 'Submit';
}
$ kwartz -p form1.plogic form1.html <%= start_form_tag :action=>'new' %> Name: <%= text_field 'member', 'name' %><br> Birthday: <%= date_select 'member', 'birth' %><br> <%= submit_to 'Submit' %> </form>
2-2 Directives
Presentation logic may be embedded into presentation data in Kwartz. You can choose to separate or not to sepearate presentation logic from presentation data.
The reason to provide both solutions (separate or not) is choosability. Some preferes to separate presentation logic from presentaion data, and others may prefere to mix them. Both approaches have own advantages and disadvantages. Thus it is the user who determine which solution to adopt. Kwartz provides both approaches and you can select which to use. Kwartz doesn't enforce you to adopt a solution.
To embed presentation logic into presentation data, use directives. Directive is a command to embed presentation logic into presentation data. In Kwartz, 'kw:d' attributes(*4) are used to describe directives.
The following is an example to use directives.
- Directive
kw:d="for var in list"means to iterate the element. - Directive
kw:d="value: expression"means to print value of expression as content of the element. - Directive
kw:d="dummy:"means that the element is a dummy and is not printed out.
<table>
<tr kw:d="for member in @members">
<td kw:d="value: member.name">foo</td>
<td>
<a href="mailto:<%= member.email %>"
kw:d="value: member.email">foo@mai.com</a>
</td>
</tr>
<tr kw:d="dummy:">
<td>bar</td>
<td><a href="mailto:bar@mail.org">bar@mail.org</a></td>
</tr>
<tr kw:d="dummy:">
<td>baz</td>
<td><a href="mailto:baz@mail.net">baz@mail.net</a></td>
</tr>
</table>
$ kwartz directive1.html > directive1.rhtml
<table>
<% for member in @members do %>
<tr>
<td><%= member.name %></td>
<td>
<a href="mailto:<%= member.email %>"><%= member.email %></a>
</td>
</tr>
<% end %>
</table>
If the first character of target attribute is a space, Kwartz recognize it as non-directive(*5).
<span kw:d="value: expr1">foo</span> <span kw:d=" value: expr2">bar</span>
$ kwartz directive2.html <span><%= expr1 %></span> <span kw:d="value: expr2">bar</span>
Directives are different in each target language. For example, foreach loop is 'for item in list' in eRuby, 'foreach($list as $item)' in PHP, 'forEach(item in list)' in JSTL. See reference manual for details about directives.
2-3 Embed Expression in Presentation Data
It is able to embed expressions in presentation data file in each language format. For example, you can use '<%= ... %>' with eRuby, '#{...}' with Ruby, '<?php echo ... ?>' with PHP, and so on.
(Experimental) '@{...}@' and '@!{...}@' are also available as embedded expression notation in all languages. The former escapes expression and the latter does not escape expression.
<p class="<%= klass %>">Hello <%=h user %></p>
<p class="@!{klass}@">Hello @{user}@</p>
$ kwartz -l eruby embed1_eruby.html <p class="<%= klass %>">Hello <%=h user %></p> <p class="<%= klass %>">Hello <%=h user %></p>
<p class="#{klass}">Hello #{ERB::Util.h user}</p>
<p class="@!{klass}@">Hello @{user}@</p>
$ kwartz -l eruby embed1_ruby.html
_buf = ""; _buf << "<p class=\"#{klass}\">Hello #{ERB::Util.h user}</p>
<p class=\""; _buf << (klass).to_s; _buf << "\">Hello "; _buf << ERB::Util.h(user); _buf << "</p>\n";
; _buf
<p class="<?php echo $klass; ?>">Hello <?php echo htmlspecialchars($user); ?></p>
<p class="@!{$klass}@">Hello @{$user}@</p>
$ kwartz -l eruby embed1_php.html <p class="<?php echo $klass; ?>">Hello <?php echo htmlspecialchars($user); ?></p> <p class="<?php echo $klass; ?>">Hello <?php echo htmlspecialchars($user); ?></p>
2-4 Escape
Kwartz supports Automatic-escape and Partial-escape/unescape.
- If command-line option '
-e' is specified, values of 'value: expr' are escaped. (Automatic-escape) - '
Value: expr' always escapes value even when '-e' is not specified. (Partial-escape) - '
VALUE: expr' always doesn't escapes value even when '-e' is specified. (Partial-unescape)
<tr> <td id="mark:val1">foo</td> <td id="mark:val2">bar</td> <td id="mark:val3">baz</td> </tr>
#val1 {
value: expr;
}
#val2 {
Value: expr;
}
#val3 {
VALUE: expr;
}
-e' option.$ kwartz -p escape1.plogic escape1.html <tr> <td><%= expr %></td> <td><%=h expr %></td> <td><%= expr %></td> </tr>
-e' option.$ kwartz -e -p escape1.plogic escape1.html <tr> <td><%=h expr %></td> <td><%=h expr %></td> <td><%= expr %></td> </tr>
In the same way, 'Stag:', 'Etag:', 'Elem:',
'Cont:', 'Attrs:', and 'Append:' properties are
always escaped, 'STAG:', 'ETAG:', 'ELEM:',
'CONT:', 'ATTRS:', and 'APPEND:' properties are
never escaped.
Escape function or method is different for each tareget language. 'h()' is used in eRuby and 'htmlspecialchars()' in PHP. JSTL prints escaped value in default.
Directives kw:d="Value: expr", kw:d="Attr: 'name' expr", and kw:d="Append: expr" always escape expression value even when the command-line option '-e' is not specified.
Directives kw:d="VALUE: expr", kw:d="ATTR: 'name' expr", and kw:d="APPEND: expr" doesn't escape expression value even when the command-line option '-e' is specified.
Configuration option PROPERTY_ESCAPE in 'kwartz/config.rb' determines whether values are escaped or not in default. If this is true then Kwartz will escape values in default.
2-5 Multi-language
Kwartz now supports the following programming language.
- Ruby, eRuby(ERB, Erubis)
- PHP
- JSP (JSTL 1.1 and 1.2)
- ePerl [experimental]
Presentation logics must be described in each target language. It means that if you have wrote presentation logics in Ruby, they were not reusable for PHP project (but you can get full-power of Ruby in presentation logic).
The followings are examples of Ruby, eRuby, PHP, JSP, and ePerl.
<html>
<body>
<table>
<tr bgcolor="#CCCCFF" id="mark:row">
<td id="mark:name">Foo</td>
<td id="mark:mail">foo@mail.com</td>
</tr>
<tr bgcolor="#FFCCCC" id="dummy:row1">
<td>Bar</td>
<td>bar@mail.net</td>
</tr>
<tr bgcolor="#CCCCFF" id="dummy:row2">
<td>Baz</td>
<td>baz@mail.org</td>
</tr>
</table>
</body>
</html>
#row {
attrs: "bgcolor" color;
logic: {
@list.each_with_index do |user, i|
color = i % 2 == 1 ? '#FFCCCC' : '#CCCCFF'
_elem
end
}
}
#name {
Value: user[:name];
}
#mail {
value: user[:mail];
}
#row {
attrs: "bgcolor" $color;
logic: {
$i = 0;
foreach ($list as $user) {
$color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF';
_elem();
}
}
}
#name {
Value: $user['name'];
}
#mail {
value: $user['mail'];
}
#row {
attrs: "bgcolor" color;
logic: {
<c:forEach var="user" items="${list}" varStatus="loop">
<c:set var="color" value="${loop.index % 2 == 0 ? '#FFCCCC' : '#CCCCFF'}"/>
_elem
</c:forEach>
}
}
#name {
Value: user.name;
}
#mail {
value: user.mail;
}
#row {
attrs: "bgcolor" $color;
logic: {
$i = 0;
foreach ($user in @list) {
$color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF';
_elem();
}
}
}
#name {
Value: $user{'name'};
}
#mail {
value: $user{'mail'};
}
$ kwartz -l eruby -p table1.ruby.plogic table1.html > table1.eruby $ kwartz -l ruby -p table1.ruby.plogic table1.html > table1.rb $ kwartz -l pierubis -p table1.ruby.plogic table1.html > table1.pierubis $ kwartz -l php -p table1.php.plogic table1.html > table1.php $ kwartz -l jstl -p table1.jstl.plogic table1.html > table1.jsp $ kwartz -l eperl -p table1.eperl.plogic table1.html > table1.eperl
<html>
<body>
<table>
<% @list.each_with_index do |user, i| %>
<% color = i % 2 == 1 ? '#FFCCCC' : '#CCCCFF' %>
<tr bgcolor="<%= color %>">
<td><%=h user[:name] %></td>
<td><%= user[:mail] %></td>
</tr>
<% end %>
</table>
</body>
</html>
_buf = ""; _buf << "<html>
<body>
<table>\n";
@list.each_with_index do |user, i|
color = i % 2 == 1 ? '#FFCCCC' : '#CCCCFF'
_buf << " <tr bgcolor=\""; _buf << (color).to_s; _buf << "\">
<td>"; _buf << ERB::Util.h(user[:name]); _buf << "</td>
<td>"; _buf << (user[:mail]).to_s; _buf << "</td>
</tr>\n";
end
_buf << " </table>
</body>
</html>\n";
; _buf
<html>
<body>
<table>
<% @list.each_with_index do |user, i| -%>
<% color = i % 2 == 1 ? '#FFCCCC' : '#CCCCFF' -%>
<tr bgcolor="<%= color %>">
<td><%=h user[:name] %></td>
<td><%= user[:mail] %></td>
</tr>
<% end -%>
</table>
</body>
</html>
<html>
<body>
<table>
<?rb @list.each_with_index do |user, i| ?>
<?rb color = i % 2 == 1 ? '#FFCCCC' : '#CCCCFF' ?>
<tr bgcolor="@!{color}@">
<td>@{user[:name]}@</td>
<td>@!{user[:mail]}@</td>
</tr>
<?rb end ?>
</table>
</body>
</html>
<html>
<body>
<table>
<?php $i = 0; ?>
<?php foreach ($list as $user) { ?>
<?php $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF'; ?>
<tr bgcolor="<?php echo $color; ?>">
<td><?php echo htmlspecialchars($user['name']); ?></td>
<td><?php echo $user['mail']; ?></td>
</tr>
<?php } ?>
</table>
</body>
</html>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<body>
<table>
<c:forEach var="user" items="${list}" varStatus="loop">
<c:set var="color" value="${loop.index % 2 == 0 ? '#FFCCCC' : '#CCCCFF'}"/>
<tr bgcolor="${color}">
<td>${user.name}</td>
<td>${user.mail}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
<html>
<body>
<table>
<? $i = 0; !>
<? foreach ($user in @list) { !>
<? $color = ++$i % 2 == 0 ? '#FFCCCC' : '#CCCCFF'; !>
<tr bgcolor="<?= $color !>">
<td><?= encode_entities($user{'name'}) !></td>
<td><?= $user{'mail'} !></td>
</tr>
<? } !>
</table>
</body>
</html>
2-6 Span Tag Deletion
Kwartz regards span tags which contain only directives as dummy tags and delete them automatically when command-line option '--delspan' is specified.
<h1><span id="mark:title">title</span></h1> Hello <span kw:d="value: user">World</span>!
#title {
value: title;
}
$ kwartz -p delspan1.plogic --delspan delspan1.html <h1><%= title %></h1> Hello <%= user %>!
The span tags are not removed when they have other attributes.
Hello <span kw:d="value: user" style="color:black">World</span>!
$ kwartz --delspan delspan2.html Hello <span style="color:black"><%= user %></span>!
2-7 Import Presentation Logic File
'@imort "filename.plogic"' imports filename.plogic.
This is useful to share common presentation logic in many files.
#link_to_new {
elem: link_to 'New', :action=>'new';
}
#link_to_show {
elem: link_to 'Show', :action=>'show', :id=>@member;
}
#link_to_edit {
elem: link_to 'Edit', :action=>'edit', :id=>@member;
}
#link_to_list {
elem: link_to 'List', :action=>'list';
}
#link_to_destroy {
elem: link_to('Destroy', {:action=>'destroy', :id=>@member}, :confirm=>'Are you sure?');
}
<p> Name: <span id="mark:name">foo</span> <br> Email: <span id="mark:email">foo@mail.com</span> <br> </p> <a href="#" id="link_to_edit">Edit</a> | <a href="#" id="link_to_new">New</a> | <a href="#" id="link_to_list">List</a>
@import 'link_to.plogic';
#name {
Value: @member.name;
}
#email {
Value: @member.email;
}
$ kwartz -p show.plogic show.html <p> Name: <span><%=h @member.name %></span> <br> Email: <span><%=h @member.email %></span> <br> </p> <%= link_to 'Edit', :action=>'edit', :id=>@member %> | <%= link_to 'New', :action=>'new' %> | <%= link_to 'List', :action=>'list' %>
2-8 Import Elements in Other Files
Command-line option '-i filename,...' imports element definitions form other files.
<form> <div id="mark:form_content"> Name: <input type="text"><br> Password: <input type="password"><br> </div> <input type="submit"> </form>
<form action="/new"> <div id="mark:placeholder"></div> <input type="submit" value="Create"> </form>
/* use element which is defined other file */
#placeholder {
logic: {
_content(form_content)
}
}
$ kwartz -i form.html -p new.plogic new.html <form action="/new"> Name: <input type="text"><br> Password: <input type="password"><br> <input type="submit" value="Create"> </form>
2-9 Extract Element
Command option '-X name' extracts element marked as name and command option '-x name' extracts content of element.
<html> <body> <div id="mark:content"> <h1>Show</h1> <p>Name: <span id="mark:name">foo</span></p> <p>Email: <span id="mark:email">foo@mail.com</span></p> </div> </body> </html>
#name {
value: user.name;
}
#email {
value: user.email;
}
$ kwartz -X content -p show.plogic show.html <div> <h1>Show</h1> <p>Name: <span><%= user.name %></span></p> <p>Email: <span><%= user.email %></span></p> </div>
$ kwartz -x content -p show.plogic show.html <h1>Show</h1> <p>Name: <span><%= user.name %></span></p> <p>Email: <span><%= user.email %></span></p>
2-10 Print Statement
Print statement is available in 'logic:' property.
<ul> <li id="items">foo</li> </ul>
#items {
logic: {
for item in list
_stag
print item
_etag
end
}
}
$ kwartz -l eruby -p print-stmt.eruby.plogic print-stmt.html <ul> <% for item in list %> <li id="items"><%= item %></li> <% end %> </ul>
#items {
logic: {
foreach ($list as $item) {
_stag();
print($item);
_etag();
}
}
}
$ kwartz -l php -p print-stmt.php.plogic print-stmt.html
<ul>
<?php foreach ($list as $item) { ?>
<li id="items"><?php echo $item; ?></li>
<?php } ?>
</ul>
#items {
logic: {
<c:forEach var="item" items="${list}">
_stag
print item
_etag
</c:forEach>
}
}
$ kwartz -l jstl -p print-stmt.jstl.plogic print-stmt.html
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<ul>
<c:forEach var="item" items="${list}">
<li id="items">${item}</li>
</c:forEach>
</ul>
$ kwartz -l jstl -p print-stmt.jstl.plogic --jstl=1.1 print-stmt.html
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<ul>
<c:forEach var="item" items="${list}">
<li id="items"><c:out value="${item}"/></li>
</c:forEach>
</ul>
It is recommended to use 'elem:', 'stag:', 'etag:', 'cont:', or 'value:' instead of print statement because they can escape or unescape exression value.
2-11 Add Code at Beginning/End of Document
'#DOCUMENT' is a special selector which represents the document. In '#DOCUMENT', properties 'begin:' and 'end:' are available to add codes at beginning/end of document.
<html> <body>hello</body> </html>
#DOCUMENT {
begin: {
title = cgi['title']
user = cgi['user']
}
end: {
print "<!--end-->\n"
}
}
$ kwartz -p document-test.plogic document-test.html <% title = cgi['title'] %> <% user = cgi['user'] %> <html> <body>hello</body> </html> <%= "<!--end-->\n" %>
2-12 Compile Template into a Function of Ruby or PHP
Using the command-line option '-a defun', you can compile templates into a function of Ruby or PHP.
Hello <span id="user">user</span> ! <ul id="mark:list"> <li id="mark:item">xxx</li> </ul>
#user {
elem: @user;
}
#list {
logic: {
_stag
for item in @list
_cont
end
_etag
}
}
#item {
value: item;
}
$ kwartz -l eruby -a defun -p defun1.plogic defun1.html | tee defun1.rb
module View
(@@proc_table ||= {})['defun1'] = proc do
_erbout = ''; _erbout.concat "Hello "; _erbout.concat(( @user ).to_s); _erbout.concat " !\n"
_erbout.concat "<ul>\n"
for item in @list
_erbout.concat " <li>"; _erbout.concat(( item ).to_s); _erbout.concat "</li>\n"
end
_erbout.concat "</ul>\n"
_erbout
end#proc
module_function
def expand_defun1(context={})
if context.is_a?(Hash)
hash = context
context = Object.new
hash.each { |key, val| context.instance_variable_set("@#{key}", val) }
end
proc_obj = @@proc_table['defun1']
context.instance_eval(&proc_obj)
end
end
The following command-line properties are available with '-a defun'.
- --module=name
- Module name. If false or null then no module is used. Default is 'View'.
- --verb=name
- Verb. Default is 'expand'.
- --method=name
- Method name. Default is "#{verb}_#{basename}".
The following languages are available with '-a defun'.
- -l eruby
- -l ruby
- -l erubis
- -l pierubis
- -l php