Purpose
rul4
is a script that can be used for rendering UL4 templates. Templates
have access to Oracle, MySQL, SQLite and Redis databases and can execute system
commands.
Options
rul4
supports the following options:
templates
One or more template files. A file named
-
will be treated as standard input. The first file in the list is the main template, i.e. the one that gets rendered. All templates will be available in the main template as thetemplates
dictionary. The keys are the base names of the files (i.e.foo.ul4
will betemplates.foo
; stdin will betemplates.stdin
).--oracle
(false
,no
,0
,true
,yes
or1
)Provide the object
oracle
to the template or not (see below)?--sqlite
(false
,no
,0
,true
,yes
or1
)Provide the object
sqlite
to the template or not (see below)?--mysql
(false
,no
,0
,true
,yes
or1
)Provide the object
mysql
to the template or not (see below)?--redis
(false
,no
,0
,true
,yes
or1
)Provide the object
redis
to the template or not (see below)?--system
(false
,no
,0
,true
,yes
or1
)Provide the object
system
to the template or not (see below)?--load
(false
,no
,0
,true
,yes
or1
)Provide the function
load
to the template or not (see below)?--compile
(false
,no
,0
,true
,yes
or1
)Provide the function
compile
to the template or not (see below)?-e
,--encoding
The encoding of the templates files (default
utf-8
)-w
,--whitespace
(keep
,strip
, orsmart
)Specifies how to handle whitespace in the template
-D
,--define
Defines an additional value that will be available inside the template.
-D
can be specified multiple times. The following formats are supported:var
Defines
var
as an empty string;var=value
Defines
var
as the stringvalue
;var:type
Defines
var
as an empty variable of the typetype
;var:type=value
Defines
var
as a variable of the typetype
with the valuevalue
.
type
can be any of the following:int
value
is an integer value.float
value
is a float value.bool
value
is a boolean value.0
,no
,false
,False
or the empty string will be recognized as false and1
,yes
,true
orTrue
will be recognized as true.str
value
is a string.oracle
value
will be a connection to an Oracle database, e.g.:-Ddb:oracle=user/pwd@database
sqlite
value
is a connection to an SQLite database.mysql
value
is a connection to a MySQL database.redis
value
will be a connection to an Redis database, e.g.:-Ddb:redis=192.168.123.1:6379/42
The port (i.e. the
6379
in the above value) is optional and defaults to 6379. The database number (i.e. the42
in the above value) is also optional and defaults to 0.
Template variables
Inside the template the following variables are available (if enabled via the matching options):
templates
A dictionary containing all the templates specified on the command line.
encoding
The output encoding.
system
An object with an
execute
method that executes system commands and returns their output, e.g. the template:<?print system.execute("whoami")?>
will output the user name.
oracle
An object with a
connect
method that returns a connection to an oracle database.mysql
An object with a
connect
method that return a MySQL connection for the MySQL connect strings passed in. A MySQL connect string is a string of the formuser/pwd@host/db
.sqlite
An object with a
connect
method that return a SQLite connection for the connect strings passed in. The connect string will be passed directly tosqlite3.connect
.redis
An object with a
connect
method that return a Redis connection for the connect strings passed in. The connectstring is of the formhostname:port/db
.port
anddb
are optional.load
load
is a function that reads a file from disk and returns the content. Its first parameter is the filename and its second parameter is the encoding of the file. The encoding parameter is optional and defaults to"utf-8"
:<?code data = load("/home/user/data.txt", "iso-8859-1")?>
compile
compile
is a function that compiles a string into an UL4 template. The signature is:compile(source, name=None, whitespace="keep", signature=None, startdelim="<?", enddelim="?>")
error
error
is a function that can be called to output an error message and abort template execution. The signature is:error(message, ast=None)
message
is the error message andast
can be an AST node from an UL4 template syntax tree to print an error message that originates from that node.
All variables defined via the -D
/--define
option will also
be available. (Note that you can't overwrite any of the predefined variables).
Database connections
All connection objects (except redis
) have a query
method that executes
the query passed in and returns an iterator over the resulting records. This
query
method requires at least one positional argument. Arguments alternate
between fragments of the SQL query and parameters that will be embedded in the
query. For example:
<?code db = oracle.connect("user/pwd@db")?> <?code name = "Bob"?> <?for p in db.query("select * from person where firstname=", name, " or lastname=", name)?> ...
The records returned from query
are dict-like objects mapping field names to
field values.
Connection objects also have an execute
method that supports the same
parameters as query
but doesn't return an iterable result. This can be used
to call functions or procedures.
Calling functions or procedures with out parameters can be done with variable
objects that can be created with the methods int
, number
,
str
, clob
and date
. The resulting value of the out
parameter is available from the value
attribute of the variable object.
The following example creates a function, calls it to get at the result and
drops it again:
<?code db = oracle.connect('user/pwd@database')?> <?code db.execute(''' create or replace function ul4test(p_arg integer) return integer as begin return 2*p_arg; end; ''')?> <?code vout = db.int()?> <?code db.execute('begin ', vout, ' := ul4test(42); end;')?> <?print vout.value?> <?code db.execute('drop function ul4test')?>
Redis connections have a get
and a put
method:
<?code db = redis.connect("192.168.123.42/1")?> <?code value = db.get("key")?> <?if isnone(value)?> <?code value = "foobar"?> <?code db.put("key", value, timedelta(seconds=10*60))?> <?end if?>
The timeout value in the put
method is optional. Without it the value will
be stored indefinitely.
Example
This example shows how to connect to an Oracle database and output the content
of a person
table into an XML file.
Suppose we have a database table that looks like this:
create table person ( id integer not null, firstname varchar2(200), lastname varchar2(200) );
Then we can use the following template to output the table into an XML file:
<?xml version='1.0' encoding='utf-8'?> <?code db = oracle.connect("user/pwd@database')?> <persons> <?for p in db.query("select id, firstname, lastname from person order by 2, 1")?> <person id="<?printx p.id?>"> <firstname><?printx p.firstname?></firstname> <lastname><?printx p.lastname?></lastname> </person> <?end for?> </persons>
If we put the template into the file person.ul4
we can call rul4
like
this:
rul4 person.ul4 >person.xml
We could also pass the connection to our database via the -D
option and
disallow the script to make any database connections itself or execute any
system commands:
rul4 person.ul4 -Ddb:oracle=user/pwd@database --oracle=0 --sqlite=0 --mysql=0 --redis=0 --system=0 >person.xml
Then the template could use the Oracle connection object db
directly.