Toolatra

Difference between version 9 and 10 - Previous - Next
[https://raw.githubusercontent.com/timkRoiverAMD/toolatra/master/logo.png]

**Toolatra**
'''Toolatra''' is a modern http://sinatrarb.com/%|%Sinatra%|%-like micro web framework for writing HTTP Tcl web applications.


***Features***
   * Sinatra-like DSL
   * does not depend on anything, except for [Tcllib] (though, Toolatra works only with Tcl 8.5 and newer)   * a built-in template engine and layout engine (preliminary Mustache templates support also available via ''ToolatraMustache'' module, which is mostly a convenient wrapper around http://github.com/ianka/mustache.tcl%|%@ianka's amazing mustache.tcl library%|%)
   * a built-in web server that easily integrates with Apache or nginx
   * a built-in module for handling and validating authorization tokens

***Installation***

****On macOS****

It is highly, '''highly''' recommended that you use [ActiveTcl] 8.6 or 8.5 and not the macOS' built-in Tcl 8.5. While Toolatra does work without any problems with macOS' own Tcl build, ActiveTcl is way more modern and comes bundled with some useful packages that can be used with Sinatra.

For macOS-only, there is a script called ''install-macos.tcl'' that installs Toolatra into ''$HOME/Library/Tcl/toolatra-master'' and does not require root privileges.

To install Toolatra, clone the repo and just run:

======
$ tclsh install-macos.tcl
======

That's it, you have Toolatra installed!


****On Linux****

On Linux, you'll have to install it system-wide. The path to the folder with Tcl packages highly depends on the distro.


   * If you use Ubuntu, Toolatra needs to be installed into ''/usr/share/tcltk/toolatra''
   * If you use Fedora or RedHat/CentOS, Toolatra needs to be installed into ''/usr/share/tcl8.6/toolatra''

For convenience, create a temporary variable ''TOOLATRA_HOME'' and set it to the correct installation path.

======
$ export TOOLATRA_HOME=/usr/share/tcltk/toolatra # Ubuntu users
$ export TOOLATRA_HOME=/usr/share/tcl8.6/toolatra # Fedora/RHEL users
======

Obviously, you need Tcl installed via your distro's package manager.

First, remove the installation prefix if it already exists:

======
$ test -d $TOOLATRA_HOME && sudo rm -rvf $TOOLATRA_HOME
======

Now create the installation prefix and copy all ''*.tcl'' files from the repo into the prefix:

======
$ sudo mkdir -pv $TOOLATRA_HOME
$ sudo cp -v *.tcl $TOOLATRA_HOME/
======

That's it!

***Templates and layouts***
Toolatra comes with an addon ''ToolatraTemplates'' that provides an easy-to-use template/layout system tightly integrated with the framework. The template markup is called ''ETcl'' (Embedded Tcl).

Templates can not only contain the markup for the page itself, but they also can contain inline Tcl code.

Here is an example (let's call it ''viewer.html''):

======
<html>
 <head><title>Some kind of blog or newspaper</title></head>
 <body>
   <center><h1>Some kind of blog or newspaper</h1></center>
   <center><i style="color: lightgrey;">
   @
      set toShow {}
      if {$auth} {  
           set toShow "You're signed in. Hey there, $name!"
      } else {
          set toShow "You're not signed in."
      }
   @
   </i></center>
   <div>
     @content@
   </div>
</body>
</html>
======

As you might've probably guessed, Tcl code and variables are wrapped around with ''@''s. To substitute a variable, you need to wrap around its name in ''@'' without any other symbols. To run Tcl code, you also wrap it with ''@''s.

To avoid repetitive static content in your templates, you can seperate into layouts. Layouts support all the same syntax as templates.

Here are two example layouts: ''head.html'' and ''foot.html''.

''head.html'':


======
<html>
 <head><title>Some kind of blog or newspaper</title></head>
 <body>
   <center><h1>Some kind of blog or newspaper</h1></center>
   <center><i style="color: lightgrey;">
   @
      set toShow {}
      if {$auth} {  
           set toShow "You're signed in. Hey there, $name!"
      } else {
          set toShow "You're not signed in."
      }
   @
   </i></center><div>
======

''foot.html'':

======
</div></body></html>
======

Then we can include our layouts into our template by wrapping around the basename of the layout in ''@'' and putting the exclamation mark right before the specified layout name. In our case, we can now include ''head.html'' and ''foot.html'' layouts from ''viewer.html'' template like this:

======
@!head.html@
@content@
@!foot.html@
======

Now, we have templates and layouts, but how can we render it?

Pretty simple - using the ''etcl'' command:


======
package require Toolatra
package require ToolatraTemplates

get / {
     etcl viewer.html [dict create content {<p>Welcome!</p>} auth 0]
}

run
======

As you can see, ''etcl'' command can accept either one or two arguments. These are:

   1. the basename of the template that we want to render
   2. ''(optional)'' the context dict that contains variable values that we will be accessing from the template

The latter is needed if the variables that you want to access are not global. If they are global, you might want to omit the context dict.


All layouts must be stored in the ''layouts'' folder, all the templates must be stored in the ''templates'' folder. 

***Some examples***

****Hello world****

''app.tcl'' code:
======
#!/usr/bin/env tclsh
package require Toolatra

get / {
     render {Hello world!}
}

get /+name {
     render "Hello, [dict get $params name]!"
}

post / {
     if {$rawData != {}} {
         render "Hello, $rawData (via POST request)!" 
     } else {
         render {Hello world (via POST request)!} 
     }
}

run
======

How to run:

======
$ tclsh8.5 app.tcl
======

The app will be running at ''http://localhost:5050''


   * If you go to ''http://localhost:5050'' via your web browser, you should see ''Hello world!''
   * If you go to ''http://localhost:5050/Tim'' via your web browser, you should see ''Hello, Tim!''
   * If you send an empty POST request to ''http://localhost:5050'', you should get ''Hello world (via POST request)!''
   * If you send a POST request with ''Jane'' sent as the data, you should get ''Hello, Jane (via POST request)!''

****Cat Language Translator****

Both the current and the previous version of '''Cat Language Translator''' are written 100% in Tcl and Toolatra. The source code of the first version can be found here: https://github.com/timkoi/catlanguage-web


***Serving Toolatra web apps with Apache (on Linux)***
First, specify the port where Toolatra's HTTP server shall be running. In the application, specify the port as the argument to the ''run'' command, like this:

======
run 5056
======

Replace ''5056'' with your preferred port number.

Now, create a user and a systemd service for the web app:

======
$ sudo useradd -M -N toolatrarunner
$ sudo chsh -s /sbin/nologin toolatrarunner
$ sudo mkdir -pv /srv/mytoolatraapp
$ mv -v * /srv/mytoolatraapp
$ sudo chown -v -R toolatrarunner:users /srv/mytoolatraapp
$ cat >> /etc/systemd/system/mytoolatraapp.service << EOF
[Unit]
Description=My Toolatra web app
After=httpd.service

[Service]
Type=simple
ExecStart=/bin/sh -c "cd /srv/mytoolatraapp && LC_ALL=C /usr/bin/env tclsh app.tcl"
User=toolatrarunner

[Install]
WantedBy=multi-user.target
EOF
$ sudo systemctl enable mytoolatraapp
$ sudo systemctl start mytoolatraapp
======

Obviously, replace ''mytoolatraapp'' with the short name of your Toolatra web app.

Now create a reverse proxy with Apache:

======
$ sudo sh
$ echo 'ProxyPreserveHost On' >> /etc/httpd/conf/httpd.conf
$ echo 'ProxyPass /mytoolatraapp/ http://localhost:5056/' >> /etc/httpd/conf/httpd.conf
$ echo 'ProxyPassReverse /mytoolatraapp/ http://localhost:5056/' >> /etc/httpd/conf/httpd.conf
$ systemctl restart httpd
$ exit
======

Obviously, replace ''5056'' with the port you've specified and ''mytoolatraapp'' with the name of your web app.

That's it!


***Links***
   * Toolatra git repo: https://github.com/timkRoiverAMD/toolatra
   * Bug tracker: https://github.com/timkRoiverAMD/toolatra/issues
   * Documentation: https://github.com/timkRoiverAMD/toolatra/blob/master/README.asciidoc#usage